通过获取总和来聚合重复的行

时间:2014-04-06 11:19:04

标签: r data.table plyr

继续我的问题:
1. Identifying whether a set of variables uniquely identifies each row of the data or not;
2. Tagging all rows that are duplicates in terms of a given set of variables,
我现在想用一组给定的变量来汇总/合并所有重复的行,取其总和。

解决方案1:

关于如何执行此操作here有一些指导,但是当形成索引的变量级别很多时,推荐的ddply方法很慢,因为它是在我试图通过给定变量集标记所有重复项的情况下。

# Values of (f1, f2, f3, f4) uniquely identify observations
dfUnique = expand.grid(f1 = factor(1:16),
                       f2 = factor(1:41),
                       f3 = factor(1:2),
                       f4 = factor(1:104))

# sample some extra rows and rbind them
dfDup = rbind(dfUnique, dfUnique[sample(1:nrow(dfUnique), 100), ])

# dummy data 
dfDup$data = rnorm(nrow(dfDup))

# aggregate the duplicate rows by taking the sum
dfDupAgg = ddply(dfDup, .(f1, f2, f3, f4), summarise, data = sum(data))

解决方案2:

第二个解决方案是使用data.table,并遵循建议here,我可以做

# data.table solution
indexVars = paste0('f', 1:4, sep = '')
dtDup = data.table(dfDup, key = indexVars)
dtDupAgg = dtDup[, list(data = sum(data)), by = key(dtDup)]

我有几个问题:
1.有没有办法让ddply版本更快?
2. data.table是否正确?我想检查,因为我是data.table的新手。

1 个答案:

答案 0 :(得分:7)

关于data.table解决方案,您无需设置密钥进行聚合操作。你可以直接做:

indexVars = paste0('f', 1:4, sep = '')
dtDup <- as.data.table(dfDup) ## faster than data.table(.)
dtDupAgg = dtDup[, list(data = sum(data)), by = c(indexVars)]

data.table版本1.9.2+还实现了一个函数setDT,可以通过引用将data.frames转换为data.tables (这意味着,没有副本,因此在转换中几乎没有时间,尤其适用于大型data.frames)。

所以,而不是做:

dtDup <- as.data.table(dfDup)
dtDup[...]

你可以这样做:

## data.table v1.9.2+
setDT(dfDup) ## faster than as.data.table(.)
dfDup[...]   ## dfDup is now a data.table, converted by reference

关于你的第一个问题,plyr并不知道它的速度。检查Why is plyr so slow?(以及那里的许多信息性评论)以获取更多信息。

也许您可能对dplyr感兴趣,这比plyr快几个数量级,但仍然比data.table慢,恕我直言。这是等效的dplyr版本:

dfDup %.% group_by(f1, f2, f3, f4) %.% summarise(data = sum(data))

以下是数据data.tabledplyr之间的基准(所有时间最少连续三次):

## data.table v1.9.2+
system.time(ans1 <- dtDup[, list(data=sum(data)), by=c(indexVars)])
#  user  system elapsed 
# 0.049   0.009   0.057 

## dplyr (commit ~1360 from github)
system.time(ans2 <- dfDup %.% group_by(f1, f2, f3, f4) %.% summarise(data = sum(data)))
#  user  system elapsed 
# 0.374   0.013   0.389 

我真的没有耐心去运行plyr版本(首次运行93秒后停止)。正如您所看到的,dplyrplyr快得多,但比data.table慢〜7倍。


检查结果是否相等:

all.equal(as.data.frame(ans1[order(f1,f2,f3,f4)]), 
          as.data.frame(ans2))
# [1] TRUE

HTH