如何按组在data.table中填充值?

8

请看下面的数据表:

# IMPUTING VALUES
library(data.table)
set.seed(1337)
mydt <- data.table(Year = rep(2000:2005, each = 10),
             Type = c("A","B"),
             Value = 30 + rnorm(60)
             )
naRows <- sample(nrow(mydt),15)
mydt[ naRows, Value := NA]
setkey(mydt,Year,Type)

我该如何按年份和类型用中位数填充缺失值?我尝试了以下方法:

# computed medians
computedMedians <- mydt[, .(Median = median(Value, na.rm = TRUE)), keyby = .(Year,Type)]
# dataset of just NA rows
dtNAs <- mydt[ is.na(Value), .SD, by = .(Year,Type)]


mydt[ is.na(Value),
      Imputations := dtNAs[computedMedians, nomatch = 0][, Median], 
      by = .(Year,Type)]
mydt

但是当你运行这段代码时,你会发现它的工作原理只要有数据缺失就会出现问题,并且计算出来的中位数会被循环使用。有没有更简单的方法?或者你如何解决这个错误呢?


2
mydt[ , Value := replace(Value, is.na(Value), median(Value, na.rm=TRUE)) , by=.(Year,Type)] 注意,对于没有非缺失值的年份-类型组合(例如2005-B),您仍然有缺失值。 - Frank
有很多方法可以填补缺失数据(EM、kNN、平均值等),你选择了中位数。NA的中位数是NA。除非你指定备用方法,否则这里没有适当的答案。一种可能性是将整个数据集的中位数作为缺失中位数。是否适用取决于您对数据的假设以及是否存在这样的层次结构。 - alexwhitworth
1
这样的答案让我既高兴又难过。高兴是因为您的解决方案既优雅又全面。但难过的是,我花费的时间比您的答案出现的59秒要多得多。谢谢Frank。非常感谢。 - jks612
关于缺失值,我将使用另一种方法进行第二次处理。我的实际数据集具有指定更细粒度和细分数据子集的限定符,因此第二次处理将针对比第一次处理更大的子集进行。 - jks612
2
嘿,写问题的时间花得很值得。只有因为问题清晰明了,才能快速回答。 :) - Frank
2个回答

10

如果您希望更新行而无需复制整个列,则:

require(data.table) # v1.9.6+
cols = c("Year", "Type")
dt[is.na(Value), Value := dt[.BY, median(Value, na.rm=TRUE), on=cols], by=c(cols)]

.BY 是一个特殊符号,它是一个包含分组信息的命名列表。尽管每次需要与整个data.table进行连接,但由于仅搜索一个组,因此速度应该相当快。


1
dt[.BY, median(Value, na.rm=TRUE), on=cols] 用于创建空数据表吗?我只是想分析一下这个代码。我运行它发现结果为空。 - Rich Scriven
1
不确定您的意思。请先执行 dt[is.na(Value), print(.BY), by=c(cols)],然后在原始的 dt 上执行 dt[is.na(Value), print(dt[.BY, Value, on=cols]), by=c(cols)]。这应该有助于澄清问题。 - Arun

4

不需要创建第二个表格,可以在单个的按组调用中完成:

mydt[, 
  Value := replace(Value, is.na(Value), median(Value, na.rm=TRUE))
, by=.(Year,Type)]

这种填充方法不能保证所有的缺失值都能被填充(例如,2005-B仍然是NA)。


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