如何有效地生成模拟值的数据框?

时间:2014-04-23 22:54:27

标签: r simulation

我正在尝试根据现有的分布参数生成模拟值的数据框。我的主数据框包含每个观察的均值和标准差,如下所示:

example.data <- data.frame(country=c("a", "b", "c"), 
                           score_mean=c(0.5, 0.4, 0.6), 
                           score_sd=c(0.1, 0.1, 0.2))

#   country score_mean score_sd
# 1       a        0.5      0.1
# 2       b        0.4      0.1
# 3       c        0.6      0.2

我可以使用sapply()和自定义函数来使用score_mean和score_sd参数从正态分布中随机抽取:

score.simulate <- function(score.mean, score.sd) {
  return(mean(rnorm(100, mean=score.mean, sd=score.sd)))
}

simulated.scores <- sapply(example.data$score_mean, 
                       FUN=score.simulate, 
                       score.sd=example.data$score_sd)

# [1] 0.4936432 0.3753853 0.6267956

这将生成一轮(或列)模拟值。但是,我想生成很多列(如100或1,000)。我发现这样做的唯一方法是将sapply()函数包含在lapply()内的泛型函数中,然后将结果列表转换为ldply()plyr的数据框}}:

results.list <- lapply(1:5, FUN=function(x) sapply(example.data$score_mean, FUN=score.simulate, score.sd=example.data$score_sd))

library(plyr)
simulated.scores <- as.data.frame(t(ldply(results.list)))

#           V1        V2        V3        V4        V5
# V1 0.5047807 0.4902808 0.4857900 0.5008957 0.4993375
# V2 0.3996402 0.4128029 0.3875678 0.4044486 0.3982045
# V3 0.6017469 0.6055446 0.6058766 0.5894703 0.5960403

这很有效,但是(1)它似乎真的很复杂,特别是as.data.frame(t(ldply(lapply(... FUN=function(x) sapply ...))))方法,(2)当使用大量迭代或更大的数据时它真的很慢 - 我的实际数据集有3,000行,并且运行1,000次迭代需要1-2分钟。

是否有更有效的方法来创建这样的模拟值数据框?

2 个答案:

答案 0 :(得分:2)

我能想到的最快捷方式是利用内置于rnorm的矢量化。 meansd参数都是矢量化的,但是您只能为绘制数提供一个整数。如果向meansd参数提供向量,则R将循环遍历它们,直到它完成所需的绘制次数。因此,只需将参数n设为rnorm,即mean向量的倍数。乘数将是data.frame每行的重复次数。在下面的函数中,这是n

我无法想到一个因素而不是单独使用base::rnorm

工作示例


#example data
df <- data.frame(country=c("a", "b", "c"), 
                           mean=c(1, 10, 100), 
                           sd=c(1, 2, 10))

#function which returns a matrix, and takes column vectors as arguments for mean and sd
normv <- function( n , mean , sd ){
    out <- rnorm( n*length(mean) , mean = mean , sd = sd )
    return( matrix( out , , ncol = n , byrow = FALSE ) )
    }

#reproducible result (note order of magnitude of rows and input sample data)
set.seed(1)
normv( 5 , df$mean , df$sd )
#           [,1]      [,2]       [,3]        [,4]        [,5]
#[1,]  0.3735462  2.595281   1.487429   0.6946116   0.3787594
#[2,] 10.3672866 10.659016  11.476649  13.0235623   5.5706002
#[3,] 91.6437139 91.795316 105.757814 103.8984324 111.2493092

答案 1 :(得分:2)

如果您记得rnorm(1,mean,sd)与rnorm(1)* sd + mean相同,这样可以非常快速地完成,因此使用您的数据框df,您可以生成类似于您的观察结果的模拟:

obs = nrow(df)
sim = 1000
mat = data.frame(matrix(rnorm(obs*sim), obs, sim) * df$sd + df$mean)

您可以使用rowMeans(mat)检查这是否具有所需的方法,并检查第1行的标准偏差为sd(mat [1,])。