R数据表:在子集设置方面表现异常糟糕



我觉得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]的第二次运行非常快,并且返回的数据表非常小,这使得第二次查询也很快。

最新更新