使用列表作为分组列对数据表进行分组

7

我有一个非常大的问题,通过循环遍历数据表来实现我的目标速度太慢了,因此我正在尝试绕过循环。假设我有一个如下所示的数据表:

a <- data.table(i = c(1,2,3), j = c(2,2,6), k = list(c("a","b"),c("a","c"),c("b")))

> a
  i j   k
1: 1 2 a,b
2: 2 2 a,c
3: 3 6   b

我希望能够基于k中的值进行分组。就像这样:

a[, sum(j), by = k]

我现在遇到如下错误:

 Error in `[.data.table`(a, , sum(i), by = k) : 
 The items in the 'by' or 'keyby' list are length (2,2,1). Each must be same length as rows in x or number of rows returned by i (3).

我正在寻找的答案是首先将所有k列中有"a"的行分组,并计算j的总和,然后再将所有"k"列中有"b"的行分组,以此类推。因此期望的答案是:
k V1 
a 4
b 8
c 2

有什么有效的方法可以做到这一点吗?我不能通过重复行来融合列K,因为数据表的大小对我的情况来说太大了。


这个回答解决了你的问题吗?R data.table - group by column includes list。我认为这个问题是一个重复的问题,但它也提供了更好和更多的答案。 - andschar
3个回答

9
我认为这可能有效:
a[, .(k = unlist(k)), by=.(i,j)][,sum(j),by=k]

   k V1
1: a  4
2: b  8
3: c  2

5
如果我们使用tidyr,一种简洁的选项是
library(tidyr)
unnest(a, k)[, sum(j) ,k]
#   k V1
#1: a  4
#2: b  8
#3: c  2

或者使用 dplyr/tidyr 管道

unnest(a, k) %>%
       group_by(k) %>%
       summarise(V1 = sum(j))
#     k    V1
#   <chr> <dbl>
#1     a     4
#2     b     8
#3     c     2

2

由于按组操作可能会很慢,我建议考虑...

dat = a[rep(1:.N, lengths(k)), c(.SD, .(k = unlist(a$k))), .SDcols=setdiff(names(a), "k")]

   i j k
1: 1 2 a
2: 1 2 b
3: 2 2 a
4: 2 2 c
5: 3 6 b

我们正在重复行的cols i:j 来匹配未列出的k。数据应该保持这种格式,而不是使用列表列。从那里开始,就像@MikeyMike的答案一样,我们可以使用dat[, sum(j), by=k]
在data.table 1.9.7+中,我们也可以这样做。
dat = a[, c(.SD[rep(.I, lengths(k))], .(k = unlist(k))), .SDcols=i:j]

我单独回答这个问题,因为我不太乐观其他回答者会注意到评论并进行编辑。 - Frank
我不明白你在这里做什么,当我尝试运行时它会抛出一个错误,你知道为什么吗?lengths(k)中的错误:找不到对象'k'。 - newbie
@newbie 是的,我认为我之所以没有看到那个错误,只是因为我在包的开发版本上(在其中我们可以在j内部引用.SD之外的列)。我会编辑说明这种不兼容性并展示另一种方法。我在这里做的事情与akrun答案中unnest后看到的或MikeyMike答案中unlist后看到的相同,但可能更有效,因为按行操作(如Mike的答案)可能很慢。 - Frank

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