查找数据突变的功能

时间:2018-08-30 21:23:03

标签: r dplyr

我想将函数或至少它们的名称存储在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。

2 个答案:

答案 0 :(得分:4)

这里有几个问题。首先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)))

答案 1 :(得分:1)

三个问题(我看到了):(1)expand.grid给您factor s; (2)get查找变量,因此将"sd"用作stat与列名"sd"混淆(很难找到!); (3)这确实是逐行操作,分组还不够用。第一个可以通过选项轻松修复,第二个可以通过使用match.fun而不是get进行修复,而第三个可以通过dplyr::rowwisepurrr::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之所以起作用,是因为您已将其分组为按行排列。如果某个分组中的某个分组具有两个或多个值,则这将失败

对于sample1sample4,您可以删除group_by,它也同样有效(尽管sample0展示了它的失败,所以也删除它)。删除分组后,您将无法获得与上述相同的结果,因为熵的消耗方式不同。