简体   繁体   中英

Manipulate data.table objects within user defined function

I'm trying to write functions that use data.table methods to add and edit columns by reference. However, the same code that work in the console does not work when called from within a function. Here is a simple examples:

> dt <- data.table(alpha = c("a","b","c"), numeric = 1:3)
> foo <- function(x) {
    print(is.data.table(x))
    x[,"uppercase":=toupper(alpha)]
}

When I call this function, I get the following error.

> test = foo(dt)
[1] TRUE
 Error in `:=`("uppercase", toupper(alpha)) : 
 Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are
 defined for use in j, once only and in particular ways. See help(":="). 

Yet if I type the same code directly into the console, it works perfectly fine.

> dt[,"uppercase":=toupper(alpha)]
> dt
   alpha numeric uppercase
1:     a       1         A
2:     b       2         B
3:     c       3         C

I've scoured stackoverflow and the only clues I could find suggest that the function might be looking for alpha in a different environment or parent frame.

EDIT: More information to reproduce the error. The function is not within a package, but declared directly in the global environment. I didn't realize this before, but in order to reproduce the error I need to dump the function to a file, then load it. I've saved all of my personal functions via dput and load them into R with dget , so that's why I get this error often.

> dput(foo, "foo.R")
> foo <- dget("foo.R")
> foo(dt)
 Error in `:=` etc...

This problem is a different flavor of the one described in the post Function on data.table environment errors . It's not exactly a problem, just how dget is designed. But for those curious, this happens because dget assigns the object to parent environment base , and the namespace base isn't data.table aware.

If x is a function the associated environment is stripped. Hence scoping information can be lost.

One workaround is to assign the function to the global enviornment:

> environment(foo) <- .GlobalEnv

But I think the best solution here is to use saveRDS to transfer R objects, which is what ?dget recommends.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM