介绍
我试图找到一种最佳方法,如何找到给定列中最后一个非零值的行,并在该行上返回不同列的值。我想在R data.table中做到这一点,我正在寻找该操作的最大效率。
例
让我们有一个像这样的数据表:
set.seed(123)
DT = data.table(x=rep(c("b","a","c"),each=6),
y=rep(1:6, 3),
z = rbinom(18, 1, 0.3))
Run Code Online (Sandbox Code Playgroud)
这提供给我们以下数据表:
x y z
1: b 1 0
2: b 2 1
3: b 3 0
4: b 4 1
5: b 5 1
6: b 6 0
7: a 1 0
8: a 2 1
9: a 3 0
10: a 4 0
11: a 5 1
12: a 6 0
13: c 1 0
14: c 2 0
15: c 3 0
16: c 4 1
17: c 5 0
18: c 6 0
Run Code Online (Sandbox Code Playgroud)
现在,该表适用于x列中按y列排序的每个值。对于列中的值给出的每个组x,我想创建一个列,该列为每y行提供最后一个非零值为的行中的值z。
现在,我对每个y使用lapply并按x分组,这给出了所需的结果:
DT[, list(y,
z,
output = lapply(y, function(x) max(y[z != 0 & y <= x]))
),
by = 'x']
Run Code Online (Sandbox Code Playgroud)
问题
我可以使示例中的代码更有效吗?
您可以尝试使用nafill:
# create a dummy column that is only populated for nonzero z (and hence NA elsewhere)
DT[z != 0, y_copy := y]
# nafill on this column using LOCF strategy by group:
DT[ , ans := nafill(y_copy, type = 'locf'), by = x][]
# x y z y_copy ans
# 1: b 1 0 NA NA
# 2: b 2 1 2 2
# 3: b 3 0 NA 2
# 4: b 4 1 4 4
# 5: b 5 1 5 5
# 6: b 6 0 NA 5
# 7: a 1 0 NA NA
# 8: a 2 1 2 2
# 9: a 3 0 NA 2
# 10: a 4 0 NA 2
# 11: a 5 1 5 5
# 12: a 6 0 NA 5
# 13: c 1 0 NA NA
# 14: c 2 0 NA NA
# 15: c 3 0 NA NA
# 16: c 4 1 4 4
# 17: c 5 0 NA 4
# 18: c 6 0 NA 4
Run Code Online (Sandbox Code Playgroud)
目前,这nafill是仅开发功能(data.table1.12.3+),但下一个或两周内应在CRAN上使用1.12.4。目前,您可以使用install.packages('data.table', type = 'source', repos = 'http://Rdatatable.github.io/data.table')
如果您不想创建y_copy,则可以通过以下方式内联is.na<-:
DT[ , ans := nafill(`is.na<-`(y, z == 0), type = 'locf'), by = x]
Run Code Online (Sandbox Code Playgroud)
这将是低效率的,因为它z==0是按组重复计算的(而不是作为单个向量);您可以在第一步中执行以下操作:
DT[ , z_zero := z == 0]
Run Code Online (Sandbox Code Playgroud)
但这种装置的另一个伪柱(用更少的存储比y_copy如果y是numeric,character,或complex)
使用滚动连接的另一个选项:
DT[, output:= DT[z==1][.SD, on=.(x, y), roll=Inf, x.y]]
Run Code Online (Sandbox Code Playgroud)
输出:
x y z output
1: b 1 0 NA
2: b 2 1 2
3: b 3 0 2
4: b 4 1 4
5: b 5 1 5
6: b 6 0 5
7: a 1 0 NA
8: a 2 1 2
9: a 3 0 2
10: a 4 0 2
11: a 5 1 5
12: a 6 0 5
13: c 1 0 NA
14: c 2 0 NA
15: c 3 0 NA
16: c 4 1 4
17: c 5 0 4
18: c 6 0 4
Run Code Online (Sandbox Code Playgroud)