Skip to content

统计推断

统计推断超越了简单的“是/否”决策,以量化的不确定性来估计总体参数。本章涵盖置信区间、点估计与区间估计、最大似然估计、矩估计法以及回归分析,这些是从原始数据到机器学习预测模型之间的桥梁。

  • 假设检验给出“是/否”的决策:拒绝或不拒绝零假设。但通常你希望获得更具信息性的结果,即你所估计参数的一个合理取值范围。这就是置信区间所提供的。

  • 点估计是从样本计算出的单个数字,如样本均值 \(\bar{x}\)。它是你对总体参数的最佳猜测,但本身无法体现估计的精确程度。

  • 置信区间给点估计包裹了一个反映不确定性的范围。其形式为:

\[\text{CI} = \bar{x} \pm \text{ME}\]
  • 边际误差(ME) 取决于三个因素:你想要的置信水平、数据的变异性以及样本大小:
\[\text{ME} = z^\ast \cdot \frac{\sigma}{\sqrt{n}}\]
  • 这里 \(z^\ast\) 是正态分布中与你期望的置信水平匹配的临界值。对于 95% 的置信水平,\(z^\ast = 1.96\);对于 99% 的置信水平,\(z^\ast = 2.576\)

置信区间:点估计及其两侧的边际误差

  • 95% 置信区间意味着:如果你多次重复实验并每次都构建一个区间,大约 95% 的这些区间会包含真实的总体参数。这并不意味着该参数有 95% 的概率落在这个特定区间内。参数是固定的,变化的是区间。

  • 工作示例:你测量了 50 人的身高,得到 \(\bar{x} = 170\) 厘米,\(\sigma = 8\) 厘米。构造一个 95% 的置信区间。

\[\text{ME} = 1.96 \cdot \frac{8}{\sqrt{50}} = 1.96 \cdot 1.131 = 2.22 \text{ 厘米}\]
\[\text{CI} = [170 - 2.22, \; 170 + 2.22] = [167.78, \; 172.22]\]
  • 你可以有 95% 的把握说,真实平均身高介于 167.78 和 172.22 厘米之间。

  • \(\sigma\) 未知(通常情况)时,使用样本标准差 \(s\) 和 t 分布代替:

\[\text{CI} = \bar{x} \pm t^\ast_{n-1} \cdot \frac{s}{\sqrt{n}}\]
  • 更宽的区间置信水平更高但精度更低;更窄的区间精度更高但置信水平更低。增大样本量可以在不降低置信水平的情况下缩小区间。

  • 功效分析帮助你在进行实验之前进行规划。问题是:为了以指定的功效检测到给定大小的效应,我需要多大的样本量?

  • 回忆前一章,功效 = \(1 - \beta\),即正确拒绝假 \(H_0\) 的概率。通常的目标是 80% 的功效。

  • 对于 z 检验,检测差值为 \(\delta\)、显著性水平为 \(\alpha\)、功效为 \(1-\beta\) 所需的样本量为:

\[n = \left(\frac{(z_{\alpha/2} + z_{\beta}) \cdot \sigma}{\delta}\right)^2\]
  • 例如,要检测 2 厘米的平均身高差异(\(\sigma = 8\)),设定 \(\alpha = 0.05\) 和 80% 功效(\(z_{0.025} = 1.96\)\(z_{0.20} = 0.84\)):
\[n = \left(\frac{(1.96 + 0.84) \cdot 8}{2}\right)^2 = \left(\frac{22.4}{2}\right)^2 = 11.2^2 \approx 126\]
  • 每组大约需要 126 人。

  • 功效分析可以防止两种常见错误:实验规模太小而无法检测到真实效应(功效不足),或者资源浪费在远大于必要规模的实验上(过度功效)。

  • 蒙特卡罗方法利用随机抽样来解决那些解析求解困难或不可能的问题。核心思想是:如果你无法精确计算某个量,那就多次模拟它,并将结果作为近似值。

  • 这个名字来源于蒙特卡洛赌场,象征着随机性的作用。这些方法是机器学习中的主力,用于估计积分、评估模型不确定性以及近似复杂分布等任务。

  • 通用的蒙特卡罗步骤:

    • 定义可能的输入域
    • 从该域生成随机输入
    • 对每个输入评估一个函数
    • 汇总结果(平均、计数等)
  • 一个经典的例子是估计 \(\pi\)。想象一个边长为 2 的正方形,中心在原点,内切一个半径为 1 的圆。正方形的面积为 4,圆的面积为 \(\pi\)

