用向量中的项目替换NA

10

我想用类似的组的平均值替换数据中的一些缺失值。

我的数据长这样:

   X   Y
1  x   y
2  x   y
3  NA  y
4  x   y

我希望它看起来像这样:

  X   Y
1  x   y
2  x   y
3  y   y
4  x   y

我写了这个代码,它运行正常

for(i in 1:nrow(data.frame){
   if( is.na(data.frame$X[i]) == TRUE){
       data.frame$X[i] <- data.frame$Y[i]
   }
  }

但我的数据框有将近50万行,使用for/if语句运行速度很慢。我想要的是像下面这样的东西:

is.na(data.frame$X) <- data.frame$Y

但是这会导致一个不匹配的大小错误。似乎应该有一个命令可以做到这一点,但我在SO或R帮助列表中找不到它。有什么想法吗?


顺便提一下 - 在某些情况下,使用 data.frame 作为变量名可能不太好,因为它会掩盖 data.frame() 函数。 - Ken Williams
在什么情况下?这不是真正的问题。 - hadley
正如 @hadley 所说,这并不是真正的问题。我假设 Y 列并没有包含完全相同的值... 就像他所说,我们需要上下文。 - OTStats
4个回答

12
< p > ifelse 是你的好朋友。

使用 Dirk 的数据集

df <- within(df, X <- ifelse(is.na(X), Y, X))

你愿意比较一下你和Dirk的答案速度吗? - Roman Luštrik
我没有计时两种方法,但它们都会立即执行(不像原始代码需要几分钟才能执行)。我认为我更喜欢这种方法,因为它只使用了一行代码而不是两行。 - gregmacfarlane

9

只需向量化 -- 布尔索引测试是一个表达式,你也可以在赋值中使用它。

设置数据:

R> df <- data.frame(X=c("x", "x", NA, "x"), Y=rep("y",4), stringsAsFactors=FALSE)
R> df
     X Y
1    x y
2    x y
3 <NA> y
4    x y

然后,通过计算要替换的位置的索引,并进行替换:

R> ind <- which( is.na( df$X ) )
R> df[ind, "X"] <- df[ind, "Y"]

这将产生所需的结果:

R> df
  X Y
1 x y
2 x y
3 y y
4 x y
R> 

which的目的是什么?数字索引是否比逻辑更快/更少出错? - Joshua Ulrich
1
我更喜欢数字索引(比如单个的“3”),而不是长度为N的布尔值。 - Dirk Eddelbuettel
2
@Joshua:我发现,如果TRUE的数量相对于元素总数很小,那么数字索引确实比逻辑索引快得多。 - Hong Ooi
这里哪个是多余的,我猜这完全取决于你喜欢布尔代数还是集合论。 - hadley
越短越好,更容易检查中间结果。迫不及待地等待着我的whch2;-) - Dirk Eddelbuettel

1
如果您已经在使用dplyr或tidyverse,您可以使用coalesce函数来实现这一点。它与ifelse函数类似,但是更加简洁易读。请参考coalesce文档
> df <- data.frame(X=c("x", "x", NA, "x"), Y=rep("y",4), stringsAsFactors=FALSE)
> df %>% mutate(X = coalesce(X, Y))
  X Y
1 x y
2 x y
3 y y
4 x y```

0

很遗憾,我暂时无法评论。但当对一些涉及字符串(又称为字符)的代码进行向量化时,上面的代码似乎不起作用。原因在于this answer中有所解释。如果涉及字符,则stringsAsFactors=FALSE是不够的,因为R可能已经将字符转换为了因子。需要确保数据也再次成为一个字符向量,例如:data.frame(X=as.character(c("x", "x", NA, "x")), Y=as.character(rep("y",4)), stringsAsFactors=FALSE)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接