2

When creating a new variable with columns, data.table does not allow quoted column names. This yields the following problem when using a data.table within a function.

library(data.table) 
dt <- data.table(var1 = c(1:10), var2 = seq(2,20,2), var3 = seq(40,4,-4))    

addColumnsError <- function(dt, v1, v2){
  dt[,v1 + v2]
}

addColumnsError(dt, var1, var2)
>  Error in eval(jsub, SDenv, parent.frame()) : object 'var1' not found 

addColumnsError(dt, "var1", "var2")
>   Error in v1 + v2 : non-numeric argument to binary operator

The following workaround handles this problem.

addColumns <- function(dt,v1,v2){

  v1<-as.character(substitute(v1))
  v2<-as.character(substitute(v2))

  dt[,eval(parse(text=v1)) + eval(parse(text=v2))]
}

addColumns(dt, var1, var2)
[1]  3  6  9 12 15 18 21 24 27 30
addColumns(dt, "var1", "var2")
[1]  3  6  9 12 15 18 21 24 27 30

Is there a more elegant way to pass column names to a data.table object within a function?

(Note: I could just call the data.table function but I intend to make more complicated calculations :) )

caranbot
  • 103
  • 1
  • 6

3 Answers3

2

If you want to use non-standard evaluation, you need something like substitute. However, there is absolutely no reason for using parse.

addColumnsError <- function(dt, v1, v2){
  eval(substitute(dt[, v1 + v2]))
}

addColumnsError(dt, var1, var2)
#[1]  3  6  9 12 15 18 21 24 27 30
Roland
  • 127,288
  • 10
  • 191
  • 288
1

I think you are looking for get()!

library(data.table) 
dt <- data.table(var1 = c(1:10), var2 = seq(2,20,2), var3 = seq(40,4,-4))    

addColumnsError <- function(dt, v1, v2){
  dt[,get(v1) + get(v2)]
}

addColumnsError(dt, "var1", "var2")

Best!

LocoGris
  • 4,432
  • 3
  • 15
  • 30
1

Using .SDcols (which accepts characters) you could do:

addColumns <- function(dt, v1, v2){
  dt[, .SD[[1]] + .SD[[2]], .SDcols = c(v1, v2)]
}

# or more elegantly:
addColumns <- function(dt, v1, v2){
  dt[, rowSums(.SD), .SDcols = c(v1, v2)]
}

addColumns(dt, "var1", "var2")
# [1]  3  6  9 12 15 18 21 24 27 30
s_baldur
  • 29,441
  • 4
  • 36
  • 69