正态分布是统计学中最基础也最重要的概率分布之一。无论是金融领域的风险评估、工业生产的质量控制,还是医学研究的临床试验设计,正态分布都扮演着关键角色。对于数据科学初学者和统计学爱好者来说,理解正态分布的各种统计定理不仅有助于掌握统计推断的基本原理,更能为后续的机器学习建模打下坚实基础。
本文将完全从编程实践的角度出发,使用Python生态中的NumPy和SciPy两大科学计算库,通过代码实现来验证正态分布的9个核心统计定理。不同于传统的数学推导,我们会用计算机模拟和数值计算的方式,让抽象的统计定理变得直观可见。所有代码都经过精心设计,可以直接复制到Jupyter Notebook中运行。
在开始验证统计定理之前,我们需要搭建好Python环境并生成符合正态分布的随机数据。这里推荐使用Anaconda发行版,它已经集成了我们所需的所有科学计算包。
首先导入必要的库:
python复制import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
plt.style.use('seaborn') # 设置美观的绘图样式
接下来,我们定义一个函数来生成正态分布样本。这个函数将返回样本数据以及各种统计量:
python复制def generate_normal_samples(mu=0, sigma=1, n=30, num_samples=1000):
"""
生成正态分布样本
参数:
mu: 均值
sigma: 标准差
n: 每个样本的大小
num_samples: 生成的样本数量
返回:
样本数据、样本均值数组、样本方差数组
"""
samples = np.random.normal(loc=mu, scale=sigma, size=(num_samples, n))
sample_means = np.mean(samples, axis=1)
sample_vars = np.var(samples, axis=1, ddof=1) # 使用n-1作为分母的无偏估计
return samples, sample_means, sample_vars
提示:在实际应用中,样本量n通常不小于30才能满足中心极限定理的要求。我们设置默认样本量为30,同时生成1000个这样的样本以提高验证的可靠性。
定理内容:设总体X服从正态分布N(μ,σ²),则样本均值X̄~N(μ,σ²/n)
我们用代码来验证这个定理:
python复制# 参数设置
mu, sigma = 5, 2
n = 30
num_samples = 1000
# 生成样本
_, sample_means, _ = generate_normal_samples(mu, sigma, n, num_samples)
# 绘制样本均值的分布
plt.figure(figsize=(10, 6))
plt.hist(sample_means, bins=30, density=True, alpha=0.6, label='样本均值分布')
# 绘制理论正态分布曲线
x = np.linspace(mu - 3*sigma/np.sqrt(n), mu + 3*sigma/np.sqrt(n), 100)
plt.plot(x, stats.norm.pdf(x, mu, sigma/np.sqrt(n)),
'r-', lw=2, label=f'N({mu},{sigma**2/n:.2f})')
plt.title('样本均值的分布验证(定理1)')
plt.xlabel('样本均值')
plt.ylabel('概率密度')
plt.legend()
plt.show()
运行这段代码,你会看到样本均值的分布与理论预测的正态曲线完美吻合。这直观地验证了样本均值确实服从N(μ,σ²/n)分布。
定理内容:u = (X̄-μ)/(σ/√n) ~ N(0,1)
这个定理是构建置信区间的基础。验证代码如下:
python复制# 计算标准化样本均值
standardized_means = (sample_means - mu) / (sigma / np.sqrt(n))
# 绘制分布
plt.figure(figsize=(10, 6))
plt.hist(standardized_means, bins=30, density=True, alpha=0.6, label='标准化样本均值')
# 绘制标准正态分布曲线
x = np.linspace(-4, 4, 100)
plt.plot(x, stats.norm.pdf(x, 0, 1), 'r-', lw=2, label='N(0,1)')
plt.title('标准化样本均值的分布验证(定理2)')
plt.xlabel('标准化样本均值')
plt.ylabel('概率密度')
plt.legend()
plt.show()
# 使用K-S检验验证分布
ks_stat, p_value = stats.kstest(standardized_means, 'norm')
print(f'K-S检验统计量: {ks_stat:.4f}, p值: {p_value:.4f}')
如果p值大于0.05,我们无法拒绝标准化样本均值服从标准正态分布的假设,从而验证了定理2。
定理3:χ² = (1/σ²)Σ(Xi-μ)² ~ χ²(n)
定理4:(n-1)S²/σ² ~ χ²(n-1),且X̄与S²独立
定理5:t = (X̄-μ)/(S/√n) ~ t(n-1)
这三个定理涉及χ²分布和t分布,是t检验的基础。验证代码如下:
python复制# 生成新的样本集
samples, sample_means, sample_vars = generate_normal_samples(mu, sigma, n, num_samples)
# 定理3验证
chi2_stats_theorem3 = np.sum((samples - mu)**2, axis=1) / sigma**2
# 定理4验证
chi2_stats_theorem4 = (n - 1) * sample_vars / sigma**2
# 定理5验证
t_stats = (sample_means - mu) / np.sqrt(sample_vars / n)
# 绘制三个统计量的分布
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 定理3
x = np.linspace(0, 80, 100)
axes[0].hist(chi2_stats_theorem3, bins=30, density=True, alpha=0.6)
axes[0].plot(x, stats.chi2.pdf(x, df=n), 'r-', lw=2)
axes[0].set_title('定理3验证: χ² = (1/σ²)Σ(Xi-μ)²')
# 定理4
x = np.linspace(0, 60, 100)
axes[1].hist(chi2_stats_theorem4, bins=30, density=True, alpha=0.6)
axes[1].plot(x, stats.chi2.pdf(x, df=n-1), 'r-', lw=2)
axes[1].set_title('定理4验证: (n-1)S²/σ²')
# 定理5
x = np.linspace(-4, 4, 100)
axes[2].hist(t_stats, bins=30, density=True, alpha=0.6)
axes[2].plot(x, stats.t.pdf(x, df=n-1), 'r-', lw=2)
axes[2].set_title('定理5验证: t = (X̄-μ)/(S/√n)')
plt.tight_layout()
plt.show()
这三个图表清晰地展示了统计量的实际分布与理论预测的χ²分布和t分布的一致性。
定理6:当σx²=σy²=σ²时,U = [(X̄-Ȳ)-(μx-μy)]/√(σ²/nx + σ²/ny) ~ N(0,1)
定理7:T = [(X̄-Ȳ)-(μx-μy)]/[Sw√(1/nx + 1/ny)] ~ t(nx+ny-2)
这两个定理是两样本t检验的基础。验证代码如下:
python复制# 设置参数
mu_x, sigma_x = 5, 2
mu_y, sigma_y = 5, 2 # 先假设均值相同,方差相同
n_x, n_y = 30, 40
num_samples = 1000
# 生成两个总体的样本
samples_x = np.random.normal(loc=mu_x, scale=sigma_x, size=(num_samples, n_x))
samples_y = np.random.normal(loc=mu_y, scale=sigma_y, size=(num_samples, n_y))
# 计算样本统计量
means_x = np.mean(samples_x, axis=1)
means_y = np.mean(samples_y, axis=1)
vars_x = np.var(samples_x, axis=1, ddof=1)
vars_y = np.var(samples_y, axis=1, ddof=1)
# 定理6验证
sigma_pooled = sigma_x # 因为sigma_x = sigma_y
U_stats = ((means_x - means_y) - (mu_x - mu_y)) / np.sqrt(sigma_pooled**2/n_x + sigma_pooled**2/n_y)
# 定理7验证
S_w = np.sqrt(((n_x - 1)*vars_x + (n_y - 1)*vars_y) / (n_x + n_y - 2))
T_stats = ((means_x - means_y) - (mu_x - mu_y)) / (S_w * np.sqrt(1/n_x + 1/n_y))
# 绘制分布
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 定理6
x = np.linspace(-4, 4, 100)
axes[0].hist(U_stats, bins=30, density=True, alpha=0.6)
axes[0].plot(x, stats.norm.pdf(x, 0, 1), 'r-', lw=2)
axes[0].set_title('定理6验证: U统计量')
# 定理7
x = np.linspace(-4, 4, 100)
axes[1].hist(T_stats, bins=30, density=True, alpha=0.6)
axes[1].plot(x, stats.t.pdf(x, df=n_x+n_y-2), 'r-', lw=2)
axes[1].set_title('定理7验证: T统计量')
plt.tight_layout()
plt.show()
定理8:F = [Σ(Xi-μx)²/(nxσx²)] / [Σ(Yi-μy)²/(nyσy²)] ~ F(nx,ny)
定理9:F = (Sx²/σx²)/(Sy²/σy²) ~ F(nx-1,ny-1)
这两个定理是方差分析(ANOVA)的基础。验证代码如下:
python复制# 设置参数(这次让两个总体的方差不同)
sigma_x, sigma_y = 2, 3
n_x, n_y = 30, 40
# 生成样本
samples_x = np.random.normal(loc=mu_x, scale=sigma_x, size=(num_samples, n_x))
samples_y = np.random.normal(loc=mu_y, scale=sigma_y, size=(num_samples, n_y))
# 计算统计量
# 定理8
F_stats_theorem8 = (np.sum((samples_x - mu_x)**2, axis=1)/(n_x*sigma_x**2)) / \
(np.sum((samples_y - mu_y)**2, axis=1)/(n_y*sigma_y**2))
# 定理9
vars_x = np.var(samples_x, axis=1, ddof=1)
vars_y = np.var(samples_y, axis=1, ddof=1)
F_stats_theorem9 = (vars_x/sigma_x**2) / (vars_y/sigma_y**2)
# 绘制分布
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 定理8
x = np.linspace(0, 5, 100)
axes[0].hist(F_stats_theorem8, bins=50, density=True, alpha=0.6, range=(0, 5))
axes[0].plot(x, stats.f.pdf(x, dfn=n_x, dfd=n_y), 'r-', lw=2)
axes[0].set_title('定理8验证: F统计量')
# 定理9
x = np.linspace(0, 5, 100)
axes[1].hist(F_stats_theorem9, bins=50, density=True, alpha=0.6, range=(0, 5))
axes[1].plot(x, stats.f.pdf(x, dfn=n_x-1, dfd=n_y-1), 'r-', lw=2)
axes[1].set_title('定理9验证: F统计量')
plt.tight_layout()
plt.show()
理解了这些统计定理后,我们可以将其应用到实际问题中。下面是一个完整的假设检验案例,展示了如何利用这些定理进行科学的统计推断。
场景:某工厂有两条生产线生产相同规格的零件。质量部门想检验两条生产线生产的零件长度是否存在显著差异。从生产线A抽取30个样本,生产线B抽取40个样本,测量长度数据如下:
python复制# 模拟生成数据
np.random.seed(42)
sample_A = np.random.normal(loc=10.0, scale=0.8, size=30)
sample_B = np.random.normal(loc=10.3, scale=0.8, size=40)
# 计算样本统计量
mean_A, mean_B = np.mean(sample_A), np.mean(sample_B)
var_A, var_B = np.var(sample_A, ddof=1), np.var(sample_B, ddof=1)
print(f"生产线A: 均值={mean_A:.2f}, 方差={var_A:.2f}")
print(f"生产线B: 均值={mean_B:.2f}, 方差={var_B:.2f}")
# 进行F检验比较方差
F = var_A / var_B
p_value_F = 2 * min(stats.f.cdf(F, len(sample_A)-1, len(sample_B)-1),
1 - stats.f.cdf(F, len(sample_A)-1, len(sample_B)-1))
print(f"\nF检验: F值={F:.3f}, p值={p_value_F:.3f}")
# 进行t检验比较均值
t_stat, p_value_t = stats.ttest_ind(sample_A, sample_B, equal_var=True)
print(f"\n独立样本t检验: t值={t_stat:.3f}, p值={p_value_t:.3f}")
# 绘制数据分布
plt.figure(figsize=(10, 6))
plt.boxplot([sample_A, sample_B], labels=['生产线A', '生产线B'])
plt.title('两条生产线零件长度比较')
plt.ylabel('长度(mm)')
plt.show()
这个案例完整展示了如何从实际问题出发,利用正态分布的统计定理进行科学的统计推断。通过F检验验证方差齐性假设后,我们使用两样本t检验比较了两条生产线的均值差异。