2012-08-02 102 views
8

我在R中有一个非常大的数据框,并且想要为其他列中每个不同值的两列进行求和,例如我们有一天中各个商店中的交易数据帧的数据如下R中不同列值的总和

shop <- data.frame('shop_id' = c(1, 1, 1, 2, 3, 3), 
    'shop_name' = c('Shop A', 'Shop A', 'Shop A', 'Shop B', 'Shop C', 'Shop C'), 
    'city' = c('London', 'London', 'London', 'Cardiff', 'Dublin', 'Dublin'), 
    'sale' = c(12, 5, 9, 15, 10, 18), 
    'profit' = c(3, 1, 3, 6, 5, 9)) 

是:

shop_id shop_name city  sale profit 
    1  Shop A  London 12 3 
    1  Shop A  London 5 1 
    1  Shop A  London 9 3 
    2  Shop B  Cardiff 15 6 
    3  Shop C  Dublin 10 5 
    3  Shop C  Dublin 18 9 

而且我要总结每个店铺的销售和利润给:

shop_id shop_name city  sale profit 
    1  Shop A  London 26 7 
    2  Shop B  Cardiff 15 6 
    3  Shop C  Dublin 28 14 

我目前使用下面的代码来做到这一点:

shop_day <-ddply(shop, "shop_id", transform, sale=sum(sale), profit=sum(profit)) 
shop_day <- subset(shop_day, !duplicated(shop_id)) 

这工作绝对没问题,但我说我的数据框大(140,000行,37列和近10万的唯一行,我想总结)而且我的代码需要很长时间才能运行,然后最终表明它的内存不足。

有谁知道最有效的方法来做到这一点。

在此先感谢!

+2

......我觉得'data.table'的答案来了...... – 2012-08-02 16:42:40

回答

13

**强制性数据表的答案**

> library(data.table) 
data.table 1.8.0 For help type: help("data.table") 
> shop.dt <- data.table(shop) 
> shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id'] 
    shop_id sale profit 
[1,]  1 26  7 
[2,]  2 15  6 
[3,]  3 28  14 
> 

直到事情得到更大这听起来很好,很好......

shop <- data.frame(shop_id = letters[1:10], profit=rnorm(1e7), sale=rnorm(1e7)) 
shop.dt <- data.table(shop) 

> system.time(ddply(shop, .(shop_id), summarise, sale=sum(sale), profit=sum(profit))) 
    user system elapsed 
    4.156 1.324 5.514 
> system.time(shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id']) 
    user system elapsed 
    0.728 0.108 0.840 
> 

如果创建data.table你获得额外的速度增加用钥匙:

shop.dt <- data.table(shop, key='shop_id') 

> system.time(shop.dt[,list(sale=sum(sale), profit=sum(profit)), by='shop_id']) 
    user system elapsed 
    0.252 0.084 0.336 
> 
+0

请注意,Justin在他的'ddply'调用中使用'summarise'而不是'transform';这种改变可能足以让你的代码在没有内存错误的情况下工作,尽管其他解决方案肯定更快。 – Aaron 2012-08-02 17:52:39

+0

@Aaron谢谢!因为有一个较早的答案解释了它,所以我留下了这个解释。不过那是自从删除! – Justin 2012-08-02 17:56:10

+0

谢谢贾斯汀,快得多。另一个快速问题是,有没有办法将其他列(例如shop_name,city)保留在最终的数据表中?我可以重新加入初始数据框来获取这个数据,但如果在初始查询中有一种方法可以做到这一点,那么它会更加整洁。 – user1165199 2012-08-02 17:56:24

3

下面是如何使用基础R加快操作是这样的:

idx <- split(1:nrow(shop), shop$shop_id) 
a2 <- data.frame(shop_id=sapply(idx, function(i) shop$shop_id[i[1]]), 
       sale=sapply(idx, function(i) sum(shop$sale[i])), 
       profit=sapply(idx, function(i) sum(shop$profit[i]))) 

对于我的系统上的ddply汇总版本,时间缩短为0.75秒,而5.70秒。

+0

如果我在上面的例子中有很多列,比如销售额和利润,我想总结一下,是否可以调用一个函数来将上面的代码中的第三行和第四行组合成一行。 – discipulus 2015-05-25 12:39:16

+1

不是真的使用这种确切的方法,但有办法做到这一点。用一个最小可重现的例子开始一个新的问题,你会得到很多建议。 – Aaron 2015-05-25 23:27:54