我想将函数或至少它们的名称存储在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。
答案 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::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
展示了它的失败,所以也删除它)。删除分组后,您将无法获得与上述相同的结果,因为熵的消耗方式不同。