首页 文章

在summarize()中使用变量作为参数

提问于
浏览
0

我希望将用户输入变量传递给group_by()和summarize()函数 .

数据框和代码的直接示例如下 . 在这里,我对列名称进行了“硬编码” .

library(dplyr)
df <- data.frame('Category' = c('a','c','a','a','b','a','b','b'), 
             'Amt' = c(100,300,200,400,500,1000,350,250), 
             'Flag' = c(0,1,1,1,0,1,1,0))
rowCount <- nrow(df)
totalAmt <- sum(df$Amt)
g <- group_by(df, Category)
summ <- summarize(g, Count = n(), CountPercentage = n()*100/rowCount, TotalAmt = sum(Amt), AmtPercentage = sum(Amt)*100/totalAmt, FlagSum = sum(Flag))
summ

输出如下

enter image description here

在我正在开发的应用程序中,数据框以及列名称将由用户定义 . 我将读取.csv文件名,要分组的列以及要从Excel文件汇总的列 .

我已经进行了广泛的搜索,在花了很多时间阅读和试验之后,我发现下面显示的解决方案对我有用 . 我没有使用滚边来使步骤更清晰 .

#The data frame df is read from the .csv file name
#Variables read from the Excel file
groupby <- 'Category'
sumBy1 <- 'Amt'
sumBy2 <- 'Flag'

rowCount <- nrow(df)
totalAmt <- sum(df[sumBy1])

g <- group_by_(df, groupby) #group by variable  #grouping

summcount <- summarize(g, Count = n(), CountPercentage = n()*100/rowCount) #summarize counts  #piece 1

summamt <- summarize_at(g, .vars = sumBy1, .funs=sum) #summarize by first variable
summamt <- summamt[-1] #remove first column to remove duplicate column
summamt$AmtPercentage <- summamt[sumBy1]*100/totalAmt  #piece 2

summflag <- summarize_at(g, .vars = sumBy2, .funs=sum) #summarize by second variable
summflag <- summflag[-1] #remove first column to remove duplicate column #piece 3

summ <- cbind(summcount, summamt, summflag)  #combine dataframes
summ

结果与上述相同 . 正如您所看到的,我正在创建最终的数据帧,然后绑定它们 . 代码很难看 . 另外,如何在此语法中定义列 Headers ?我确实考虑过summarize_all(),但这需要创建数据框的子集 . 我已经阅读了以下问题,但它们对我不起作用

Passing arguments to dplyr summarize function

Summarizing data in table by group for each variable in r

你能推荐一种更简单,更优雅的方法吗?

上面我有'硬编码'两种类型的摘要,即 . 数和总和 . 要增加另一级别的复杂性,如果用户还要定义所需的摘要类型(即总和,平均值,计数等),该怎么办?在Excel文件中,我可以捕获每个变量所需的汇总类型 .

谢谢你的任何建议 .

1 回答

  • 0

    这听起来像是超人的工作!或者至少是准引用 .

    您想使用bang-bang运算符 !! 插入变量 .

    你可以这样做

    # Make a variable symbol from strings
    make_var <- function(prefix, var, suffix) 
        as.symbol(paste0(prefix, var, suffix))
    calc_summary <- function(df, groupby, sumBy1, sumBy2) {
        totalSumBy1      <- make_var("Total", sumBy1, "")
        sumBy1Percentage <- make_var("", sumBy1, "Percentage")
        sumBy1           <- make_var("", sumBy1, "")
        sumBy2Sum        <- make_var("", sumBy2, "Sum")
        sumBy2           <- make_var("", sumBy2, "")
    
        group_by_(df, groupby) %>%
            summarize(Count = n(), 
                      CountPercentage = n()*100/rowCount,
                      !!totalSumBy1 := sum(!!sumBy1),
                      !!sumBy2Sum := sum(!!sumBy2)) %>%
            mutate(CountPercentage = Count/sum(Count),
                   !!sumBy1Percentage := 100 * !!totalSumBy1 / sum(!!totalSumBy1)) 
    }
    

    当您使用 !! 时,您正在插入变量的值,因此您可以参数化为 dplyr 函数赋予的表达式 . 你需要它们作为符号,这就是我使用 make_var 函数的原因 . 它可以更优雅地完成,但这将为您提供您在示例中使用的变量 .

    请注意,当我们分配的变量是动态的时,我们必须使用 := 赋值而不是 = . 否则,解析器会抱怨 .

    你可以这样使用这个功能:

    > df %>% calc_summary("Category", "Amt", "Flag")
    # A tibble: 3 x 6
      Category Count CountPercentage TotalAmt FlagSum AmtPercentage
      <fct>    <int>           <dbl>    <dbl>   <dbl>         <dbl>
    1 a            4           0.500    1700.      3.         54.8 
    2 b            3           0.375    1100.      1.         35.5 
    3 c            1           0.125     300.      1.          9.68
    

    列的顺序与示例中的不同,但您可以使用 select 进行修复 . 我通过在摘要之后将它们移动到 mutate 来清理百分比计算 . 它消除了对 rowCount 变量的需要 . 如果您愿意,可以轻松使用该变量并避免 mutate 调用 . 然后,您还可以在 summarise 调用中按所需顺序获取列 .

    无论如何,重要的一点是,你想要bang-bang操作员在这里做什么 .

相关问题