内切圆的正方形,随机点按是否在圆内着色

  • 在正方形内均匀随机投点。落在圆内的点的比例近似于 \(\pi/4\)
\[\pi \approx 4 \times \frac{\text{圆内点数}}{\text{总点数}}\]
  • \((x, y)\) 在圆内当且仅当 \(x^2 + y^2 \le 1\)。投的点越多,估计值就越接近 \(\pi\) 的真值。

  • 在机器学习中,蒙特卡罗方法出现在:

    • 蒙特卡罗 dropout:在启用 dropout 的情况下多次运行推理,以估计预测不确定性
    • MCMC(马尔可夫链蒙特卡罗):从贝叶斯模型中的复杂后验分布中抽样
    • 策略梯度方法:通过对轨迹抽样来估计强化学习中的梯度
  • 因子分析是一种发现隐藏(潜)变量的技术,这些潜变量可以解释观测变量之间的相关性。如果 10 个个性调查问题可以用 3 个潜在特质(外向性、宜人性、尽责性)来解释,因子分析就能找到这些特质。

  • 该模型假设每个观测变量 \(x_i\) 是少数几个潜在因子 \(f_j\) 的线性组合加上噪声:

\[x_i = \lambda_{i1} f_1 + \lambda_{i2} f_2 + \ldots + \lambda_{ik} f_k + \epsilon_i\]
  • \(\lambda\) 值称为因子载荷,告诉你每个观测变量与每个因子的关联强度。这直接联系到第 2 章的矩阵分解;因子分析与特征值分解和 SVD 密切相关。

  • 实验设计是构建实验以便得出有效结论的艺术。糟糕的设计即使有大型数据集也可能毫无用处。

  • 设计良好的实验的关键组成部分:

    • 自变量(IV):你操纵的变量(例如,药物剂量、模型架构)
    • 因变量(DV):你测量的变量(例如,恢复时间、准确率)
    • 控制组:不接受处理(或接受安慰剂),提供比较的基线
    • 随机分配:参与者被随机分配到各组,这平衡了你未测量的混杂变量
  • 常见的实验设计

    • 完全随机设计:受试者被随机分配到处理组。当各组可比时简单有效。
    • 随机区组设计:首先将受试者按区组分组(例如按年龄),然后在每个区组内随机分配到处理。这减少了区组因子的变异性,类似于分层抽样的思想。
    • 析因设计:同时测试多个自变量。一个 \(2 \times 3\) 析因设计表示一个变量有 2 个水平,另一个变量有 3 个水平,共产生 6 种处理组合。这使你能检测交互作用,即一个变量的效应依赖于另一个变量的水平。
    • 交叉设计:每个受试者按顺序接受所有处理(中间有洗脱期)。每个受试者作为自己的对照,减少了个体差异的影响。
  • 在机器学习实验中,这些原则至关重要。比较模型时,应控制随机种子、数据集划分和硬件。交叉验证是交叉设计的一种形式。消融研究(一次移除一个组件)遵循析因设计的逻辑。

编程任务(使用 CoLab 或 notebook)

  1. 为身高示例构造 95% 置信区间,然后尝试不同的置信水平和样本量。

    import jax.numpy as jnp
    
    x_bar = 170.0    # 样本均值
    sigma = 8.0      # 总体标准差(已知)
    n = 50           # 样本量
    
    # 常见置信水平的临界值
    z_stars = {0.90: 1.645, 0.95: 1.960, 0.99: 2.576}
    
    for conf, z_star in z_stars.items():
        me = z_star * (sigma / jnp.sqrt(n))
        lower, upper = x_bar - me, x_bar + me
        print(f"{conf*100:.0f}% CI: [{lower:.2f}, {upper:.2f}]  (ME = {me:.2f})")
    

  2. 使用蒙特卡罗模拟估计 \(\pi\)。绘制随着点数增加估计值如何收敛的图。

    import jax
    import jax.numpy as jnp
    import matplotlib.pyplot as plt
    
    key = jax.random.PRNGKey(42)
    
    # 在 [-1, 1] x [-1, 1] 内生成随机点
    n_points = 100_000
    k1, k2 = jax.random.split(key)
    x = jax.random.uniform(k1, shape=(n_points,), minval=-1, maxval=1)
    y = jax.random.uniform(k2, shape=(n_points,), minval=-1, maxval=1)
    
    # 检查哪些点位于单位圆内
    inside = (x**2 + y**2) <= 1.0
    cumulative_inside = jnp.cumsum(inside)
    counts = jnp.arange(1, n_points + 1)
    pi_estimates = 4.0 * cumulative_inside / counts
    
    plt.figure(figsize=(10, 4))
    plt.plot(pi_estimates, color="#3498db", alpha=0.7, linewidth=0.5)
    plt.axhline(y=jnp.pi, color="#e74c3c", linestyle="--", label=f"π = {jnp.pi:.6f}")
    plt.xlabel("点数")
    plt.ylabel("π 的估计值")
    plt.title("蒙特卡罗估计 π")
    plt.legend()
    plt.ylim(2.8, 3.5)
    plt.show()
    
    print(f"最终估计: {pi_estimates[-1]:.6f}")
    print(f"真值:     {jnp.pi:.6f}")
    print(f"误差:     {abs(pi_estimates[-1] - jnp.pi):.6f}")
    

  3. 进行简单的功效分析:给定效应大小和标准差,计算所需样本量,并通过模拟验证。

    import jax
    import jax.numpy as jnp
    
    # 参数
    delta = 2.0      # 效应大小(均值差)
    sigma = 8.0      # 总体标准差
    alpha = 0.05
    power_target = 0.80
    
    # 解析样本量
    z_alpha = 1.96   # 双侧,alpha=0.05
    z_beta = 0.84    # 功效=0.80
    n_required = ((z_alpha + z_beta) * sigma / delta) ** 2
    print(f"每组所需样本量: {n_required:.0f}")
    
    # 通过模拟验证
    key = jax.random.PRNGKey(7)
    n = int(jnp.ceil(n_required))
    n_sims = 5000
    rejections = 0
    
    for _ in range(n_sims):
        key, k1, k2 = jax.random.split(key, 3)
        group_a = jax.random.normal(k1, shape=(n,)) * sigma + 50
        group_b = jax.random.normal(k2, shape=(n,)) * sigma + 50 + delta
        pooled_se = jnp.sqrt(2 * sigma**2 / n)
        z = (group_b.mean() - group_a.mean()) / pooled_se
        p = 2 * (1 - __import__("jax").scipy.stats.norm.cdf(jnp.abs(z)))
        if p <= alpha:
            rejections += 1
    
    print(f"模拟功效: {rejections/n_sims:.3f}")
    print(f"目标功效:    {power_target:.3f}")
    

  4. 可视化置信区间宽度随样本量的变化。这展示了为什么收集更多数据能给出更精确的估计。

    import jax.numpy as jnp
    import matplotlib.pyplot as plt
    
    sigma = 8.0
    z_star = 1.96  # 95% 置信度
    
    sample_sizes = jnp.array([10, 20, 30, 50, 100, 200, 500, 1000], dtype=jnp.float32)
    margins = z_star * sigma / jnp.sqrt(sample_sizes)
    
    plt.figure(figsize=(8, 4))
    plt.bar([str(int(n)) for n in sample_sizes], margins, color="#3498db", alpha=0.7)
    plt.xlabel("样本量")
    plt.ylabel("边际误差(厘米)")
    plt.title("更大的样本量使 95% CI 边际误差缩小")
    plt.show()