Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use data.table inside a function?

Tags:

r

data.table

As a minimal working example, for instance, I want to be able to dynamically pass expressions to a data.table object to create new columns or modify existing ones:

dt <- data.table(x = 1, y = 2)
dynamicDT <- function(...) {
    dt[, list(...)]
}
dynamicDT(z = x + y)

I was expecting:

   z
1: 3

but instead, I get the error:

Error in eval(expr, envir, enclos) : object 'x' not found 

So how can I fix this?

Attempts:

I've seen this post, which suggests using quote or substitute, but

> dynamicDT(z = quote(x + y))
Error in `rownames<-`(`*tmp*`, value = paste(format(rn, right = TRUE),  : 
  length of 'dimnames' [1] not equal to array extent

or

> dynamicDT <- function(...) {
+     dt[, list(substitute(...))]
+ }
> dynamicDT(z = x + y)
Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L,  : 
  first argument must be atomic

haven't worked for me.

like image 698
mchen Avatar asked May 28 '14 11:05

mchen


2 Answers

This should be a better alternative to David's answer:

dynamicDT <- function(...) {
 dt[, eval(substitute(...))]
}

dynamicDT(z := x + y)
#   x y z
#1: 1 2 3
like image 112
Roland Avatar answered Sep 26 '22 12:09

Roland


You will need to use eval(parse(text = )) combination. parse will transform the string into an expression, while eval will evaluate it.

library(data.table)
dt <- data.table(x = 1, y = 2)
dynamicDT <- function(temp = "") {
  dt[, eval(parse(text = temp))]
}

In order to get your previous desired output

dynamicDT("z := x + y")
##    x y z
## 1: 1 2 3

In order to get your current desired output

dynamicDT("z = x + y")
## [1] 3

In order to parse multiple arguments you can do

dynamicDT('c("a","b") := list(x + y, x - y)')

##   x y a  b
##1: 1 2 3 -1
like image 34
David Arenburg Avatar answered Sep 24 '22 12:09

David Arenburg