【问题标题】:In a named argument to dplyr::funs, can I reference the names of other arguments?在 dplyr::funs 的命名参数中,我可以引用其他参数的名称吗?
【发布时间】:2019-04-08 04:06:10
【问题描述】:

考虑以下几点:

library(tidyverse)

df <- tibble(x = rnorm(100), y = rnorm(100, 10, 2), z = x * y)

df %>% 
mutate_all(funs(avg = mean(.), dev = sd(.), scaled = (. - mean(.)) / sd(.)))

有没有办法通过引用avg 和dev 列来避免调用mean 和sd 两次。我的想法是这样的

df %>% 
mutate_all(funs(avg = mean(.), dev = sd(.), scaled = (. - avg) / dev))

显然这行不通,因为没有列avg 和dev,而是x_avg、x_dev、y_avg、y_dev 等。

有没有一种好方法,在funs 中使用rlang 工具以编程方式创建这些列引用,这样我就可以将由先前命名参数创建的列引用到funs(当. 是x,我会参考x_mean 和x_dev 来计算x_scaled,等等)?

【问题讨论】:

    标签: r dplyr rlang


    【解决方案1】:

    这可能对你有用:

    avg <- quo(mean(.))
    dev <- quo(sd(.))
    res <- df %>% 
      mutate_all(funs(avg = !!avg, dev = !!dev, scaled = (. - !!avg) / !!dev))
    

    确认它有效:

    res0 <- df %>% 
      mutate_all(funs(avg = mean(.), dev = sd(.), scaled = (. - mean(.)) / sd(.)))
    identical(res, res0)
    # [1] TRUE
    

    【讨论】:

    • 从技术上讲,这仍然计算 mean(.) 和 sd(.) 两次,但这是表达式算术的一个巧妙示例。
    【解决方案2】:

    这似乎有点令人费解,但确实有效:

    scaled <- function(col_name, x, y) {
      col_name <- deparse(substitute(col_name))
      avg <- eval.parent(as.symbol(paste0(col_name, x)))
      dev <- eval.parent(as.symbol(paste0(col_name, y)))
      (eval.parent(as.symbol(col_name)) - avg) / dev
    }
    
    df %>%
      mutate_all(funs(avg = mean(.), dev = sd(.), scaled = scaled(., "_avg", "_dev"))) 
    

    【讨论】:

      【解决方案3】:

      我认为将数据转换为长格式会更容易

      library(tidyverse)
      
      set.seed(111)
      df <- tibble(x = rnorm(100), y = rnorm(100, 10, 2), z = x * y)
      
      df %>% 
        gather(key, value) %>% 
        group_by(key) %>% 
        mutate(avg    = mean(value),
               sd     = sd(value),
               scaled = (value - avg) / sd)
      #> # A tibble: 300 x 5
      #> # Groups:   key [3]
      #>    key    value     avg    sd scaled
      #>    <chr>  <dbl>   <dbl> <dbl>  <dbl>
      #>  1 x      0.235 -0.0128  1.07  0.232
      #>  2 x     -0.331 -0.0128  1.07 -0.297
      #>  3 x     -0.312 -0.0128  1.07 -0.279
      #>  4 x     -2.30  -0.0128  1.07 -2.14 
      #>  5 x     -0.171 -0.0128  1.07 -0.148
      #>  6 x      0.140 -0.0128  1.07  0.143
      #>  7 x     -1.50  -0.0128  1.07 -1.39 
      #>  8 x     -1.01  -0.0128  1.07 -0.931
      #>  9 x     -0.948 -0.0128  1.07 -0.874
      #> 10 x     -0.494 -0.0128  1.07 -0.449
      #> # ... with 290 more rows
      

      由reprex package (v0.2.1.9000) 于 2018 年 11 月 4 日创建

      【讨论】:

      • 值得注意的是,如果需要,可以使用 spread 将结果转换回宽格式。
      猜你喜欢
      • 2016-10-19
      • 1970-01-01
      • 2011-03-24
      • 2018-10-11
      • 1970-01-01
      • 2014-11-02
      • 2013-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多