根据条件(‘ if’)语句替换数据帧中的值

在 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。我可以明白为什么这样做,但我似乎不能让它取代只有垃圾 $nm 的情况下,其原始值是 B

注意: 我设法用 gsub解决了这个问题,但是为了学习 R,我仍然想知道如何得到我原来的工作方法(如果可能的话)

750818 次浏览

简短的回答是:

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

看看 引言中的索引向量(如果你还没有读过的话)。


正如注释中所注意到的,这个解决方案适用于字符向量,因此数据失败。

因素最好的办法是改变水平:

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

更容易将 nm 转换为字符,然后进行更改:

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

编辑: 如果你确实需要维护 nm 作为因素,最后补充一点:

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

您已经在 nm中创建了一个 factor 变量,因此您要么需要避免这样做,要么需要向 factor 属性添加额外的级别。您还应该避免在 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

由于您显示的数据是因素,因此事情有点复杂。@ 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

这非常简单,我经常忘记 levels()有一个替换函数。

编辑: 正如@Seth 在评论中提到的,这可以在一行程序中完成,而不会丢失清晰度:

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

在一个命令中做到这一点的最简单的方法是使用 which命令,而且也不需要通过这样做将因子改变为字符:

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

另一种替换值的有用方法

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

如果使用的是字符变量(请注意这里的 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)])
}

使用以下代码行调用此函数。

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