match.fun比R中的实际函数慢

时间:2017-01-12 16:57:37

标签: r data.table

我有大型数据集,其中的行测量相同的东西(基本上是带有一些噪音的重复)。作为我正在编写的更大函数的一部分,我希望用户能够使用他们选择的函数(例如,均值,中值)来折叠这些行。

我的问题是,如果我直接调用该函数,速度比使用match.fun(这是我需要的)快得多。 MWE:

require(data.table)

rows <- 100000
cols <- 1000
dat <- data.table(id=sample(LETTERS, rows, replace=TRUE), 
                  matrix(rnorm(rows*cols), nrow=rows))

aggFn <- "median"

system.time(dat[, lapply(.SD, median), by=id])
system.time(dat[, lapply(.SD, match.fun(aggFn)), by=id])

在我的系统上,最后两行的计时结果:

   user  system elapsed 
  1.112   0.027   1.141 
   user  system elapsed 
  2.854   0.265   3.121 

对于更大的数据集,这变得非常引人注目。

最后一点,我意识到aggregate()可以做到这一点(并且似乎没有这种行为),但由于数据大小,我需要使用data.table对象。

1 个答案:

答案 0 :(得分:3)

原因是gforce优化data.table适用于median。如果设置options(datatable.verbose=TRUE),则可以看到。有关详细信息,请参阅help("GForce")

如果您比较其他功能,您会得到更多相似的时间:

fun <- median
aggFn <- "fun"
system.time(dat[, lapply(.SD, fun), by=id])
system.time(dat[, lapply(.SD, match.fun(aggFn)), by=id])

如果函数恰好得到支持,使用优化的可能解决方法是使用它来评估表达式构建,例如,使用可怕的eval(parse())

dat[, eval(parse(text = sprintf("lapply(.SD, %s)", aggFn))), by=id]

但是,使用match.fun添加会丢失小安全性。

如果您有用户可以选择的功能列表,您可以这样做:

funs <- list(quote(mean), quote(median))
fun <- funs[[1]] #select
expr <- bquote(lapply(.SD, .(fun)))
a <- dat[, eval(expr), by=id]