【问题标题】:How to convert r data.table expression into a function for looping如何将 r data.table 表达式转换为循环函数
【发布时间】:2019-06-18 19:26:53
【问题描述】:

我正在尝试将 R data.table 代码 sn-p 转换为适当的函数,但我没有成功。

我想用这段代码总结一个变量:

library(data.table)
mtcars_dt <- 
  data.table(mtcars)

# Expression
mtcars_dt[,list(.N),by=cyl][order(cyl),list(cyl,N,Proportion=N/sum(N))]

结果是一个 data.table(如预期的那样):

   cyl  N Proportion
1:   4 11    0.34375
2:   6  7    0.21875
3:   8 14    0.43750

然后我希望创建一个函数并将此函数应用于多个变量,并在循环的每次迭代中生成一个 data.table 应用该函数:

# turn into function and apply loop, returning DT from each iteration
var_list <- c('cyl','gear')
for (i in var_list){
  # generalize the code above
}

我不确定最好的方法。我尝试了这个解决方案,但我丢失了第一列中的变量名。我想知道我是否走错了 eval(quote(...))

# My attempt, not working yet!
var_list <- c(quote(cyl),quote(gear))
f_numeric_cat <- 
  function(dt,var1) {
    dt[,list(.N),by=eval(var1)][order(eval(var1)),Proportion:=N/sum(N)][]
  }
for (i in var_list){
  print(f_numeric_cat(mtcars_dt,i))
}
   var1  N Proportion
1:    6  7    0.21875
2:    4 11    0.34375
3:    8 14    0.43750
   var1  N Proportion
1:    4 12    0.37500
2:    3 15    0.46875
3:    5  5    0.15625

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    目标是一个函数DT & var要做的事情:

    DT[, list(.N), by=var][order(var), list(var, N, Proportion=N/sum(N))]
    

    要按变量进行计算然后按其排序,请使用keyby=。所以你的函数可以变成:

    f_tabulate <- 
      function(DT, var) {
        DT[, list(.N), keyby=var][, Proportion := N/sum(N)][]
      } 
    # usage
    for (i in c('cyl', 'gear')) print(f_tabulate(mtcars_dt, i))
    

    keyby=by= 可以采用多种形式的参数,您不需要引用或评估一个简单的变量名向量。 (其他方式包括.(var1, var2)list(var1, var2)"var1,var2"。)您还可以扩展到通过多个变量进行计数...

    f_tabulate2 <- 
      function(DT, ...) {
        DT[, list(.N), keyby=c(...)][, Proportion := N/sum(N)][]
      } 
    # usage
    f_tabulate2(mtcars_dt, 'cyl', 'gear')
    

    对于这个操作(除了订购部分),你也可以使用groupingsets()

    > groupingsets(mtcars_dt, .N, keyby=c('cyl', 'gear'), sets=list("cyl", "gear"))[, 
        Proportion := N/nrow(mtcars_dt)][]
       cyl gear  N Proportion
    1:   6   NA  7    0.21875
    2:   4   NA 11    0.34375
    3:   8   NA 14    0.43750
    4:  NA    4 12    0.37500
    5:  NA    3 15    0.46875
    6:  NA    5  5    0.15625
    

    作为一个函数(并重新添加排序)...

    f_tabulate_all = function(DT, vars){
      lvars = as.list(vars)
      ocall = as.call(lapply(c("order", vars), as.name))
      groupingsets(DT[eval(ocall)], .N, by=vars, sets=as.list(vars))[, 
        Proportion := N/nrow(DT)][]
    }
    # usage
    f_tabulate_all(mtcars_dt, c('cyl', 'gear'))
    

    as.name 函数与 quote 应用于命名函数或其他对象的字符串时实现相同的功能。

    【讨论】:

    • 不错的答案!一般不推荐 eval(quote()) 方法吗?
    • @co_biostat 谢谢 :) 我认为这是推荐的,as.call/call 正在使用相同的想法。 data.table 常见问题解答中曾经有关于如何操作的指导,但在可以重写/更新之前将其删除:github.com/Rdatatable/data.table/issues/2209 这是另一个示例:stackoverflow.com/a/39124362
    • 我确实注意到从常见问题解答中删除了该指南,并想知道这是否意味着它不再是理想的方法。感谢您的信息
    猜你喜欢
    • 1970-01-01
    • 2020-11-02
    • 2011-03-25
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 2020-02-06
    • 2013-11-03
    • 2021-12-29
    相关资源
    最近更新 更多