我正在尝试根据现有的分布参数生成模拟值的数据框。我的主数据框包含每个观察的均值和标准差,如下所示:
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分钟。
是否有更有效的方法来创建这样的模拟值数据框?
答案 0 :(得分:2)
我能想到的最快捷方式是利用内置于rnorm
的矢量化。 mean
和sd
参数都是矢量化的,但是您只能为绘制数提供一个整数。如果向mean
和sd
参数提供向量,则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,])。