2016-03-31 37 views
15

目标使用标准的评估和DO_无需do.call

我想用dplyr上的参数电网运行模拟运行的参数网格模拟。具体来说,我想我可以在

  • 被传递一个data.frame
  • 的每一行另一程序使用函数计算采用每列作为参数
  • 也有些仿真通过一些额外的数据(例如,初始条件)

这里是我的方法

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。)

我真的很感兴趣的方法是用一些做同样的事情,但没有do.call的东西来代替行grouped_out <- do_(rowwise(data), ~ do.call(fun, c(., fixed_parameters, ...)))编辑:某种方式可以避免使用上述链接中列出的do.call的性能损失也会奏效。

注释和参考文献

+1

FWIW听起来很像'plyr :: mdply'。不幸的是,这两个软件包相当不兼容。 – baptiste

+0

dang,我从来没有发现'plyr'的那部分!感谢您的指针 – jaimedash

+1

我想你可能需要'purrr :: invoke_rows',这是'mdply'的现代等价物。 http://rpackages.ianhowson.com/cran/purrr/man/by_row.html – Shorpy

回答

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) 

使用申请办理网格,然后附加结果

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 
+0

对不起,您缺少问题的关键上下文:使用dplyr。 (问题的第一行)。 5/19的编辑说明了这一点。尽管这个代码很有用,但它以一种不太通用的方式完成相同的整体任务。谢谢! – jaimedash

+0

另请注意,只要你有非数字参数,apply()'就会失败 – hadley

0

您可以替换do.call在符合以下(感谢@shorpy您指出purrr:invoke_rows()):

grouped_out <- purrr::invoke_rows(fun, dplyr::rowwise(data), fixed_parameters) 

没有任何其他的变化,这会给一个数据帧数据帧的列,如

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 

并无其他变动的代码需要:)

+0

我不会依赖它,因为'invoke_rows()'对于这个世界可能不会很长 – hadley

+1

感谢你的支持!我会研究'pmap'(如你的答案),而不是 – jaimedash

5

我发现它有点棘手跟随你的代码,但我认为这相当于。

首先我定义,它的计算你感兴趣的函数:

growth_t <- function(n0, r, K, b, T) { 
    n <- n0 

    for (t in 1:T) { 
    n <- n + r - exp(n)/K - b - rnorm(1, 0, 0.1) 
    } 
    n 
} 

然后我定义要改变数据,包括代表一个“虚拟”变量:

data <- expand.grid(
    b = seq(0.01, 0.5, length.out = 5), 
    K = exp(seq(0.1, 5, length.out = 5)), 
    r = seq(0.5, 3.5, length.out = 5), 
    rep = 1:20 
) 

然后我可以喂它到purrr::pmap_d()pmap_d()做了一个“并行”映射 - 即它将一个列表(或数据帧)作为输入,并调用函数来改变每次迭代的所有命名参数。固定参数在函数名称后面提供。

library(purrr) 
data$output <- pmap_dbl(data[1:3], growth_t, n0 = 0.9, T = 5) 

这真的不觉得像我的dplyr问题,因为它不是真正的数据处理。

+0

谢谢!公平点replyr,它开始于'dplyr :: do'。但是考虑到整理数据的扩展工具,特别是你用'purrr'(例如http://stackoverflow.com/q/35505187/4598520)标题的方向,我同意它可能更好地描述为整洁的数据问题 – jaimedash