Passing multiple arguments to data.table inside a function

回眸只為那壹抹淺笑 提交于 2021-02-11 10:30:07

问题


Here is the output that I want from data.table.

library(data.table)
dt_mtcars <- as.data.table(mtcars)

## desired output ----
dt_mtcars[mpg >20
          , .(mean_mpg = mean(mpg)
              ,median_mpg = median(mpg))
          , .(cyl, gear)]

   cyl gear mean_mpg median_mpg
1:   6    4   21.000      21.00
2:   4    4   26.925      25.85
3:   6    3   21.400      21.40
4:   4    3   21.500      21.50
5:   4    5   28.200      28.20

I want to get the output by passing arguments to a function.

processFUN <- function(dt, where, select, group){

  out <- dt[i=eval(parse(text = where))
            ,j=eval(parse(text = select))
            ,by=eval(parse(text = group))]

  return(out)
}

report <- processFUN(dt_mtcars 
                     ,where= "mpg > 20"
                     ,select= ".(mean_mpg = mean(mpg), median_mpg = median(mpg))"
                     ,group= ".(cyl, gear)")

However, I get an error message.

 Error in .(cyl, gear) : could not find function "." 


回答1:


Or using eval with substitute:

library(data.table) #Win R-3.5.1 x64 data.table_1.12.2
dt_mtcars <- as.data.table(mtcars)

processFUN <- function(dt, where, select, group) {

    out <- dt[i=eval(substitute(where)), 
        j=eval(substitute(select)), 
        by=eval(substitute(group))]

    return(out)
}

processFUN(dt_mtcars, mpg>20, .(mean_mpg=mean(mpg), median_mpg=median(mpg)), .(cyl, gear))

Some of the earliest references that I can find are

  1. Aggregating sub totals and grand totals with data.table
  2. Using data.table i and j arguments in functions

The old faq 1.6 contains reference to this: http://datatable.r-forge.r-project.org/datatable-faq.pdf




回答2:


Just to give you an alternative, if you can/want to use table.express, you can also use strings in many situations:

library(data.table)
library(table.express)

processFUN <- function(dt, where, select, group) {
  dt %>%
    start_expr %>%
    group_by(!!!group, .parse = TRUE) %>%
    where(!!!where, .parse = TRUE) %>%
    transmute(!!!select, .parse = TRUE) %>%
    end_expr
}

processFUN(as.data.table(mtcars),
           "mpg>20",
           c("mean_mpg = mean(mpg)", "median_mpg = median(mpg)"),
           c("cyl", "gear"))
   cyl gear     V1    V2
1:   6    4 21.000 21.00
2:   4    4 26.925 25.85
3:   6    3 21.400 21.40
4:   4    3 21.500 21.50
5:   4    5 28.200 28.20

In the next release, start_expr and end_expr will be optional.




回答3:


Do you really want to pass conditions as strings? If so, one way would be to construct the query together using paste and then use eval(parse... to evaluate it

library(data.table)

processFUN <- function(dt, where, select, group){
    eval(parse(text = paste0(as.character(substitute(dt)), "[", where, ",", 
               select, ",by = ", group, "]")))
}

processFUN(dt_mtcars 
          ,where= "mpg > 20"
          ,select= ".(mean_mpg = mean(mpg), median_mpg = median(mpg))"
          ,group= ".(cyl, gear)")


#   cyl gear mean_mpg median_mpg
#1:   6    4   21.000      21.00
#2:   4    4   26.925      25.85
#3:   6    3   21.400      21.40
#4:   4    3   21.500      21.50
#5:   4    5   28.200      28.20


来源:https://stackoverflow.com/questions/57253159/passing-multiple-arguments-to-data-table-inside-a-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!