我觉得data.table
优化得非常好,所以我很惊讶地看到:
library(data.table)
SimData <- data.table(ID = sample(1:4e5, 4e6, replace = TRUE),
DATE = sample(seq(as.Date("2000-01-01"), as.Date("2019-12-31"), by = "day"),
4e6, replace = TRUE))
microbenchmark::microbenchmark(SimData[ID==1&DATE>="2005-01-01"])
microbenchmark::microbenchmark(SimData[ID==1][DATE>="2005-01-01"])
这两种解决方案显然是相同的,但在运行时存在一个数量级以上的差异。data.table
可能在第一种形式下表现如此糟糕吗?(也就是说,它不能自动优化这个调用。(或者我忽略了这里的一些东西。。。?
长操作是SimData[DATE>="2005-01-01"]
,因为它返回数百万行。
microbenchmark::microbenchmark(SimData[DATE>="2005-01-01"],SimData[ID==1])
Unit: microseconds
expr min lq mean median uq max neval
SimData[DATE >= "2005-01-01"] 32542.8 44549.55 51323.53 47529.75 50258.10 117396.3 100
SimData[ID == 1] 820.0 1043.55 1397.79 1435.15 1688.25 2302.5 100
SimData[ID == 1]
要短得多,因为它只返回几行,
执行SimData[ID==1&DATE>="2005-01-01"]
时,将强制对所有行执行两个求值。
对于SimData[ID==1][DATE>="2005-01-01"]
,快速操作首先完成,随后的过滤器也很快,因为只应用于少数行。
正如@jangorecki所提到的,在这方面还有改进的空间。
data.table
优化了类似X==x
的查询,而ID==1
是这种形式的,因此第一次运行此查询需要一段时间,但之后调用同一查询的速度非常快。在您的情况下,查询SimData[ID==1]
的第二次运行非常快,并且返回的数据表非常小,这使得第二次查询也很快。