【问题标题】:Passing multiple arguments to data.table inside a function将多个参数传递给函数内的 data.table
【发布时间】:2019-07-29 11:43:35
【问题描述】:

这是我想要来自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

我想通过将参数传递给函数来获得输出。

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)")

但是,我收到一条错误消息。

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

【问题讨论】:

标签: r data.table


【解决方案1】:

只是给你一个选择, 如果您可以/想要使用table.express, 你也可以在很多情况下使用字符串:

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

在下一个版本中,start_exprend_expr 将是可选的。

【讨论】:

    【解决方案2】:

    您真的想将条件作为字符串传递吗?如果是这样,一种方法是使用paste 一起构造查询,然后使用eval(parse... 对其进行评估

    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
    

    【讨论】:

    • 我最好将表达式(而不是字符串)传递给processFUN()。这可能吗?
    • @WilliamChiu 是的,表达式也应该可以。
    【解决方案3】:

    或者使用evalsubstitute

    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))
    

    我能找到的一些最早的参考资料是

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

    旧的 faq 1.6 包含对此的引用: http://datatable.r-forge.r-project.org/datatable-faq.pdf

    【讨论】:

    • 重新“在外面使用它是行不通的”——似乎是错误的。实际上它在 j 中可以正常工作,只是在 by= 中不行。 select = ".(mean_mpg = mean(mpg), median_mpg = median(mpg))"; dt_mtcars[, eval(parse(text = select))]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 2020-05-15
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    相关资源
    最近更新 更多