蒙特卡洛验证均匀分布样本和的中心极限定理:样本量变化无显著差异疑问
问题:蒙特卡洛模拟验证中心极限定理的疑惑
我尝试用蒙特卡洛模拟展示:当样本维度增大时,均匀分布样本的和趋近于正态分布。具体来说,设$X \sim U[2,3]$,$X_1,…,X_n$是来自X的独立同分布样本,$S = \sum_{1}^{n}(X_i)$,我希望通过蒙特卡洛模拟验证当n足够大时,S的分布近似服从正态分布(符合中心极限定理预测)。我关注的是$X_i$的和,而非均值的一般情况,想要展示随样本量n增加,S的分布更趋近正态。
但我遇到两个问题:
- 增减蒙特卡洛次数会明显影响正态性的视觉表现
- 样本量从10增至100时,分布的正态性没有显著差异,甚至n=10时已经能看到近似正态的分布
以下是我的最小可复现代码:
# 创建10000个服从U[2,3]的均匀分布样本 data <- runif(n=10000, min=2, max=3) hist(data, col='steelblue', main='Histogram from the Uniform') # 进行1000次蒙特卡洛模拟,每次取10个样本求和 sample10 <- c() n = 1000 for (i in 1:n){ sample10[i] = sum(sample(data, 10, replace=TRUE)) } hist(sample10, col ='steelblue', main='Sample size = 10', prob=TRUE) qqnorm(sample10); qqline(sample10) # 增大单次模拟的样本量到100 sample100 <- c() n = 1000 for (i in 1:n){ sample100[i] = sum(sample(data, 100, replace=TRUE)) } hist(sample100, col ='steelblue', main='Sample size = 100', prob=TRUE) qqnorm(sample100); qqline(sample100)
请问我哪里出错了?
问题原因与改进方案
1. 蒙特卡洛次数影响表现的核心原因
你当前设置的蒙特卡洛次数(1000次)过少,导致模拟得到的sample10和sample100本身属于小样本,分布的随机性极强,所以增减次数会让直方图、QQ图的表现出现大幅波动。要稳定展示真实的分布形态,需要大幅提高蒙特卡洛次数(比如增加到10000次甚至更多),让模拟得到的和的样本量足够大,才能抵消随机波动,呈现稳定的分布特征。
2. n=10时已近似正态的原因
均匀分布是对称分布,中心极限定理对对称分布的收敛速度极快——对于均匀分布,n=10时和的分布已经非常接近正态分布,因此n从10提升到100时,正态性的提升在视觉上很难分辨。如果想要更直观看到收敛过程,可以:
- 选择非对称的原始分布(比如指数分布),这类分布的收敛速度更慢,n从10到100的正态性差异会更明显
- 对和进行标准化处理($Z = \frac{S - n\mu}{\sqrt{n\sigma^2}}$),把不同n的和转换到同一标准正态尺度下,更容易对比收敛程度:
对于$X \sim U[2,3]$,$\mu = 2.5$,$\sigma^2 = \frac{(3-2)^2}{12} = \frac{1}{12}$,标准化后的统计量会随n增大更贴近标准正态分布,QQ图的拟合效果差异会更清晰
3. 代码优化点
- 无需预先生成大样本
data再反复抽样,直接在模拟中用runif生成样本求和,效率更高且避免重复抽样的潜在偏差 - 用
replicate替代循环,代码更简洁高效 - 添加理论正态分布曲线作为参考,直观对比拟合程度
改进后的示例代码:
# 定义均匀分布的参数 mu <- 2.5 sigma_sq <- 1/12 mc_times <- 10000 # 提高蒙特卡洛次数至10000 # n=10的模拟与可视化 n10 <- 10 sum_n10 <- replicate(mc_times, sum(runif(n10, 2, 3))) z_n10 <- (sum_n10 - n10*mu)/sqrt(n10*sigma_sq) par(mfrow=c(2,2)) hist(sum_n10, col='steelblue', main='n=10: 和的分布', prob=TRUE) curve(dnorm(x, mean=n10*mu, sd=sqrt(n10*sigma_sq)), add=TRUE, col='red', lwd=2) qqnorm(z_n10, main='n=10: 标准化QQ图'); qqline(z_n10, col='red') # n=100的模拟与可视化 n100 <- 100 sum_n100 <- replicate(mc_times, sum(runif(n100, 2, 3))) z_n100 <- (sum_n100 - n100*mu)/sqrt(n100*sigma_sq) hist(sum_n100, col='steelblue', main='n=100: 和的分布', prob=TRUE) curve(dnorm(x, mean=n100*mu, sd=sqrt(n100*sigma_sq)), add=TRUE, col='red', lwd=2) qqnorm(z_n100, main='n=100: 标准化QQ图'); qqline(z_n100, col='red') par(mfrow=c(1,1))
内容的提问来源于stack exchange,提问作者RobertCGA
相关产品推荐
相关产品推荐

