创建一个函数来表征重复模拟

Creating a function to characterise repeated simulations

我想创建一个函数来帮助表征某些模拟的结果。出于此 post 的目的,让模拟函数为:

example_sim <- function(time=100, npops=5){
  result <- data.frame(matrix(NA, nrow = time, ncol = npops))
  colnames(result) <- LETTERS[1:npops]
  for(i in 1:npops){
    sim <- sample.int(time, time)
    result[,i] <- sim
    result[,i] <- result[,i]*i
  }
  return(result)
}

这将根据人口数量 (npops) 和模拟时间创建一个长度和宽度不同的数据框。

我想创建一个函数,它使用此类模拟的输出并表征 n 次模拟 (nsim) 中每个总体的均值和方差。

到目前为止,我已经设法使用以下代码使其适用于两个人群:

library("matrixStats")
library("reshape2")

ensembles <- function(nsims=10, time = 100, npops = 2){
  result_N.A <- data.frame(matrix(NA, nrow = time, ncol = nsims))
  result_N.B <- data.frame(matrix(NA, nrow = time, ncol = nsims))
  for( i in 1:(nsims)){
    simulation_with_2pops <- example_sim(time=100,npops=2)
    result_N.A[,i] <- simulation_with_2pops[,1]
    result_N.B[,i] <- simulation_with_2pops[,2]
  }
  output <- simulation_with_2pops
  for( j in 1:params$ntime){
    output$meanA[j] <- rowMeans(result_N.A[j,])
  }
  for( j in 1:params$ntime){
    output$meanB[j] <- rowMeans(result_N.B[j,])
  }
  for( j in 1:params$ntime){
    output$varA[j] <- rowVars(as.matrix(result_N.A[j,]))
  }
  for( j in 1:params$ntime){
    output$varB[j] <- rowVars(as.matrix(result_N.B[j,]))
  }
  return(output)
} 
ensembles_output<- ensembles(nsims = 10)
ensembles_output

要为任意数量的人群完全实现该功能,我需要创建另一个 for 循环,我在其中创建和更新 result_N.A 对象。 (大概叫做 result[i] 之类的东西。) 我也考虑过创建一个 3 维对象(时间、npops、nsims)并取其一部分来计算均值和方差,但我还没有取得太大的成功。 我没有为这条路线结婚,对其他建议持开放态度。

最终我想创建一个代码,其中还通过突出显示参数中的两个总体来计算协方差和相关性。 (例如人口 A 和人口 E)。如果您对实施有任何想法,我将不胜感激。

感谢您考虑这个问题。

我认为在这种情况下使用多维数组是一个非常好的主意。

首先,您可以使用 mapply() 更便宜地获得 example_sim() 的模拟。这里有一个 time=10npops=3 的例子。使用相同的 set.seed(42) 和参数并自行检查。

我在这里使用的参数要小得多,这样您就可以轻松地在脑海中检查结果。

set.seed(42)
sim <- replicate(nsims, mapply(\(time, i) sample.int(time, time)*i, 10, 1:3))

sim
# , , 1
# 
#       [,1] [,2] [,3]
#  [1,]    1   16   27
#  [2,]    5   14   30
#  [3,]   10    8    9
#  [4,]    8    2   12
#  [5,]    2   10   15
#  [6,]    4   20   18
#  [7,]    6    4    3
#  [8,]    9   12    6
#  [9,]    7   18   24
# [10,]    3    6   21
# 
# , , 2
# 
#       [,1] [,2] [,3]
#  [1,]    3   10   18
#  [2,]    1    8    6
#  [3,]    2    4   12
#  [4,]    6   16    9
#  [5,]   10    6   30
#  [6,]    8    2   15
#  [7,]    4   20   27
#  [8,]    5   14   21
#  [9,]    7   12   24
# [10,]    9   18    3
# 
# , , 3
# 
#       [,1] [,2] [,3]
#  [1,]   10    8   18
#  [2,]    8   18    6
#  [3,]    5    6   27
#  [4,]    1   16    3
#  [5,]    7   10   24
#  [6,]    4   12   15
#  [7,]    6   20   30
#  [8,]    2    4    9
#  [9,]    9    2   12
# [10,]    3   14   21

接下来,我相信您想要收集 row-wise 每个人口列 A、B、C... 的统计数据。这里你基本上想要apply(., MARGINS=1:2, FUN)。就平均而言,存在 rowMeans(., dims=2L),速度更快。

rowMeans(sim, dims=2L)
#           [,1]      [,2] [,3]
#  [1,] 4.666667 11.333333   21
#  [2,] 4.666667 13.333333   14
#  [3,] 5.666667  6.000000   16
#  [4,] 5.000000 11.333333    8
#  [5,] 6.333333  8.666667   23
#  [6,] 5.333333 11.333333   16
#  [7,] 5.333333 14.666667   20
#  [8,] 5.333333 10.000000   12
#  [9,] 7.666667 10.666667   20
# [10,] 5.000000 12.666667   15

apply(sim, 1:2, var)
#            [,1]      [,2] [,3]
#  [1,] 22.333333 17.333333   27
#  [2,] 12.333333 25.333333  192
#  [3,] 16.333333  4.000000   93
#  [4,] 13.000000 65.333333   21
#  [5,] 16.333333  5.333333   57
#  [6,]  5.333333 81.333333    3
#  [7,]  1.333333 85.333333  219
#  [8,] 12.333333 28.000000   63
#  [9,]  1.333333 65.333333   48
# [10,] 12.000000 37.333333  108

不过我不确定为什么要使用 simulation_with_2pops 作为最终输出,因为它是 for (i in 1:nsims) 循环的最后一次迭代的结果。无论如何,希望这对你有进一步的帮助。

注意:R >= 4.1 使用。