当您使用 data.tables 进行聚合操作(分组)时,尤其是对于大型数据集,您应该将分组依据的字段设置为 key(使用 setkeyv(DT, "your_key_field"), ETC...)。另外,我不能明确地谈论这个话题,但总的来说,我认为在 data.table 对象中使用本机 data.table:: 函数/操作会比使用其他包的函数(如 plyr::count)获得更好的性能例如。下面,我制作了一些 data.table 对象 - 第一个与您的示例相同;第二个添加一列Year(而不是在函数执行时计算format(Date,"%Y")),但将Date设置为key;第三个与第二个相同,只是它使用Year 作为key。我还制作了一些以不同方式进行分组的函数(为了方便进行基准测试)。
library(data.table)
library(plyr) # for 'count' function
library(microbenchmark)
##
dates <- seq.Date(
from=as.Date("2000-01-01"),
to=as.Date("2012-12-31"),
by="day")
##
set.seed(123)
sampleDate <- sample(
dates,
1e06,
replace=TRUE)
##
DT.dt <- data.table(
Date=sampleDate,
incident=1)
##
DT.dt2 <- copy(DT.dt)
DT.dt2[,Year:=format(Date,"%Y")]
setkeyv(DT.dt2,"Date")
##
DT.dt3 <- copy(DT.dt2)
setkeyv(DT.dt3,"Year")
##
> head(DT.dt,3)
Date incident
1: 2003-09-27 1
2: 2010-04-01 1
3: 2005-04-26 1
> head(DT.dt2,3)
Date incident Year
1: 2000-01-01 1 2000
2: 2000-01-01 1 2000
3: 2000-01-01 1 2000
> head(DT.dt3,3)
Date incident Year
1: 2000-01-01 1 2000
2: 2000-01-01 1 2000
3: 2000-01-01 1 2000
## your original method
f1 <- function(dt)
{
dt[,count(format(Date,"%Y"))]
}
## your method - using 'Year' column
f1.2 <- function(dt)
{
dt[,count(Year)]
}
## use 'Date' column; '.N' and
## 'by=' instead of 'count'
f2 <- function(dt)
{
dt[,.N,by=format(Date,"%Y")]
}
## use 'Year' and '.N','by='
f3 <- function(dt)
{
dt[,.N,by=Year]
}
##
Res <- microbenchmark(
f1(DT.dt),
f1.2(DT.dt2),
f1.2(DT.dt3),
f2(DT.dt2),
f3(DT.dt3))
##
> Res
Unit: milliseconds
expr min lq median uq max neval
f1(DT.dt) 478.941767 515.144253 557.428159 585.579862 706.8724 100
f1.2(DT.dt2) 98.722062 115.588034 126.332104 137.792116 223.4967 100
f1.2(DT.dt3) 97.475673 118.134788 125.836817 136.136156 238.2697 100
f2(DT.dt2) 352.767219 373.337958 387.759996 429.301164 542.1674 100
f3(DT.dt3) 7.912803 8.441159 8.736887 9.685267 76.9629 100
观察:
按预先计算的字段Year分组,而不是计算
format(Date,"%Y") 在执行时是一个明显的改进 -
对于count 和.N 方法。你可以看到这个
将f1() 和f2() 时间与f1.2() 时间进行比较。
count 方法似乎比 .N 和 'by=' 方法慢一些(f1() 与 f2() 相比。
- 迄今为止最好的方法是使用预先计算的字段
Year和本机data.table分组.N和by=; f3() 比其他四个时间快得多。
在 SO 上有一些非常有经验的 data.table 用户,肯定比我自己更多,所以可能有更快的方法来做到这一点。不过,抛开其他一切不谈,在data.table 上设置key 绝对是个好主意;而且看起来你预先计算像Year这样的字段比“即时”这样做要好得多;如果您不需要它,您可以随时使用 DT.dt[,Year:=NULL] 删除它。
此外,您说您正在尝试计算每年 incidents 的数量 - 由于您的示例数据的所有行都有 incident = 1,因此计数与求和相同。但假设你的真实数据有不同的incident 值,你可以这样:
> DT.dt3[,list(Incidents=sum(incident)),by=Year]
Year Incidents
1: 2000 77214
2: 2001 77385
3: 2002 77080
4: 2003 76609
5: 2004 77197
6: 2005 76994
7: 2006 76560
8: 2007 76904
9: 2008 76786
10: 2009 76765
11: 2010 76675
12: 2011 76868
13: 2012 76963
(我在上面称为setkeyv(DT.dt3,cols="Year"))。