如果想根据组内的前/后非NA观察值填写变量的缺失值,则data.table命令为
setkey(DT,id,date)
DT[, value_filled_in := DT[!is.na(value), list(id, date, value)][DT[, list(id, date)], value, roll = TRUE]]
这很复杂。遗憾的是roll
是一个非常快速和强大的选项(特别是与在每个组中应用zoo::na.locf
等功能相比)
我可以写一个便利函数来填补缺失的值
fill_na <- function(x , by = NULL, roll =TRUE , rollends= if (roll=="nearest") c(TRUE,TRUE)
else if (roll>=0) c(FALSE,TRUE)
else c(TRUE,FALSE)){
id <- seq_along(x)
if (is.null(by)){
DT <- data.table("x" = x, "id" = id, key = "id")
return(DT[!is.na(x)][DT[, list(id)], x, roll = roll, rollends = rollends, allow.cartesian = TRUE])
} else{
DT <- data.table("x" = x, "by" = by, "id" = id, key = c("by", "id"))
return(DT[!is.na(x)][DT[, list(by, id)], x, roll = roll, rollends = rollends, allow.cartesian = TRUE])
}
}
然后写
setkey(DT,id, date)
DT[, value_filled_in := fill_na(value, by = id)]
由于有人想写
,这并不令人满意setkey(DT,id, date)
DT[, value_filled_in := fill_na(value), by = id]
然而,这需要花费大量时间来运行。而且,对于最终用户来说,了解应使用fill_na
选项调用by
并且不应与data.table
by
一起使用,这很麻烦。这周围有一个优雅的解决方案吗?
一些速度测试
N <- 2e6
set.seed(1)
DT <- data.table(
date = sample(10, N, TRUE),
id = sample(1e5, N, TRUE),
value = sample(c(NA,1:5), N, TRUE),
value2 = sample(c(NA,1:5), N, TRUE)
)
setkey(DT,id,date)
DT<- unique(DT)
system.time(DT[, filled0 := DT[!is.na(value), list(id, date, value)][DT[, list(id, date)], value, roll = TRUE]])
#> user system elapsed
#> 0.086 0.006 0.105
system.time(DT[, filled1 := zoo::na.locf.default(value, na.rm = FALSE), by = id])
#> user system elapsed
#> 5.235 0.016 5.274
# (lower speed and no built in option like roll=integer or roll=nearest, rollend, etc)
system.time(DT[, filled2 := fill_na(value, by = id)])
#> user system elapsed
#> 0.194 0.019 0.221
system.time(DT[, filled3 := fill_na(value), by = id])
#> user system elapsed
#> 237.256 0.913 238.405
为什么我不使用na.locf.default
?即使速度差异并不重要,但同样的问题也出现在其他类型的data.table命令中(那些依赖于变量在“by”中合并的命令) - 为了得到一个系统地忽略它们是一种耻辱。语法更简单。我也非常喜欢所有的滚动选项。
答案 0 :(得分:11)
这是一种更快,更紧凑的方式(版本1.9.3 +):
DT[, filled4 := DT[!is.na(value)][DT, value, roll = T]]
答案 1 :(得分:3)
现在有一种原生的data.table
方式来填充缺失值(自1.12.4
起)。
这个问题催生了一个github issue,它最近因创建函数nafill
和setnafill
而关闭。您现在可以使用
DT[, value_filled_in := nafill(value, type = "locf")]
也可以用恒定值填充NA
或带回的下一个观测值。
该问题与方法的不同之处在于,这些功能当前仅适用于NA
而不适用于NaN
,而is.na
是TRUE
的{{1}}-这是planned,将在下一发行版中通过一个额外的参数进行修正。
我没有参与该项目,但我看到尽管github问题链接在这里,但没有其他链接,所以我代表未来的访问者进行回答。