【发布时间】:2021-12-11 15:59:31
【问题描述】:
我想创建一个使用列变量名和数据变量名的函数。
这个功能是我想要的,它可以工作:
n <- 1e7
d <- data.table(x = 1:n, grp = sample(1:1e5, n, replace = T))
dataName = "d"
colName = "x"
# Objective :
FOO <- function(dataName = "d",
colName = "x"){
get(dataName)[, mean(get(colName)), by = grp]
}
问题是对每个组的get() 进行评估非常耗时。在真实数据示例中,它比等效的静态名称长 14 倍。我想达到与列名是静态的相同的执行时间。
我尝试了什么:
(cl <- substitute(mean(eval(parse(text = colName))), list(colName = as.name(colName))))
microbenchmark::microbenchmark(
# 1) works and quick but does not use variable names of columns (654ms)
(t1 <- d[, mean(x), by = grp]),
# 2) works but slow (1006ms)
(t2 <- get(dataName)[, mean(get(colName)), by = grp]), # works but slow
# 3) works but slow (4075ms)
(t3 <- eval(parse(text = dataName))[, mean(eval(parse(text = colName))), by = grp]),
# 4) works but very slow (37202ms)
(t4 <- get(dataName)[, eval(cl), by = grp]),
# 5) double dot syntax doesn't work cause I don't master it
# (t5 <- get(dataName)[, mean(..colName), by = grp]),
times = 10)
双点语法在这里合适吗?为什么 4) 这么慢?我从this post 那里得到它,这是最好的选择。我从 post 改编了双点语法。
非常感谢您的帮助!
【问题讨论】:
-
您的
FOO函数是否需要使用get从变量name 中获取数据?基于命名空间/环境继承(尤其是在嵌套函数调用中),该方法将非常难以排除故障,并且似乎不必要地低效(而不是FOO("mydata"),只需调用FOO(mydata)?)。 -
谢谢!我认为将数据传递给函数会复制它并且效率会降低,但这似乎是一种误解。我应该更多地了解 R 函数的机制。感谢您指出这些缺点:)
-
使用 env var 参数化你的 data.table 查询,注意这个功能可能还没有在 CRAN 上
标签: r data.table