【问题标题】:Passing multiple column names to "by" in a data.table function将多个列名传递给 data.table 函数中的“by”
【发布时间】:2020-05-15 01:10:58
【问题描述】:

我已经阅读了很多关于将列名传递给 data.table 函数的帖子,但我没有看到一篇关于将多个变量传递给“by”的帖子。我通常使用这样的代码来按组计算汇总统计数据。

# Data
library(data.table)
dt=mtcars
setDT(dt)

# Summary Stats Example
dt[cyl==4,.(Count=.N,
    Mean=mean(hp),
    Median=median(hp)),
    by=.(am,vs)]

#    am vs Count   Mean Median
# 1:  1  1     7 80.571     66
# 2:  0  1     3 84.667     95
# 3:  1  0     1 91.000     91

我无法使用以下功能:

# Function
myFun <- function(df,i,j,by){
    df[i==4,.(Count=.N,
      Mean=mean(j),
      Median=median(j)),
      by=.(am,by)]
}
myFun(dt,i='cyl',j='hp',by='vs')

请注意,我将“4”和“am”硬编码到此示例的函数中。 get() 通过分组变量仅使用 1 时有效,但在使用多个分组变量时失败。感谢您在编写 data.table 函数时如何正确使用 get/quote/eval/substitute/parse/as.name/etc 的指导。

【问题讨论】:

标签: r function data.table


【解决方案1】:

我已经接受了 sm95 的回答。下面是一个更复杂的示例/解决方案,它将列表发送到 by 参数:

# Libraries
library(data.table)

# Data
dt = mtcars
setDT(dt)

# Function to calculate summary statistics
myFun <- function(df, i1var, i1val, i2var, i2val,            # i arguments
                                    j,                       # j arguments
                                    by1var, by2var, by2val){ # by arguments
    df[get(i1var) == i1val & get(i2var) %in% i2val,
         .(Count = .N,
            Mean = mean(get(j)),
            Median = median(get(j))),
        by = .(get(by1var), get(by2var) == by2val)]
} # END Function

# Run function
myFun(dt,i1var = 'cyl', i1val = 4, i2var = 'gear', i2val = c(3,4),
            j = 'hp',
            by1var = 'vs', by2var = 'am', by2val = 1)
#    vs am Count     Mean Median
# 1:  1  1     6 75.16667     66
# 2:  1  0     3 84.66667     95

# Should match
dt[cyl == 4 & gear %in% c(3,4),
     .(Count = .N,
        Mean = mean(hp),
        Median = median(hp)),
     by = .(vs, am == 1)]
#    vs am Count     Mean Median
# 1:  1  1     6 75.16667     66
# 2:  1  0     3 84.66667     95

这是我的备忘单:

  • 使用get(var) 传递ijby 变量
  • 直接通过iby 条件

以上可能不适用于更复杂的功能,也可能不是最优的。

如果by 是向量而不是列表(例如,by=c()by=.()),则可以直接传递 by 参数。

【讨论】:

    【解决方案2】:

    只需为data.tableby 部分创建一个字符向量,它就可以工作:

    myFun <- function(df, i, j, by){
    
     df[get(i) == 4, .(Count = .N, 
               Mean = mean(get(j)),
               Median = median(get(j))),
      by = c(by, 'am')]
    }
    
    
    
    myFun(dt, i = 'cyl', j = 'hp', by = 'vs')
    
    #vs am Count     Mean Median
    #1:  1  1     7 80.57143     66
    #2:  1  0     3 84.66667     95
    #3:  0  1     1 91.00000     91
    

    【讨论】:

    • eval(by) 不是必需的。
    • 感谢@sm925 和@sindri_baldur。我注意到上面的代码将 by 参数从列表更改为向量。我的示例没有显示它,但我通常在 by 参数中应用标准(例如 grp&gt;2),所以对于我的一般目的,我需要使用 by=.()
    • 您的回答帮助我制作了以下备忘单: - 通过 i、j 和使用 get(var) 的变量 - 通过 i 或直接通过标准 以上假设 by 是一个列表。在更复杂的情况下,上述方法可能会失败或被视为不好的做法。例如,我使用merge() 而不是利用[ 来连接两个data.tables。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    相关资源
    最近更新 更多