【发布时间】:2021-08-15 13:59:55
【问题描述】:
我有如下数据表:
library(data.table)
dat = data.table(j = c(3,8,9,11,10,28), gr = c(9,9,9,9,10,10))
> dat
j gr
1: 3 9
2: 8 9
3: 9 9
4: 11 9
5: 10 10
6: 28 10
有两个组(由“gr”指定)并且它们是有序的。现在我想要实现的是为每组的每一行创建一个累积的“j”值向量。结果应该是list 列,如下所示:
res_dat = data.table(j = c(3,8,9,11,10,28), gr = c(9,9,9,9,10,10),
res = list(3, c(3,8), c(3,8,9), c(3,8,9,11),
10, c(10, 28)))
> res_dat
j gr res
1: 3 9 3
2: 8 9 3,8
3: 9 9 3,8,9
4: 11 9 3, 8, 9,11
5: 10 10 10
6: 28 10 10,28
我尝试了以下方法:
首先,我创建了一个虚拟列,其中包含每个组的每行数。
dat[, tmp:= seq_len(.N), by = gr]
我的计划是使用该数字来对 j 向量进行子集化,但我没有做到。这些都不起作用:
dat[, res := list(j[1:tmp]), by = gr]
dat[, res := list(list(j[1:tmp])), by = gr] # based on https://stackoverflow.com/questions/22531477/using-lists-inside-data-table-columns
我收到以下错误:
Warning messages:
1: In 1:tmp : numerical expression has 4 elements: only the first used
2: In 1:tmp : numerical expression has 2 elements: only the first used
这确实有助于理解它是如何失败的,但我不知道如何让它成功。有什么想法吗?
【问题讨论】:
-
一种可能性:
dat[, res := .(sapply(seq_len(.N), function(x) j[seq_len(x)])), by = gr] -
虽然
Reduce(c, j, accumulate=TRUE)在控制台上工作,但它不能在dat环境中工作,令人沮丧。 @Henrik 的评论(我相信)是最简单的,尽管我建议使用lapply或sapply(., simplify=FALSE)来排除极端情况的差异。 -
@r2evans 把它包裹在
list:dat[, res2 := .(Reduce(c, j, accumulate=TRUE)), by = gr] -
该死,我以为我已经尝试过了。谢谢@Henrik ...不妨回答一下!它很优雅,
data-table-canonical。 (在我看来,它获取列表返回值并在赋值中丢弃了大部分,这对我来说似乎很奇怪。来自Reduce(..., accum=T)的返回值已经是list,不知道为什么这里严格需要双重列表。)
标签: r data.table