目标
我想使用dplyr在参数网格上运行模拟。具体来说,我喜欢我可以在另一个程序中使用的功能
这是我的方法
require(dplyr)
run <- function(data, fun, fixed_parameters, ...) {
## ....
## argument checking
##
fixed_parameters <- as.environment(fixed_parameters)
grouped_out <- do_(rowwise(data), ~ do.call(fun, c(., fixed_parameters, ...)))
ungroup(grouped_out)
}
这很有效。例如,对于
growth <- function(n, r, K, b) {
# some dynamical simulation
# this is an obviously-inefficient way to do this ;)
n + r - exp(n) / K - b - rnorm(1, 0, 0.1)
}
growth_runner <- function(r, K, b, ic, ...) {
# a wrapper to run the simulation with some fixed values
n0 = ic$N0
T = ic$T
reps = ic$reps
data.frame(n_final = replicate(reps, {for(t in 1:T) {
n0 <- growth(n0, r, K, b)
};
n0})
)
}
我可以定义并运行
data <- expand.grid(b = seq(0.01, 0.5, length.out=10),
K = exp(seq(0.1, 5, length.out=10)),
r = seq(0.5, 3.5, length.out=10))
initial_data = list(N0=0.9, T=5, reps=20)
output <- run(data, growth_runner, initial_data)
问题
尽管这似乎有效,但我想知道是否有办法在没有do.call
的情况下做到这一点。 (部分原因是issues with do.call。)
我真的很感兴趣的方法是将行grouped_out <- do_(rowwise(data), ~ do.call(fun, c(., fixed_parameters, ...)))
替换为同样但没有do.call
的行。 修改:以某种方式避免使用上述链接中列出的do.call
的性能损失的方法也可以。
备注和参考
.values
可以取代do.call
答案 0 :(得分:5)
我发现遵循您的代码有点棘手,但我认为这是等效的。
首先,我定义了一个执行您感兴趣的计算的函数:
purrr::pmap_d()
然后我定义了您想要改变的数据,包括代表的“虚拟”变量:
pmap_d()
然后我可以将其提供给library(purrr)
data$output <- pmap_dbl(data[1:3], growth_t, n0 = 0.9, T = 5)
。 {{1}}执行“并行”映射 - 即它将列表(或数据帧)作为输入,并调用函数来改变每次迭代的所有命名参数。固定参数在函数名称后面提供。
{{1}}
这对我来说真的不是一个dplyr问题,因为它并不是真正的数据操作。
答案 1 :(得分:1)
以下内容避免使用do.call
,并以与OP相同的方式显示输出。
首先,使用您传入的矢量替换函数的参数 - 这是您使用apply传递的内容。
growth_runner <- function(data.in, ic, ...) {
# a wrapper to run the simulation with some fixed values
n0 = ic$N0
T = ic$T
reps = ic$reps
data.frame(n_final = replicate(reps, {for(t in 1:T) {
n0 <- growth(n0, data.in[3], data.in[2], data.in[1])
};
n0})
)
}
设置要搜索的网格,就像之前一样。
data <- expand.grid(b = seq(0.01, 0.5, length.out=10),
K = exp(seq(0.1, 5, length.out=10)),
r = seq(0.5, 3.5, length.out=10))
initial_data = list(N0=0.9, T=5, reps=20)
使用apply浏览网格,然后附加结果
output.mid = apply(data, 1, ic=initial_data, FUN=growth_runner)
output <- data.frame('n_final'=unlist(output.mid))
您可以在不调用do.call
或任何外部库的情况下获得输出。
> dim(output)
[1] 20000 1
> head(output)
n_final
1 -0.6375070
2 -0.7617193
3 -0.3266347
4 -0.7921655
5 -0.5874983
6 -0.4083613
答案 2 :(得分:0)
您可以使用以下内容替换do.call
行(感谢 @shorpy 指出purrr:invoke_rows()
):
grouped_out <- purrr::invoke_rows(fun, dplyr::rowwise(data), fixed_parameters)
没有任何其他更改,这将为数据框提供一列data.frames,如
Source: local data frame [1,000 x 4]
b K r .out
(dbl) (dbl) (dbl) (chr)
1 0.01000000 1.105171 0.5 <data.frame [20,1]>
2 0.06444444 1.105171 0.5 <data.frame [20,1]>
3 0.11888889 1.105171 0.5 <data.frame [20,1]>
要恢复更接近原始行为的内容,请将run
的最后一行替换为
dplyr::ungroup(tidyr::unnest(grouped_out, .out))
给出了
Source: local data frame [20,000 x 4]
b K r n_final
(dbl) (dbl) (dbl) (dbl)
1 0.01 1.105171 0.5 -0.6745470
2 0.01 1.105171 0.5 -0.7500365
3 0.01 1.105171 0.5 -0.6568312
不需要对代码进行其他更改:)