这个问题相当于Pass a data.frame column name to a function 的data.table 问题。
假设我有一个非常简单的 data.table:
dat <- data.table(x = 1:4,
y = 5:8)
Run Code Online (Sandbox Code Playgroud)
现在我想为任何给定的函数创建一个新列:
new_column <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Run Code Online (Sandbox Code Playgroud)
以便它正确地提供:
> new_column (dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Run Code Online (Sandbox Code Playgroud)
但是,因为它是一个 data.table,我想使用以下方法创建这个新列:=:
new_column_byref <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[, col_name:=eval(substitute(expr)
,df
,parent.frame()
)]
df
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用:
> a <- new_column_byref(dat,z,x+y)
Error: Check that is.data.table(DT) == TRUE. Otherwise, :=, `:=`(...) and let(...) are defined for use in j, once only and in particular ways. See help(":=").
Run Code Online (Sandbox Code Playgroud)
我该如何解决?谢谢。
new_column_byref <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
set(df,j=col_name,value=eval(substitute(expr),df,parent.frame()))
}
dat <- data.table(x = 1:4,y = 5:8)
new_column_byref(dat,z,x+y)[]
x y z
1: 1 5 6
2: 2 6 8
3: 3 7 10
4: 4 8 12
Run Code Online (Sandbox Code Playgroud)
set是 data.table 惯用的方式。如果您需要做其他事情,例如 use by,rlang有一种通用的方法来延迟评估,即enexprargs (或者 enquo ,如果您希望它们在原始环境中评估)并将!!它们放在inject您通常使用的表达式中。
library(rlang)
#> Warning: package 'rlang' was built under R version 4.1.2
library(data.table)
#>
#> Attaching package: 'data.table'
#> The following object is masked from 'package:rlang':
#>
#> :=
dat <- data.table(x = 1:4,
y = 5:8)
new_column <- function(df, col_name, expr) {
col_name <- enexpr(col_name)
expr <- enexpr(expr)
inject(df[, !!col_name := !!expr])
}
new_column(dat, z, x + y)
dat
#> x y z
#> <int> <int> <int>
#> 1: 1 5 6
#> 2: 2 6 8
#> 3: 3 7 10
#> 4: 4 8 12
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2022 年 2 月 25 日创建(v2.0.1)
或者,同样没有 rlang
library(data.table)
dat <- data.table(x = 1:4,
y = 5:8)
new_column <- function(df, col_name, expr) {
col_name <- deparse(substitute(col_name))
expr <- substitute(expr)
df[, (col_name) := eval(expr)]
}
new_column(dat, z, x + y)
dat
#> x y z
#> <int> <int> <int>
#> 1: 1 5 6
#> 2: 2 6 8
#> 3: 3 7 10
#> 4: 4 8 12
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2022 年 2 月 25 日创建(v2.0.1)
使用开发版本中的“语言编程”界面。
https://rdatatable.gitlab.io/data.table/news/index.html
library(data.table)
dat <- data.table(x = 1:4,
y = 5:8)
new_column <- function(df, col_name, expr) {
df[, col_name := expr,
env = list(col_name = substitute(col_name),
expr = substitute(expr))]
}
new_column(dat, z, x + y)
dat
#> x y z
#> <int> <int> <int>
#> 1: 1 5 6
#> 2: 2 6 8
#> 3: 3 7 10
#> 4: 4 8 12
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2022 年 3 月 1 日创建(v2.0.1)
或者使用match.call
library(data.table)
dat <- data.table(x = 1:4,
y = 5:8)
new_column <- function(df, col_name, expr) {
fun_call <- match.call()
df[, col_name := expr,
env = as.list(fun_call)[c('col_name', 'expr')]]
}
new_column(dat, z, x + y)
dat
#> x y z
#> <int> <int> <int>
#> 1: 1 5 6
#> 2: 2 6 8
#> 3: 3 7 10
#> 4: 4 8 12
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2022 年 3 月 1 日创建(v2.0.1)