簡體   English   中英

根據條件 (`if`) 語句替換數據框中的值

[英]Replace a value in a data frame based on a conditional (`if`) statement

在下面編碼的 R 數據幀中,我想用b替換B出現的所有時間。

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12])
colnames(junk) <- c("nm", "val")

這提供了:

   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   f
7   C   g
8   D   h
9   A   i
10  B   j
11  C   k
12  D   l

我最初的嘗試是使用這樣的forif語句:

for(i in junk$nm) if(i %in% "B") junk$nm <- "b"

但我相信你可以看到,這將junk$nm的所有值替換為b 我可以明白為什么會這樣做,但我似乎無法讓它僅替換原始值為B的那些 junk$nm 情況。

注意:我設法用gsub解決了這個問題,但為了學習 R 我仍然想知道如何讓我原來的方法工作(如果可能的話)

更容易將 nm 轉換為字符,然后進行更改:

junk$nm <- as.character(junk$nm)
junk$nm[junk$nm == "B"] <- "b"

編輯:如果您確實需要將 nm 作為因素進行維護,請在最后添加:

junk$nm <- as.factor(junk$nm)

另一種替換值的有用方法

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))

簡短的回答是:

junk$nm[junk$nm %in% "B"] <- "b"

查看R 簡介中的索引向量(如果您還沒有閱讀)。


編輯。 正如評論中所注意到的,此解決方案適用於字符向量,因此您的數據失敗。

對於因素,最好的方法是改變水平:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"

由於您顯示的數據是因素,因此它使事情變得有些復雜。 @diliop 的答案通過將nm轉換為字符變量來解決問題。 要回到原始因素,還需要進一步的步驟。

另一種方法是操縱現有因素的水平。

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   nm val
1   A   a
2   b   b
3   C   c
4   D   d
5   A   e
6   b   f
7   C   g
8   D   h
9   A   i
10  b   j
11  C   k
12  D   l

這很簡單,我經常忘記有一個替代 function 的levels()

編輯:正如@Seth 在評論中指出的那樣,這可以在單行中完成,而不會失去清晰度:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")

在一個命令中執行此操作的最簡單方法是使用which命令,並且不需要通過執行以下操作將因子更改為字符:

junk$nm[which(junk$nm=="B")]<-"b"

您已經在nm中創建了一個因子變量,因此您要么需要避免這樣做,要么為因子屬性添加一個額外的級別。 您還應該避免在 arguments 中使用<-到 data.frame()

選項1:

junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE)
junk$nm[junk$nm == "B"] <- "b"

選項 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk

如果您正在使用字符變量(請注意這里的stringsAsFactors為 false),您可以使用替換:

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE)
colnames(junk) <- c("nm", "val")

junk$nm <- replace(junk$nm, junk$nm == "B", "b")
junk
#    nm val
# 1   A   a
# 2   b   b
# 3   C   c
# 4   D   d
# ...
stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

使用下面的行調用這個 function。

d=stata.replace(d,"under20",1,"age<20")

也可以使用ifelse ,很簡單易懂

junk$val <- ifelse(junk$nm == "B", "b", junk$val)

如果您仍想通過for loop執行此操作,請使用正確的方法

for(i in 1:nrow(junk)){
  if(junk[i, "nm"] == "B"){
    junk[i, "val"] <- "b"
  }
}

junk
> junk
   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   b
7   C   g
8   D   h
9   A   i
10  B   b
11  C   k
12  D   l

我遇到了同樣的問題,你也可以對每一列做同樣的事情,

 fix_junk <- function(x){
      #x <- as.character(x)
      x[x == "B"] <- "b"
      x
    }
    junk[] <- lapply(junk, fix_junk); junk # junk[] to get a data frame rather than a list
    junk[1:3] <- lapply(junk[1:3], fix_junk); junk

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM