三大抽样分布(χ²/t/F)Python 模拟:从定义到 10000 次抽样可视化

统计学中的三大抽样分布——卡方分布(χ²)、t分布和F分布,是数据分析师和统计学家工具箱中的核心武器。这些分布不仅在假设检验中扮演关键角色,更是理解数据背后规律的重要桥梁。但传统的数学定义和公式推导往往让学习者望而生畏,难以直观把握其本质特征。

本文将采用 计算模拟与可视化 的全新视角,通过Python代码实现三大分布的随机抽样和动态图表展示。我们将从定义出发,用10000次抽样实验揭示分布形态随自由度的变化规律,并通过交互式图表对比不同参数下的分布特征。这种"代码+可视化"的学习路径,不仅能帮助您建立直观理解,还能让抽象的统计概念变得可操作、可验证。

1. 环境准备与基础概念

在开始模拟之前,我们需要配置Python环境并理解三大分布的基本定义。以下是所需的工具包:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns

1.1 三大分布的核心定义

表:三大抽样分布的数学定义对比

分布类型 定义公式 参数说明
卡方分布(χ²) $X = \sum_{i=1}^n Z_i^2$ $Z_i$为标准正态变量,n为自由度
t分布 $T = \frac{Z}{\sqrt{V/n}}$ Z为标准正态,V为自由度为n的卡方变量
F分布 $F = \frac{U/n_1}{V/n_2}$ U,V为独立的卡方变量,n1,n2为自由度

提示:自由度是分布形态的关键参数,可以理解为独立信息的数量。在卡方分布中,它等于平方和的项数;在t分布中代表样本量减1;在F分布中则有两组自由度。

1.2 分布的可视化准备

我们将使用Matplotlib创建动态图表,展示不同自由度下分布形态的变化。以下代码设置画布样式:

plt.style.use('seaborn')
plt.rcParams['figure.figsize'] = (12, 6)
plt.rcParams['font.size'] = 12
colors = ['#1f77b4', '#ff7f0e', '#2ca02c']  # 设置配色方案

2. 卡方分布(χ²)的模拟实验

卡方分布是正态随机变量平方和的分布,广泛用于独立性检验和方差分析。让我们通过模拟揭示其特性。

2.1 卡方分布生成与可视化

def simulate_chi2(df_list, sample_size=10000):
    fig, ax = plt.subplots()
    x = np.linspace(0, 20, 1000)
    
    for df, color in zip(df_list, colors):
        samples = np.sum(np.random.randn(sample_size, df)**2, axis=1)
        sns.kdeplot(samples, label=f'df={df}', color=color, ax=ax)
        plt.plot(x, stats.chi2.pdf(x, df), '--', color=color)
    
    plt.title(f'卡方分布形态 (n={sample_size})')
    plt.xlabel('Value')
    plt.ylabel('Density')
    plt.legend()
    plt.show()

simulate_chi2(df_list=[2, 5, 10])

图1展示了不同自由度下卡方分布的形态变化,我们可以观察到:

  • 分布右偏,随着自由度增加逐渐对称
  • 峰值位置向右移动,分布变得更加分散
  • 当自由度很大时(通常>50),接近正态分布

2.2 卡方分布的性质验证

卡方分布有两个重要性质:

  1. 期望E(χ²)=n,方差D(χ²)=2n
  2. 可加性:独立的卡方变量之和仍为卡方分布

让我们用模拟验证这些性质:

# 期望和方差验证
df = 5
samples = np.sum(np.random.randn(10000, df)**2, axis=1)
print(f"模拟均值: {np.mean(samples):.2f}, 理论均值: {df}")
print(f"模拟方差: {np.var(samples):.2f}, 理论方差: {2*df}")

# 可加性验证
chi1 = np.sum(np.random.randn(10000, 3)**2, axis=1)  # df=3
chi2 = np.sum(np.random.randn(10000, 4)**2, axis=1)  # df=4
combined = chi1 + chi2

plt.hist(combined, bins=50, density=True, alpha=0.6, label='模拟值')
x = np.linspace(0, 25, 100)
plt.plot(x, stats.chi2.pdf(x, 7), 'r-', label='χ²(7)')
plt.legend()
plt.title('卡方分布可加性验证')
plt.show()

3. t分布的模拟与中心极限定理

t分布在小样本推断中至关重要,特别是在总体方差未知时。我们将探索其与正态分布的关系。

3.1 t分布生成代码

def simulate_t_distribution(df_list, sample_size=10000):
    x = np.linspace(-5, 5, 1000)
    plt.figure()
    
    for df, color in zip(df_list, colors):
        # t分布可以表示为标准正态与卡方分布的组合
        z = np.random.randn(sample_size)
        chi2 = np.sum(np.random.randn(sample_size, df)**2, axis=1)
        t_samples = z / np.sqrt(chi2/df)
        
        sns.kdeplot(t_samples, label=f'df={df}', color=color)
        plt.plot(x, stats.t.pdf(x, df), '--', color=color)
    
    # 添加标准正态分布对比
    plt.plot(x, stats.norm.pdf(x), 'k-', label='N(0,1)') 
    plt.title('t分布与正态分布对比')
    plt.legend()
    plt.show()

simulate_t_distribution(df_list=[1, 5, 30])

关键观察结果:

  • 自由度越小,尾部越厚(极端值概率更高)
  • 当df=1时,t分布就是柯西分布
  • 当df>30时,t分布与标准正态几乎无法区分

3.2 中心极限定理的t分布视角

中心极限定理告诉我们,样本均值经过标准化后会趋近正态分布。但当用样本标准差代替总体标准差时,就产生了t分布:

def clt_t_demo(pop_dist, df=5, sample_size=30, n_experiments=10000):
    means = []
    t_stats = []
    
    for _ in range(n_experiments):
        sample = pop_dist.rvs(size=sample_size)
        sample_mean = np.mean(sample)
        sample_std = np.std(sample, ddof=1)
        
        z_stat = (sample_mean - 0)/(pop_dist.std()/np.sqrt(sample_size))
        t_stat = (sample_mean - 0)/(sample_std/np.sqrt(sample_size))
        
        means.append(z_stat)
        t_stats.append(t_stat)
    
    # 绘制对比图
    plt.figure(figsize=(12, 5))
    plt.subplot(121)
    sns.kdeplot(means, label='Z统计量')
    plt.plot(np.linspace(-4,4,100), stats.norm.pdf(np.linspace(-4,4,100)), 'r--')
    plt.title('总体方差已知时的分布')
    
    plt.subplot(122)
    sns.kdeplot(t_stats, label='t统计量')
    plt.plot(np.linspace(-4,4,100), stats.t.pdf(np.linspace(-4,4,100), df), 'r--')
    plt.title('总体方差未知时的分布')
    plt.show()

clt_t_demo(pop_dist=stats.norm(loc=0, scale=1))

注意:当使用样本标准差时,统计量服从t分布而非正态分布。这就是为什么小样本情况下必须使用t检验而非z检验。

4. F分布的模拟与方差分析基础

F分布是方差比值的分布,在ANOVA和回归分析中广泛应用。让我们深入理解其特性。

4.1 F分布生成与可视化

def simulate_f_distribution(df_pairs, sample_size=10000):
    plt.figure()
    x = np.linspace(0, 5, 1000)
    
    for (df1, df2), color in zip(df_pairs, colors):
        # 生成两个独立的卡方变量
        chi1 = np.sum(np.random.randn(sample_size, df1)**2, axis=1) / df1
        chi2 = np.sum(np.random.randn(sample_size, df2)**2, axis=1) / df2
        f_samples = chi1 / chi2
        
        sns.kdeplot(f_samples, label=f'df=({df1},{df2})', color=color)
        plt.plot(x, stats.f.pdf(x, df1, df2), '--', color=color)
    
    plt.title('F分布形态')
    plt.xlim(0, 5)
    plt.legend()
    plt.show()

simulate_f_distribution(df_pairs=[(5,10), (10,10), (20,20)])

F分布的关键特征:

  • 非负且右偏
  • 形态由两组自由度共同决定
  • 当分母自由度很大时,F(n1,∞)等价于χ²(n1)/n1

4.2 F分布在方差分析中的应用

F统计量是组间方差与组内方差的比值。让我们模拟单因素ANOVA场景:

def anova_simulation(groups_means, group_std, n_per_group=20):
    n_groups = len(groups_means)
    data = []
    
    for mean in groups_means:
        data.append(stats.norm(loc=mean, scale=group_std).rvs(n_per_group))
    
    # 计算F统计量
    overall_mean = np.mean(np.concatenate(data))
    ss_between = n_per_group * sum((np.mean(group) - overall_mean)**2 for group in data)
    ss_within = sum(np.sum((group - np.mean(group))**2) for group in data)
    
    df_between = n_groups - 1
    df_within = n_groups * (n_per_group - 1)
    
    f_stat = (ss_between/df_between) / (ss_within/df_within)
    
    # 绘制结果
    x = np.linspace(0, 10, 100)
    plt.plot(x, stats.f.pdf(x, df_between, df_within), 'b-')
    plt.axvline(f_stat, color='r', linestyle='--')
    plt.title(f'F分布与模拟F统计量 (F={f_stat:.2f})')
    plt.xlabel('F值')
    plt.ylabel('密度')
    plt.show()

anova_simulation(groups_means=[5, 6, 7], group_std=1.5)

5. 三大分布的相互关系与综合应用

三大抽样分布并非孤立存在,它们之间有着深刻的联系。理解这些关系有助于构建统一的统计推断框架。

5.1 分布间的数学关系

  1. t分布与F分布 :当F分布的分母自由度为1时,F(1,n) = t²(n)
  2. 卡方分布与F分布 :当F分布的分母自由度趋近∞时,n1×F(n1,∞) ~ χ²(n1)
  3. t分布与正态分布 :当t分布的自由度n→∞时,t(n)→N(0,1)

让我们用代码验证第一个关系:

df = 10
t_samples = stats.t.rvs(df, size=10000)
f_samples = t_samples**2

plt.figure(figsize=(12,5))
plt.subplot(121)
sns.kdeplot(f_samples, label='t²')
plt.plot(np.linspace(0,10,100), stats.f.pdf(np.linspace(0,10,100), 1, df), 'r--')
plt.title('t²与F(1,n)比较')

plt.subplot(122)
qqplot(f_samples, stats.f(1, df), line='45')
plt.title('Q-Q图检验')
plt.show()

5.2 实际应用中的选择指南

表:三大分布在假设检验中的典型应用场景

检验类型 适用分布 典型问题 Python函数
方差检验 卡方分布 单个方差是否等于特定值 scipy.stats.chisquare
均值检验 t分布 小样本均值比较 scipy.stats.ttest_1samp
方差比检验 F分布 两组方差是否相等 scipy.stats.f_oneway

提示:现代统计软件虽然会自动选择合适的检验方法,但理解背后的分布原理能帮助正确解读结果并处理异常情况。

5.3 综合案例:线性回归中的分布应用

在线性回归中,三大分布各司其职:

from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression

# 生成回归数据
X, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)
model = LinearRegression().fit(X, y)

# 计算t统计量(回归系数显著性)
residuals = y - model.predict(X)
sigma_hat = np.sqrt(np.sum(residuals**2) / (len(y)-2))
se_beta = sigma_hat / np.sqrt(np.sum((X - np.mean(X))**2))
t_stat = model.coef_[0] / se_beta

# 计算F统计量(模型整体显著性)
ssr = np.sum((model.predict(X) - np.mean(y))**2)
sse = np.sum(residuals**2)
f_stat = (ssr/1) / (sse/(len(y)-2))

print(f"回归系数t统计量: {t_stat:.2f} (p={2*(1-stats.t.cdf(abs(t_stat), len(y)-2)):.4f})")
print(f"模型F统计量: {f_stat:.2f} (p={1-stats.f.cdf(f_stat, 1, len(y)-2):.4f})")

输出结果显示:

  • 回归系数的显著性检验使用t分布
  • 模型整体显著性检验使用F分布
  • 残差分析中还会用到卡方分布

6. 高级可视化与交互探索

为了更深入地理解这些分布,我们创建交互式可视化工具,允许动态调整参数观察分布变化。

6.1 使用Plotly创建动态图表

import plotly.graph_objects as go
from ipywidgets import interact

def interactive_chi2(df=(1, 30)):
    x = np.linspace(0, 50, 500)
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=x, y=stats.chi2.pdf(x, df), 
                            mode='lines', name=f'χ²({df})'))
    fig.update_layout(title=f'卡方分布 (df={df})', 
                     xaxis_title='Value', yaxis_title='Density')
    fig.show()

interact(interactive_chi2)

6.2 分布比较仪表盘

def distribution_dashboard(dist_type='t', df1=5, df2=5):
    x = np.linspace(-5, 5, 500) if dist_type == 't' else np.linspace(0, 5, 500)
    
    if dist_type == 't':
        y = stats.t.pdf(x, df1)
        title = f't分布 (df={df1})'
    elif dist_type == 'chi2':
        y = stats.chi2.pdf(x, df1)
        title = f'卡方分布 (df={df1})'
    else:
        y = stats.f.pdf(x, df1, df2)
        title = f'F分布 (df=({df1},{df2}))'
    
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=x, y=y, mode='lines'))
    fig.update_layout(title=title, xaxis_title='Value', yaxis_title='Density')
    fig.show()

interact(distribution_dashboard, 
         dist_type=['t', 'chi2', 'f'], 
         df1=(1, 30), 
         df2=(1, 30))

这种交互式探索让参数变化对分布形态的影响变得直观可见,特别适合教学和自学场景。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