Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic / private function name in dcast.data.table

Tags:

r

data.table

I have a question about the scope within which function names in data.table::dcast calls are evaluated (data.table version 1.9.6, R 3.2.2).

I'd like to make the function name, but this fails.

Here is what I have tried:

library(data.table)
DT <- data.table(value = c(1:10),
                 cat1 = c("a", "b", "a", "b", "a", "b", "a", "b", "c", "a"),
                 cat2 = c("x", "x", "x", "y", "y", "y", "y", "y", "y", "x"))

This works fine:

result1 <- dcast.data.table(DT, cat1 ~ cat2, value.var = "value", fun = sum)

Now I make my own function, which also works:

f1 <- function(x) {
    y <- sum(x) ^ 2
    return(y)
}
result2 <- dcast.data.table(DT, cat1 ~ cat2, value.var = "value", fun = f1)

Here I do the same thing, but I am creating a private function within a function. However, this fails with Error in eval(expr, envir, enclos) : could not find function "f2".

If I replace f2 with f1 it works and calls f1. It seems that it's looking at the global environment to evaluate the expression fun=f2, and f2 exists in the local scope only.

testFunction <- function(DT1) {
    f2 <- function(x) {
        y <- sum(x) ^ 2
        return(y)
    }
    r3 <- dcast.data.table(DT1,cat1 ~ cat2, value.var = "value", fun = f2)
    return(r3)
}
result3 <- testFunction(DT)

Is there any way around that? What I really wanted to do is make the function name f2 dynamic, so that I pass in, let's say, "f3", and it will call private function f3.

I would have hoped that something like

functionName = "f3"
r3 <- dcast.data.table(DT1, cat1 ~ cat2, value.var = "value", fun = get(functionName))

...would get me there, but this does not seem to work. Any ideas?

like image 967
user5577796 Avatar asked Nov 18 '15 17:11

user5577796


1 Answers

Based on the bug report I was able to work around the issue for now by using a parameter named "fun.aggregate".

Thanks for pointing me to it.

The code below works and achieves what I need. I can pass in a pre-existing function name such as mean or a locally defined function.

   testFunction <- function(DT1,functionName="mean") {

    f2 <- function(x) {
        y <- sum(x) ^ 2
        return(y)
    }

    fun.aggregate <- get(functionName)

    r3 <- dcast.data.table(DT1,cat1~cat2,value.var="value",fun.aggregate=fun.aggregate)
    return(r3)
}
result3 <- testFunction(DT,"mean")
result4 <- testFunction(DT,"f2")
like image 91
user5577796 Avatar answered Nov 09 '22 12:11

user5577796