首页 > 解决方案 > 将变量名作为参数传递给 data.table

问题描述

我正在尝试创建一个修改 data.table 的函数,并想使用一些非标准的评估,但我意识到我真的不知道如何在 data.tables 中使用它。我的功能基本上是这样的:

do_stuff <- function(dt, col) {
  copy(dt)[, new_col := some_fun(col)][]
}

我想这样称呼它:

do_stuff(data, column)

其中“column”是“data”中存在的列的名称。如果我运行该函数,我会收到一个错误:

#> Error in some_fun(col) : object 'column' not found 

这对我说 data.table 显然将正确的名称传递给函数(“列”),但由于某种原因它没有找到它。这是一个最小的可重现示例

library(data.table)

data <- data.table(x = 1:10, y = rnorm(10))

plus <- function(x, y) {
   x + y
}

add_one <- function(data, col) {
   copy(data)[, z := plus(col, 1)][]
}

add_one(data, y)
#> Error in plus(col, 1): object 'y' not found

不幸的是,使用deparse(substitute(col))似乎不起作用:(

add_one <- function(data, col) {
   copy(data)[, z := plus(deparse(substitute(col)), 1)][]
}

add_one(data, y)
#> Error in x + y: non-numeric argument to binary operator

标签: rdata.table

解决方案


通常, quote 和 eval 将起作用:

library(data.table)
plus <- function(x, y) {
   x + y
}

add_one <- function(data, col) {
   expr0 = quote(copy(data)[, z := plus(col, 1)][])

   expr  = do.call(substitute, list(expr0, list(col = substitute(col))))
   cat("Evaluated expression:\n"); print(expr); cat("\n")

   eval(expr)
}

set.seed(1)
library(magrittr)
data.table(x = 1:10, y = rnorm(10)) %>% 
   add_one(y)

这使

Evaluated expression:
copy(data)[, `:=`(z, plus(y, 1))][]

     x          y         z
 1:  1 -0.6264538 0.3735462
 2:  2  0.1836433 1.1836433
 3:  3 -0.8356286 0.1643714
 4:  4  1.5952808 2.5952808
 5:  5  0.3295078 1.3295078
 6:  6 -0.8204684 0.1795316
 7:  7  0.4874291 1.4874291
 8:  8  0.7383247 1.7383247
 9:  9  0.5757814 1.5757814
10: 10 -0.3053884 0.6946116

推荐阅读