【问题标题】:Replace NAs with mean of the same column of a data.table将 NA 替换为 data.table 同一列的平均值
【发布时间】:2015-12-22 22:58:10
【问题描述】:

我想用同一列的平均值替换 DATA TABLE 列中存在的 NA。我正在做以下事情。但它不起作用。

ww <- data.table(iris)

ww <- ww[1:5 , ]

ww[1,1] <- NA

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1:           NA         3.5          1.4         0.2  setosa
2:          4.9         3.0          1.4         0.2  setosa
3:          4.7         3.2          1.3         0.2  setosa
4:          4.6         3.1          1.5         0.2  setosa
5:          5.0         3.6          1.4         0.2  setosa


ww[is.na(Sepal.Length) , Sepal.Length:= mean(Sepal.Length, na.rm = T)]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1:          NaN         3.5          1.4         0.2  setosa
2:          4.9         3.0          1.4         0.2  setosa
3:          4.7         3.2          1.3         0.2  setosa
4:          4.6         3.1          1.5         0.2  setosa
5:          5.0         3.6          1.4         0.2  setosa

为什么我用 NaN 代替 NA 而它应该是其余值(4.9、4.7、4.6、5.0)的平均值?

如果这种语法有问题,有什么替代方法可以实现?

我想要数据表的语法。

【问题讨论】:

  • 问题是您首先要对数据集进行子集化,然后将操作应用于 Sepal.Length 列,此时该列仅包含一个 NA
  • @AkhilNair 没有找到你。可以举个例子吗?
  • @RHertel 您的解决方案正在替换整个列,而不仅仅是 NA。
  • 为什么要用平均值替换缺失值?对于您要解决的问题,可能有更好的解决方案。

标签: r data.table


【解决方案1】:

zoo 包中的na.aggregate 将 NA 替换为同一列中非 NA 的平均值:

library(zoo)

ww[, Sepal.Length := na.aggregate(Sepal.Length)]

【讨论】:

  • na.aggregate 是动物园中的一个函数。注意library 语句。
  • 非常感谢。在我发表新文章之前,有没有办法为解决方案编制索引,以便通过其他分组(例如物种)获取非 NA 列的平均值?
  • ww[ , ..., by = Species]
【解决方案2】:

虽然zoo 的答案非常好,但它需要新的依赖项。
仅使用 data.table 您可以执行以下操作。

library(data.table)

# prepare data
ww = data.table(iris[1:5,])
ww[1, Sepal.Length := NA]

# solution
ww[, Sepal.Length.mean := mean(Sepal.Length, na.rm = TRUE) # calculate mean
   ][is.na(Sepal.Length), Sepal.Length := Sepal.Length.mean # replace NA with mean
     ][, Sepal.Length.mean := NULL # remove mean col
       ][] # just prints

虽然它与动物园相比可能看起来很大,但它的性能效率很高,因为所有步骤都是使用 通过引用更新 := 进行的。 它也可以很容易地调整为按组用平均值替换 NA,只需在 data.table 中使用 by 参数。

【讨论】:

    【解决方案3】:

    您的尝试首先对表格进行子集化,选择

    > ww[is.na(Sepal.Length)]
       Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    1:   
    
        NA         3.5          1.4         0.2  setosa
    

    所以任何进一步的操作只能“看到”这些行 - 即 Sepal.Length 只能看到那一个 NA

    您想要的 data.table 解决方案如下 - 它查看整个表格并用使用 ifelse 的方法替换 NAs。

    ww[, Sepal.Length := ifelse(is.na(Sepal.Length), mean(Sepal.Length, na.rm = TRUE), Sepal.Length)]
    

    【讨论】:

    • ww[, Sepal.Length := replace(Sepal.Length, is.na(Sepal.Length), mean(Sepal.Length, na.rm=TRUE))] 因为ifelse 通常很慢。烦人的是Sepal.Length 需要在这里输入四次。
    【解决方案4】:

    在基础 R 中:

    ww$Sepal.Length[is.na(ww$Sepal.Length)] <- mean(ww$Sepal.Length, na.rm = T)
    

    【讨论】:

    • 你能把这个语法转换成data.table的吗?
    【解决方案5】:

    它没有取整个 Sepal.Length 列的平均值;只有您选择的 1 列。

    相当使用:

    ww[is.na(Sepal.Length) , Sepal.Length:= mean(ww$Sepal.Length, na.rm=TRUE)]
    

    【讨论】:

    • 这个语法对data.table有效吗?
    • @user3664020 现在是。
    • 在全局范围内的ww 范围内调用Sepal.Length 可能是不好的做法。再举一个例子,如果你全局调用ww,你可能已经对列进行了重新排序,这会搞砸后续的事情。
    • @AkhilNair,不明白为什么重新排序的列会搞砸获取平均值。你有一个可以分享的例子吗?
    • 我并不是说它会与平均值出错 - 只是这是一个坏习惯,即如果我要使用全局范围复制列,它会除非我在同一行重新排列表格,否则没问题。
    【解决方案6】:

    tidyr 有一个内置函数,replace_na 你可以使用它:

    library(tidyr)
    ww %>% replace_na(list(Sepal.Length = mean(.$Sepal.Length, na.rm = TRUE)))
    

    【讨论】:

      猜你喜欢
      • 2016-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 2016-10-03
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      相关资源
      最近更新 更多