我有一个宽的data.table
(20米行),由一个人ID键入,但有很多列(~150)有很多空值。每列都是我希望为每个人结转的记录状态/属性。每个人可能有10到10,000个观察点,并且该集合中有大约500,000人。来自一个人的价值观不能流血#39;进入下面的人,所以我的解决方案必须适当地尊重人员ID栏和组。
出于演示目的 - 这里是一个非常小的样本输入:
DT = data.table(
id=c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3),
aa=c("A", NA, "B", "C", NA, NA, "D", "E", "F", NA, NA, NA),
bb=c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
cc=c(1, NA, NA, NA, NA, 4, NA, 5, 6, NA, 7, NA)
)
看起来像这样:
id aa bb cc
1: 1 A NA 1
2: 1 NA NA NA
3: 1 B NA NA
4: 1 C NA NA
5: 2 NA NA NA
6: 2 NA NA 4
7: 2 D NA NA
8: 2 E NA 5
9: 3 F NA 6
10: 3 NA NA NA
11: 3 NA NA 7
12: 3 NA NA NA
我的预期输出如下:
id aa bb cc
1: 1 A NA 1
2: 1 A NA 1
3: 1 B NA 1
4: 1 C NA 1
5: 2 NA NA NA
6: 2 NA NA 4
7: 2 D NA 4
8: 2 E NA 5
9: 3 F NA 6
10: 3 F NA 6
11: 3 F NA 7
12: 3 F NA 7
我找到了一个可行的data.table
解决方案,但它在我的大型数据集上速度非常慢:
DT[, na.locf(.SD, na.rm=FALSE), by=id]
我发现使用同样慢的dplyr的等效解决方案。
GRP = DT %>% group_by(id)
data.table(GRP %>% mutate_each(funs(blah=na.locf(., na.rm=FALSE))))
我很有希望能够想出一个滚动的“自我”'使用data.table
功能加入,但我似乎无法正确使用(我怀疑我需要使用.N
,但我还没想到它。)< / p>
此时我想我必须在Rcpp中写一些内容来有效地应用分组的locf。
我是R的新手,但我对C ++并不陌生 - 所以我有信心我能做到。我觉得应该有一种有效的方法来使用data.table
在R中执行此操作。
答案 0 :(得分:18)
可以通过转发(na.locf
)非cummax
索引(NA
)并相应地进行子集化来构建非常简单的(!is.na(x)) * seq_along(x)
:
x = c(1, NA, NA, 6, 4, 5, 4, NA, NA, 2)
x[cummax((!is.na(x)) * seq_along(x))]
# [1] 1 1 1 6 4 5 4 4 4 2
这会使用na.locf
参数复制na.rm = TRUE
,以获得na.rm = FALSE
行为,我们只需要确保cummax
中的第一个元素为TRUE
:
x = c(NA, NA, 1, NA, 2)
x[cummax(c(TRUE, tail((!is.na(x)) * seq_along(x), -1)))]
#[1] NA NA 1 1 2
在这种情况下,我们不仅需要考虑非NA
指数,还要考虑(订购或待订购)&#34; id&#34;列更改值:
id = c(10, 10, 11, 11, 11, 12, 12, 12, 13, 13)
c(TRUE, id[-1] != id[-length(id)])
# [1] TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE FALSE
结合以上内容:
id = c(10, 10, 11, 11, 11, 12, 12, 12, 13, 13)
x = c(1, NA, NA, 6, 4, 5, 4, NA, NA, 2)
x[cummax(((!is.na(x)) | c(TRUE, id[-1] != id[-length(id)])) * seq_along(x))]
# [1] 1 1 NA 6 4 5 4 4 NA 2
请注意,我们OR
第一个元素TRUE
,即使其等于TRUE
,从而获得na.rm = FALSE
行为。
对于这个例子:
id_change = DT[, c(TRUE, id[-1] != id[-.N])]
DT[, lapply(.SD, function(x) x[cummax(((!is.na(x)) | id_change) * .I)])]
# id aa bb cc
# 1: 1 A NA 1
# 2: 1 A NA 1
# 3: 1 B NA 1
# 4: 1 C NA 1
# 5: 2 NA NA NA
# 6: 2 NA NA 4
# 7: 2 D NA 4
# 8: 2 E NA 5
# 9: 3 F NA 6
#10: 3 F NA 6
#11: 3 F NA 7
#12: 3 F NA 7