根据条件语句(“ if”)替换数据框中的值


122

在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

我最初的尝试是使用forand if语句,如下所示:

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

但我相信你可以看到,这个替换所有的值junk$nmb。我知道为什么这样做了,但是我似乎无法用它代替那些原来值为的junk $ nm情况B

注意:我设法解决了问题,gsub但是为了学习RI,我仍然想知道如何使我的原始方法起作用(如果可能的话)


1
您可能需要将stringAsFactors = FALSE添加到原始data.frame结构中。
jimmyb 2011年

@jimmyb为什么?如果使用R的大多数建模代码进行建模,则因子是有用的,并且是必需的。处理此问题的正确方法是确认数据是一个因素。如果您不希望/不需要此转换,则可以按照您所说的做。如果您确实想要这个因素,那么@Kenny可以通过简单的方法进行操作。
加文·辛普森

1
因此,由于性能,因数曾经更受欢迎,但是,由于字符串是不可变的且经过散列处理,因数的值变得不那么明显了,因为大多数基本R功能只会直接转换它们(尽管带有警告)。我认为因素会导致在Peoples R代码中发现大量错误。
jimmyb 2011年

Answers:


217

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

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

编辑:如果确实需要维护nm作为因素,请在末尾添加:

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

4
as.character()使使用因子的工作变得更加轻松。+1
布兰登·贝特尔森

4
如果您有多列怎么办?
geodex


25

简短的答案是:

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

看一下R Introduction中的Index vectors(如果您还没有阅读的话)。


编辑。正如评论中所注意到的,此解决方案适用于字符向量,因此对您的数据无效。

对于因素,最好的方法是更改​​级别:

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

简短的补充:%in%的用法仅在右侧有设置时才有帮助(例如)c("B","C")。做junk$nm[junk$nm == "B"]是更好的方法。
Thilo

1
哦,另一个重要的补充:要做到这一点,首先需要将因子水平添加b到因子nm。如果您想使用角色而不是要素,那么diliop的版本实际上是更好的版本。(始终考虑变量首先具有的类型!)
Thilo

不适用于@Kenny创建的数据,因为数据是因素。您是否忘记了某个步骤,或者您具有全局设置以停止将字符转换为因数?
加文·辛普森

4
@Thilo一之间的重要区别%in%,并==正在NA处理:c(1,2,NA)==1给予TRUE, FALSE, NA,但c(1,2,NA) %in% 1给人TRUE, FALSE, FALSE。是的,我忘了检查这项工作是否:/
Marek

20

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

6
真好 我不知道的替换功能levels()。一支班轮junk <- within(junk, levels(nm)[levels(nm)=="B"] <- "b")怎么样?

但是你叫了两次:)
Marek

2
@Marek拍了一下头,只是表明一个人在就寝时间已经过去的时候不应该对SO的评论做出回应。让我们再试一次...
Gavin Simpson

@Seth确实-很好。不确定为什么我分开了步骤?也许是为了博览会……
Gavin Simpson

11

在一个命令中执行此操作的最简单方法是使用which命令,并且无需通过执行以下操作将因子更改为特征:

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

5

您已在中创建了一个因子变量,nm因此您需要避免这样做或在因子属性中添加一个附加级别。您还应该避免使用<-在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

@DWin感谢您对问题的投入以及对变量类型的考虑。我接受@diliop的回答,因为这是第一个可行的方法。我知道在<-vs =上有很多问题,但是(如果可以简单回答)为什么应该与=一起使用data.frame
DQdlM 2011年

您无需添加b为级别,只需将级别更改为B即可b
加文·辛普森

@KennyPeanuts:列名是一个问题,请看a <- data.frame(x<-1:10)。它的列名不是x一团糟x....1.10。最好使用data.frame(x = 1:10)。然后,您知道列名是什么。
IRTFM 2011年

@Gavin:添加起来比替换起来更容易,甚至不使其成为一个因素也更容易。
IRTFM 2011年

@Dwin更容易吗?我不同意-有关简单的内容,请参见我的答案。添加级别可以吸引您,例如在建模中,predict()如果新数据中的因子级别与用于拟合模型的因子级别不匹配,则会抱怨。从长远来看,与依靠快捷方式相比​​,可以更清洁地获取所需格式的数据。我同意,不让它成为一个因素可能会更容易,但是如果它已经是一个因素,或者对于某些建模练习来说需要成为一个因素……
Gavin Simpson

1

如果使用字符变量(请注意stringsAsFactors此处为假),则可以使用replace:

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
# ...

0
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")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.