【问题标题】:take mean of variable defined by string in dplyr取dplyr中字符串定义的变量的平均值
【发布时间】:2017-12-28 20:02:11
【问题描述】:

看起来这应该很容易,但我很难过。我已经掌握了使用dplyr 0.7 进行编程的粗略窍门,但为此苦苦挣扎:如果我要编程的变量是字符串,我该如何在dplyr 中编程?

我正在抓取一个数据库,出于各种原因想总结一个我知道位置但不知道名称的变量(我想要的总是提供的表的第一列,但名称存储在该列中的变量将根据被抓取的数据库而有所不同)。以iris为例,假设我知道我想要的变量在第一列

library(tidyverse)
desired_var <- colnames(iris)[1]
print(desired_var)
"Sepal.Length"

我现在想按Species 分组,取desired_var 的平均值,即我想要执行的操作

iris %>% 
group_by(Species) %>% 
summarise(desired_mean = mean(Sepal.Length))

但是,现在我想取由存储在desired_var 中的字符串定义的列的平均值

我知道如何用“裸”Sepal.Length 做到这一点

desired_var <- quo(Sepal.Length)

iris %>% 
group_by(Species) %>% 
summarise(desired_mean = mean(!!desired_var))

但是我到底该如何处理我拥有 "Sepal.Length" 而不是 Sepal.Length 的事实,即 desired_var &lt;- "Sepal.Length" 呢?

【问题讨论】:

    标签: r dplyr tidyverse


    【解决方案1】:

    您想知道tidyevaltidyverse 的一个相当新的功能(参见here),更多用于使用tidyverse 函数创建函数。目前它仅适用于dplyr,但计划将其扩展到其他tidyverse 包。

    不过,对于您的需要,您并不需要真正参与其中,summarize_at 就可以了。此函数允许您将指定的特定操作扩展到您选择的任何变量:

    iris %>% 
      group_by(Species) %>% 
      summarise_at(vars(one_of("Sepal.Length", "Sepal.Width")), funs(desired_mean = mean))
    
    # A tibble: 3 x 3
         Species Sepal.Length_desired_mean Sepal.Width_desired_mean
          <fctr>                     <dbl>                    <dbl>
    1     setosa                     5.006                    3.428
    2 versicolor                     5.936                    2.770
    3  virginica                     6.588                    2.974
    

    您可以将变量列表存储到一个向量中,然后改用该向量:

    selected_vectors <- c("Sepal.Length", "Sepal.Width")
    iris %>% 
      group_by(Species) %>% 
      summarise_at(vars(one_of(selected_vectors)), funs(desired_mean = mean))
    

    【讨论】:

      【解决方案2】:

      1) 带有 !!sym 的动态变量 像这样使用sym(或parse_expr):

      library(dplyr)
      library(rlang)
      
      desired_var <- "Sepal.Length"
      
      iris %>% 
        group_by(Species) %>% 
        summarise(desired_mean = mean(!!sym(desired_var))) %>%
        ungroup
      

      给予:

      # A tibble: 3 x 2
           Species desired_mean
            <fctr>        <dbl>
      1     setosa        5.006
      2 versicolor        5.936
      3  virginica        6.588
      

      2) summarise_at 正如@Phil 在summarise 特定情况下的cmets 中指出的那样,这可以在不使用任何rlang 工具的情况下完成:

      library(dplyr)
      
      desired_var <- "Sepal.Length"
      
      iris %>% 
         group_by(Species) %>% 
         summarise_at(desired_var, funs(mean)) %>%
         ungroup
      

      给予:

      # A tibble: 3 x 2
           Species Sepal.Length
            <fctr>        <dbl>
      1     setosa        5.006
      2 versicolor        5.936
      3  virginica        6.588
      

      3) 动态变量和带有 !! 的名称 如果您需要在 (1) 中动态设置名称,请尝试以下操作:

      library(dplyr)
      library(rlang)
      
      desired_var <- "Sepal.Length"
      
      desired_var_name <- paste("mean", desired_var, sep = "_")
      
      iris %>% 
        group_by(Species) %>% 
        summarise(!!desired_var_name := mean(!!sym(desired_var))) %>%
        ungroup
      

      给予:

      # A tibble: 3 x 2
           Species mean_Sepal.Length
            <fctr>             <dbl>
      1     setosa             5.006
      2 versicolor             5.936
      3  virginica             6.588
      

      【讨论】:

      • 谢谢! !!!parse_expr 可以解决我需要的各种其他情况(例如,也可以按字符串分组)
      • 我无法理解这比 summarize_at 有什么优势。这似乎是一种更复杂的方法来实现相同的结果。
      • @Rich Scriven,请确保您使用的是每个软件包的最新版本。这表示最近添加的功能。
      • @Phil,我已将您的建议添加为 (2)
      • @Rich_Scriven,要么!要么 !!!应该管用。 !!!用于拼接多个参数,但这里我们只有一个!足够了。我已经简化了使用的答案!虽然 !!!没有错,它确实有效。
      猜你喜欢
      • 2021-02-14
      • 1970-01-01
      • 2015-04-28
      • 2016-04-04
      • 1970-01-01
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      相关资源
      最近更新 更多