别再死记硬背了!用Python模拟抽样,5分钟搞懂样本均值与方差的无偏性

张开发
2026/4/20 19:39:30 15 分钟阅读

分享文章

别再死记硬背了!用Python模拟抽样,5分钟搞懂样本均值与方差的无偏性
用Python模拟抽样5分钟可视化理解样本统计量的无偏性第一次接触统计学中的无偏估计概念时那个神秘的n-1分母让我百思不得其解。为什么样本方差的计算要用n-1而不是n直到我用Python模拟了上万次抽样过程看到样本统计量如何在总体参数周围波动一切才变得直观起来。本文将带你用不到50行代码通过实验理解这个统计学中的重要概念。1. 准备工作构建正态总体我们先从创建一个已知参数的虚拟总体开始。假设某城市成年男性的身高服从正态分布N(175, 15²)单位是厘米。用NumPy生成这个总体非常简单import numpy as np import matplotlib.pyplot as plt # 设置随机种子保证结果可复现 np.random.seed(42) # 生成一个足够大的总体模拟真实世界 population np.random.normal(loc175, scale15, size1000000)这里我们生成了100万个数据点足以代表理论上的无限总体。让我们看看这个总体的关键参数print(f总体均值: {np.mean(population):.2f}) print(f总体方差: {np.var(population):.2f})输出结果应该接近总体均值: 175.01 总体方差: 225.21注意总体方差σ²的计算使用n作为分母这是总体参数的定义方式与样本统计量不同。2. 抽样实验设计现在我们要从这个总体中反复抽取样本观察样本统计量的行为。关键步骤包括设置样本容量n比如n30从总体中随机抽取一个样本计算样本均值和样本方差重复上述过程数千次分析这些统计量的分布特征def calculate_sample_stats(data, sample_size): 从总体中抽取一个样本并计算统计量 sample np.random.choice(data, sizesample_size, replaceTrue) sample_mean np.mean(sample) # 注意这里使用ddof1计算样本方差 sample_var np.var(sample, ddof1) return sample_mean, sample_var3. 模拟抽样过程让我们进行5000次抽样实验每次抽取30个样本点sample_size 30 n_experiments 5000 means [] variances [] for _ in range(n_experiments): m, v calculate_sample_stats(population, sample_size) means.append(m) variances.append(v)现在我们可以分析这些统计量的分布了。先看样本均值plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) plt.hist(means, bins50, densityTrue, alpha0.7) plt.axvline(np.mean(means), colorr, linestyle--, label样本均值均值) plt.axvline(175, colorg, linestyle-, label总体均值) plt.title(样本均值的分布) plt.legend()4. 无偏性的可视化证明关键的部分来了——让我们比较两种方差计算方式的平均值使用n作为分母有偏样本方差使用n-1作为分母无偏样本方差# 计算两种方差的平均值 biased_var_avg np.mean([np.var(np.random.choice(population, sample_size)) for _ in range(n_experiments)]) unbiased_var_avg np.mean(variances) print(f有偏样本方差的平均值: {biased_var_avg:.2f}) print(f无偏样本方差的平均值: {unbiased_var_avg:.2f}) print(f总体方差: {np.var(population):.2f})典型输出结果有偏样本方差的平均值: 217.73 无偏样本方差的平均值: 225.08 总体方差: 225.21这个实验清晰地展示了为什么需要n-1校正——使用n作为分母会系统性地低估总体方差而n-1校正后的估计量平均值几乎等于真实总体方差。5. 数学原理与直观解释为什么样本方差需要n-1校正关键在于样本均值本身也是从数据中估计出来的它已经吸收了一部分变异。具体来说当我们用样本均值代替总体均值时样本点会倾向于比它们距离总体均值更靠近样本均值这导致直接用样本均值计算的离差平方和会系统性地偏小n-1校正实际上是在补偿这种自由度的损失用Python可以直观展示这种偏差# 生成一个样本 sample np.random.choice(population, size30) sample_mean np.mean(sample) # 计算两种离差 deviations_from_pop sample - 175 deviations_from_sample sample - sample_mean # 绘制比较图 plt.figure(figsize(10, 6)) plt.scatter(sample, deviations_from_pop**2, label与总体均值的离差平方) plt.scatter(sample, deviations_from_sample**2, label与样本均值的离差平方) plt.axhline(0, colorblack, linestyle--) plt.xlabel(样本值) plt.ylabel(离差平方) plt.legend() plt.title(离差平方的比较)6. 进阶探索不同样本量的影响样本大小如何影响估计的准确性让我们通过实验来观察sample_sizes [5, 10, 20, 30, 50, 100] bias_ratios [] for n in sample_sizes: biased np.mean([np.var(np.random.choice(population, n)) for _ in range(1000)]) unbiased np.mean([np.var(np.random.choice(population, n), ddof1) for _ in range(1000)]) bias_ratio biased / np.var(population) bias_ratios.append(bias_ratio) plt.plot(sample_sizes, bias_ratios, markero) plt.axhline(1 - 1/max(sample_sizes), colorr, linestyle--) plt.xlabel(样本量) plt.ylabel(有偏方差/总体方差) plt.title(样本量对有偏方差的影响)这个图表展示了有偏估计的系统性偏差如何随着样本量增大而减小——当n趋近于无穷大时n和n-1的差别变得微不足道。7. 实际应用建议在数据分析实践中关于样本统计量的使用有几个实用建议样本方差计算使用np.var(data, ddof1)或pd.Series.var()默认使用n-1校正只有在确定需要总体方差时才使用ddof0小样本情况当n30时考虑使用t分布而不是正态分布进行推断特别注意极端值对估计的影响可视化验证绘制统计量的抽样分布比较不同估计方法的偏差# 实用代码示例完整的抽样分布分析函数 def analyze_estimator(population, sample_size, n_experiments5000): means [] var_biased [] var_unbiased [] for _ in range(n_experiments): sample np.random.choice(population, sizesample_size) means.append(np.mean(sample)) var_biased.append(np.var(sample)) var_unbiased.append(np.var(sample, ddof1)) fig, ax plt.subplots(1, 3, figsize(18, 5)) # 绘制均值分布 ax[0].hist(means, bins50, alpha0.7) ax[0].axvline(np.mean(population), colorr) ax[0].set_title(样本均值分布) # 绘制有偏方差分布 ax[1].hist(var_biased, bins50, alpha0.7) ax[1].axvline(np.mean(var_biased), colorr, labelf平均{np.mean(var_biased):.1f}) ax[1].axvline(np.var(population), colorg, labelf总体方差{np.var(population):.1f}) ax[1].set_title(有偏样本方差分布) ax[1].legend() # 绘制无偏方差分布 ax[2].hist(var_unbiased, bins50, alpha0.7) ax[2].axvline(np.mean(var_unbiased), colorr, labelf平均{np.mean(var_unbiased):.1f}) ax[2].axvline(np.var(population), colorg, labelf总体方差{np.var(population):.1f}) ax[2].set_title(无偏样本方差分布) ax[2].legend() plt.tight_layout() return fig在数据分析项目中我经常使用这种模拟方法来验证理论结果。有一次在A/B测试中当样本量很小时这种对抽样变异性的直观理解帮助我避免了过早下结论的错误。统计学概念通过编程实验变得鲜活起来不再是枯燥的公式推导。

更多文章