【问题标题】:Lookup function for mutate in data数据变异的查找函数
【发布时间】:2018-08-31 05:48:52
【问题描述】:

我想在data.frame 的列中存储函数,或者至少是它们的名称,以便在调用mutate 时使用。一个简化的破例:

library(dplyr)
expand.grid(mu = 1:5, sd = c(1, 10), stat = c('mean', 'sd')) %>%
  group_by(mu, sd, stat) %>%
  mutate(sample = get(stat)(rnorm(100, mu, sd))) %>%
  ungroup()

如果这按我的想法工作,sample 的值将由.GlobalEnv 中的函数生成,对应于'mean' 或'sd',具体取决于行。

我得到的错误是:

 Error in mutate_impl(.data, dots) : 
    Evaluation error: invalid first argument. 

这肯定与非标准评估有关...... grrr。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    这里有几个问题。首先expand.grid 将字符值转换为因子。而get() 不喜欢使用因子(即get(factor("mean")) 会出错)。对 tidyverse 友好的版本是 tidyr::crossing()。 (您也可以将stringsAsFactors=FALSE 传递给expand.grid。)

    其次,mutate() 假定您调用的所有函数都是矢量化的,但像 get() 这样的函数没有矢量化,它们需要一次调用一个。一种更安全的方法是使用rowwise(),而不是在这里执行 group_by 来保证一次评估。

    最后,你真正的问题是你试图调用 get("sd") 但是当你这样做时,sd 也恰好是你的 data.frame 中的一列,它是变异的一部分。因此get() 会首先找到这个sd,而这个sd 只是一个数字,而不是一个函数。您需要告诉get() 明确地从全局环境中提取。试试

    tidyr::crossing(mu = 1:5, sd = c(1, 10), stat = c('mean', 'sd')) %>%
      rowwise() %>% 
      mutate(sample = get(stat, envir = globalenv())(rnorm(100, mu, sd)))
    

    【讨论】:

      【解决方案2】:

      三个问题(我看到的):(1)expand.grid 给你factors; (2) get 查找变量,因此使用"sd" 作为stat 与列名"sd" 混淆(这很难找到!); (3) 这确实是按行操作,分组没有足够的帮助。第一个可以通过选项轻松修复,第二个可以通过使用match.fun 而不是get 来修复,第三个可以通过dplyr::rowwise、purrr::pmap 或base R 的mapply 来缓解。

      这个辅助函数在调试过程中很有用,可以用来“清理”mutate 中的代码,但它不是必需的(除了这个演示之外)。内联“匿名”函数也可以工作。

      func <- function(f,m,s) get(f)(rnorm(100,mean=m,sd=s))
      

      几种实现方式:

      set.seed(0)
      expand.grid(mu = 1:5, sd = c(1, 10), stat = c('mean', 'sd'),
                  stringsAsFactors=FALSE)  %>%
        group_by(mu, sd, stat) %>%              # can also be `rowwise() %>%`
        mutate(
          sample0 = match.fun(stat)(rnorm(100, mu, sd)),
          sample1 = purrr::pmap_dbl(list(stat, mu, sd), ~ match.fun(..1)(rnorm(100, ..2, ..3))),
          sample2 = purrr::pmap_dbl(list(stat, mu, sd), func),
          sample3 = mapply(function(f,m,s) match.fun(f)(rnorm(100,m,s)), stat, mu, sd),
          sample4 = mapply(func, stat, mu, sd)
        ) %>%
        ungroup()
      # # A tibble: 20 x 8
      #       mu    sd stat  sample0 sample1 sample2 sample3 sample4
      #    <int> <dbl> <chr>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
      #  1     1     1 mean    1.02    1.03    0.896   1.08    0.855
      #  2     2     1 mean    1.95    2.07    2.05    1.90    1.92 
      #  3     3     1 mean    2.93    3.07    3.03    2.89    3.01 
      #  4     4     1 mean    4.01    3.94    4.23    4.05    3.96 
      #  5     5     1 mean    5.04    5.11    5.05    5.17    5.19 
      #  6     1    10 mean    1.67    1.21    1.30    2.08   -0.641
      #  7     2    10 mean    1.82    2.82    2.35    3.65    1.78 
      #  8     3    10 mean    1.45    3.10    3.15    4.28    2.58 
      #  9     4    10 mean    3.49    6.33    5.11    2.84    3.41 
      # 10     5    10 mean    5.33    4.85    4.07    5.58    6.66 
      # 11     1     1 sd      0.965   1.04    0.993   0.942   1.08 
      # 12     2     1 sd      0.974   0.967   0.981   0.984   1.15 
      # 13     3     1 sd      1.12    0.902   1.06    0.977   1.02 
      # 14     4     1 sd      0.946   0.928   0.960   1.01    0.992
      # 15     5     1 sd      1.06    1.01    0.911   1.11    1.00 
      # 16     1    10 sd      9.46    8.95   10.0     8.91    9.60 
      # 17     2    10 sd      9.51    9.11   11.5     9.85   10.6  
      # 18     3    10 sd      9.77    9.96   11.0     9.09   10.7  
      # 19     4    10 sd     10.5     9.84   10.1    10.6     8.89 
      # 20     5    10 sd     11.2     8.82   10.4     9.06    9.64 
      

      sample0 恰好可以工作,因为您已将其按行分组。如果在某一时刻任何一个分组有两个或多个值,这将失败。

      对于sample1 到sample4,您可以删除group_by,它同样可以正常工作(尽管sample0 证明它失败了,所以也删除它)。删除分组后,您将不会得到与上述相同的结果,因为熵的消耗方式不同。

      【讨论】:

        猜你喜欢
        • 2020-11-22
        • 1970-01-01
        • 1970-01-01
        • 2018-04-02
        • 2014-03-25
        • 1970-01-01
        • 2018-05-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多