如何用apply、lapply替代R语言中的for循环?
用apply/lapply替代Box-Muller方法的for循环
首先你的原函数存在两个问题:一是未初始化samp1和samp2向量,运行时会报错;二是函数没有返回生成的样本结果。下面给出几种用apply系列函数替代的写法,同时修正这些问题:
方法1:用lapply生成样本列表再整理
lapply会遍历每个索引执行样本生成逻辑,返回包含每组(X1,X2)的列表,最后将列表转成矩阵拆分出两个样本向量:
f_lapply <- function(n) { samples_list <- lapply(1:n, function(i) { U1 <- runif(1) U2 <- runif(1) X1 <- sqrt(-2*log(U1))*cos(2*pi*U2) X2 <- sqrt(-2*log(U1))*sin(2*pi*U2) c(X1, X2) }) samples_mat <- do.call(rbind, samples_list) list(samp1 = samples_mat[,1], samp2 = samples_mat[,2]) }
方法2:用apply基于矩阵处理
先一次性生成所有需要的均匀分布随机数,再用apply逐行计算对应的正态样本:
f_apply <- function(n) { # 一次性生成n组U1和U2,比循环里每次调用runif更高效 U_mat <- matrix(runif(2*n), ncol = 2) samples_mat <- apply(U_mat, 1, function(u) { U1 <- u[1] U2 <- u[2] X1 <- sqrt(-2*log(U1))*cos(2*pi*U2) X2 <- sqrt(-2*log(U1))*sin(2*pi*U2) c(X1, X2) }) # 转置矩阵让每行对应一组样本 samples_mat <- t(samples_mat) list(samp1 = samples_mat[,1], samp2 = samples_mat[,2]) }
额外建议:优先用向量化操作
其实在R里,最高效的写法是直接用向量运算,完全不需要循环或apply系列——因为R的向量运算底层由C实现,速度远快于循环类操作:
f_vectorized <- function(n) { U1 <- runif(n) U2 <- runif(n) sqrt_term <- sqrt(-2*log(U1)) samp1 <- sqrt_term * cos(2*pi*U2) samp2 <- sqrt_term * sin(2*pi*U2) list(samp1 = samp1, samp2 = samp2) }
以上三种写法都能生成符合要求的标准正态分布样本,其中向量化版本的性能最优。
内容的提问来源于stack exchange,提问作者user19825372
相关产品推荐
相关产品推荐

