快速融化的data.table操作

时间:2012-12-20 09:08:25

标签: r dataframe data.table aggregation reshape2

我正在寻找操纵data.table对象的模式,这些对象的结构类似于melt包中使用reshape2创建的数据帧的结构。我正在处理数百万行的数据表。绩效至关重要。

问题的一般形式是,是否有一种方法可以根据列中值的子集执行分组,并使分组操作的结果创建一个或多个新列。

问题的一个特定形式可能是如何使用data.table来完成以下内容dcast的等效内容:

input <- data.table(
  id=c(1, 1, 1, 2, 2, 2, 3, 3, 3, 3), 
  variable=c('x', 'y', 'y', 'x', 'y', 'y', 'x', 'x', 'y', 'other'),
  value=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
dcast(input, 
  id ~ variable, sum, 
  subset=.(variable %in% c('x', 'y')))

其输出为

  id  x  y
1  1  1  5
2  2  4 11
3  3 15  9

3 个答案:

答案 0 :(得分:9)

快速未经测试的答案:似乎您正在寻找 by-without-by ,a.k.a。 grouping-by-i

setkey(input,variable)
input[c("x","y"),sum(value)]

这就像SQL中的快速HAVING。对j的每一行评估i。换句话说,上述结果相同,但速度要快得多:

input[,sum(value),keyby=variable][c("x","y")]

在选择感兴趣的组之前,所有组(浪费)的后者子集和证据。前者( by-without-by )直接进入组的子集。

小组结果将一如既往地以长格式返回。但是,在(相对较小的)聚合数据之后重新变宽,应该是相对即时的。无论如何,这就是想法。

如果setkey(input,variable)有很多不感兴趣的列,则第一个input可能会咬人。如果是这样,可能需要对所需列进行分组:

DT = setkey(input[,c("variable","value"),with=FALSE], variable)
DT[c("x","y"),sum(value)]

将来实施二级密钥会更容易:

set2key(input,variable)              # add a secondary key 
input[c("x","y"),sum(value),key=2]   # syntax speculative

id进行分组:

setkey(input,variable)
input[c("x","y"),sum(value),by='variable,id']
根据您的数据,

并在密钥中包含id可能会花费setkey的费用:

setkey(input,variable,id)
input[c("x","y"),sum(value),by='variable,id']

如果将by-by-by与by组合,如上所述,则by-without-by然后就像子集一样运行;即,j仅在缺少by时i的每一行运行(因此名称​​ by-without-by )。因此,您需要再次在variable中添加by,如上所示。

或者,以下内容应由id分组而不是“x”和“y”的并集(但上面是您在问题中要求的内容,iiuc):

input[c("x","y"),sum(value),by=id]

答案 1 :(得分:3)

> setkey(input, "id")
> input[ , list(sum(value)), by=id]
   id V1
1:  1  6
2:  2 15
3:  3 34

> input[ variable %in% c("x", "y"), list(sum(value)), by=id]
   id V1
1:  1  6
2:  2 15
3:  3 24

最后一个:

> input[ variable %in% c("x", "y"), list(sum(value)), by=list(id, variable)]
   id variable V1
1:  1        x  1
2:  1        y  5
3:  2        x  4
4:  2        y 11
5:  3        x 15
6:  3        y  9

答案 2 :(得分:2)

我不确定这是不是最好的方法,但你可以尝试:

input[, list(x = sum(value[variable == "x"]), 
             y = sum(value[variable == "y"])), by = "id"]
#    id  x  y
# 1:  1  1  5
# 2:  2  4 11
# 3:  3 15  9