Skip to content

假设检验

假设检验提供了一个严格的框架,用于判断观察到的效应是真实存在的还是由偶然因素造成的。本章涵盖零假设与备择假设、p 值、显著性水平、t 检验、卡方检验、方差分析以及第 I 类与第 II 类错误,这些逻辑同样用于 A/B 测试、模型比较和研究中。

  • 统计学不仅仅是描述数据。通常你需要做出一个决策:一种新药是否有效?一种算法是否比另一种更快?平均值是否发生了变化?假设检验为你提供了一个结构化的框架,利用数据来回答这些问题。

  • 思路很简单:假设没有发生任何变化(“零假设”),然后检查数据是否极端到使这个假设难以令人信服。

  • 零假设\(H_0\))是默认的主张,通常是“无效应”或“无差异”的陈述。例如:“平均配送时间仍然是 30 分钟”或“新模型并不比旧模型好”。

  • 备择假设\(H_1\)\(H_a\))是你认为可能成立的情况:“平均配送时间已经改变”或“新模型更好”。

  • 你永远不会直接证明 \(H_1\)。相反,你会问:如果 \(H_0\) 为真,我观察到如此极端的数据的可能性有多大?如果这种可能性很小,你就拒绝 \(H_0\),转而支持 \(H_1\)

  • 检验统计量是一个单值,它概括了你的样本结果与 \(H_0\) 预测结果之间的差距。不同的检验使用不同的公式,但逻辑总是相同的:测量观测值与期望值之间的距离。

  • p 值是在假设 \(H_0\) 为真的前提下,观察到检验统计量至少与你的结果一样极端的概率。p 值很小意味着在 \(H_0\) 下数据是令人惊讶的。

  • 显著性水平\(\alpha\))是你在查看数据之前设定的阈值。如果 \(p \le \alpha\),你就拒绝 \(H_0\)。常用的选择是 \(\alpha = 0.05\)(5%)和 \(\alpha = 0.01\)(1%)。

正态曲线,显示拒绝域、标记的检验统计量以及高亮的 p 值区域

  • 阴影尾部是拒绝域。如果你的检验统计量落在那里,表明在 \(H_0\) 下数据足够令人惊讶,从而拒绝它。绿色区域显示了特定检验统计量的 p 值。

  • 以下是逐步流程:

    • 第 1 步:陈述 \(H_0\)\(H_1\)
    • 第 2 步:选择显著性水平 \(\alpha\)
    • 第 3 步:收集数据并计算检验统计量
    • 第 4 步:找到 p 值(或将检验统计量与临界值比较)
    • 第 5 步:如果 \(p \le \alpha\),则拒绝 \(H_0\);否则,不拒绝 \(H_0\)
  • 工作示例:一家工厂声称他们的螺栓平均长度为 10 厘米。你测量了 36 个螺栓,发现样本均值为 10.3 厘米。已知总体标准差为 0.9 厘米。是否有证据表明均值已经改变?

  • \(H_0\)\(\mu = 10\)\(H_1\)\(\mu \neq 10\)\(\alpha = 0.05\)

  • 检验统计量(z 检验,因为 \(\sigma\) 已知且 \(n\) 较大):

\[z = \frac{\bar{x} - \mu_0}{\sigma / \sqrt{n}} = \frac{10.3 - 10}{0.9 / \sqrt{36}} = \frac{0.3}{0.15} = 2.0\]
  • 对于 \(\alpha = 0.05\) 的双侧检验,临界值为 \(\pm 1.96\)。我们的 \(z = 2.0 > 1.96\),因此我们拒绝 \(H_0\)。p 值约为 0.046,小于 0.05。

  • 结论:有统计学上显著的证据表明螺栓的平均长度不同于 10 厘米。

  • 单侧检验检查特定方向上的效应(\(H_1\)\(\mu > 10\)\(\mu < 10\))。整个 \(\alpha\) 放在一侧尾部,使得在该方向上更容易拒绝 \(H_0\),但无法检测相反方向上的效应。

  • 双侧检验检查任何差异(\(H_1\)\(\mu \neq 10\))。\(\alpha\) 被分到两侧尾部(每侧 \(\alpha/2\))。这样更保守,但能捕捉到任何方向的效应。

  • 即使有好的流程,错误也会发生。恰好有两种类型的错误:

2x2 网格显示第 I 类和第 II 类错误:现实情况 vs 决策结果

  • 第 I 类错误(假阳性):当 \(H_0\) 实际上为真时,你拒绝 \(H_0\)。这个概率是 \(\alpha\),由你选择的显著性水平控制。就像没有火时火警响了。

  • 第 II 类错误(假阴性):当 \(H_0\) 实际上为假时,你没有拒绝 \(H_0\)。这个概率是 \(\beta\)。就像发生火灾时火警保持沉默。

  • 功效(Power)是 \(1 - \beta\),即正确拒绝假 \(H_0\) 的概率。功效越高,检测真实效应的能力越强。功效随着以下因素增加:

    • 真实效应量更大(更大的差异更容易检测)
    • 样本量更大(更多数据 = 更高精度)
    • 显著性水平 \(\alpha\) 更大(但这会增加第 I 类错误风险)
    • 变异性更低(噪声更小)
  • 第 I 类错误和第 II 类错误之间存在权衡。降低 \(\alpha\)(对假阳性更谨慎)会增加 \(\beta\)(更多假阴性)。在固定样本量下,你无法同时最小化两者。

  • 参数检验假设数据服从特定分布(通常是正态分布)。当假设成立时,它们功效更强。

  • Z 检验:在 \(\sigma\) 已知且 \(n\) 较大(\(n \ge 30\))时,将样本均值与已知值进行比较。检验统计量:

\[z = \frac{\bar{x} - \mu_0}{\sigma / \sqrt{n}}\]
  • t 检验:类似于 z 检验,但适用于 \(\sigma\) 未知(从样本估计)或 \(n\) 较小的情况。使用 t 分布,其尾部比正态分布更重。更重的尾部考虑了估计 \(\sigma\) 所带来的额外不确定性。
\[t = \frac{\bar{x} - \mu_0}{s / \sqrt{n}}\]
  • t 分布有一个称为自由度\(df = n - 1\))的参数。随着 \(df\) 增加,t 分布趋近于正态分布。

  • t 检验有几种形式:

    • 单样本 t 检验:样本均值是否与某个特定值不同?
    • 独立双样本 t 检验:两个独立组的均值是否不同?
    • 配对 t 检验:两个相关测量值的均值是否不同(例如同一对象治疗前后的测量值)?
  • ANOVA(方差分析):检验三个或更多组的均值是否相等。不是进行多次 t 检验(这会使第 I 类错误率膨胀),而是通过比较组间方差与组内方差进行一次检验。

\[F = \frac{\text{组间方差}}{\text{组内方差}}\]
  • 大的 \(F\) 比率意味着组间差异大于仅由随机变异所预期的差异。

  • 非参数检验对数据分布所做的假设较少。它们基于秩次而非原始值,因此对异常值和非正态性具有稳健性。

  • 卡方检验\(\chi^2\)):检验观测频数是否与期望频数匹配。用于分类数据。例如:红色、蓝色和绿色汽车的比例是否与制造商声称的比例一致?

\[\chi^2 = \sum \frac{(O_i - E_i)^2}{E_i}\]
  • Mann-Whitney U 检验:独立双样本 t 检验的非参数替代。它通过比较秩次来检验一组是否倾向于比另一组有更大的值。

  • Wilcoxon 符号秩检验:配对 t 检验的非参数替代。通过观察差异的大小和方向来比较配对观测值。

  • Kruskal-Wallis 检验:单因素方差分析的非参数替代。通过比较所有组的秩次来检验多个组是否来自同一分布。

  • 拟合优度检验检查你的数据是否遵循特定的理论分布。卡方拟合优度检验将观测的区间计数与假设分布下的期望计数进行比较。

  • 正态性检验专门检查数据是否服从正态分布。常见的包括 Shapiro-Wilk 检验(对样本量小的情况功效较强)和 Kolmogorov-Smirnov 检验(将样本 CDF 与理论 CDF 进行比较)。

  • 在机器学习中,当你比较模型性能时,假设检验会出现。如果模型 A 达到 92% 的准确率,模型 B 达到 91% 的准确率,差异是真实的还是仅仅是噪声?对交叉验证得分进行配对 t 检验可以回答这个问题。

编程任务(使用 CoLab 或 notebook)

  1. 对正文中的螺栓工厂示例进行 z 检验。计算检验统计量、p 值并做出决策。

    import jax.numpy as jnp
    
    x_bar = 10.3    # 样本均值
    mu_0 = 10.0     # 零假设值
    sigma = 0.9     # 已知总体标准差
    n = 36          # 样本量
    alpha = 0.05
    
    # 检验统计量
    z = (x_bar - mu_0) / (sigma / jnp.sqrt(n))
    print(f"z = {z:.4f}")
    
    # 使用正态 CDF 近似计算双侧 p 值
    # 对于 |z| = 2.0,p ≈ 0.0456
    from jax.scipy.stats import norm
    p_value = 2 * (1 - norm.cdf(jnp.abs(z)))
    print(f"p 值 = {p_value:.4f}")
    print(f"拒绝 H₀? {p_value <= alpha}")
    

  2. 模拟第 I 类错误:当 \(H_0\) 为真时,我们错误拒绝它的频率是多少?运行 10,000 次实验,检查拒绝率是否与 \(\alpha\) 匹配。

    import jax
    import jax.numpy as jnp
    
    key = jax.random.PRNGKey(0)
    mu_0 = 50.0
    sigma = 10.0
    n = 30
    alpha = 0.05
    n_experiments = 10_000
    
    rejections = 0
    for i in range(n_experiments):
        key, subkey = jax.random.split(key)
        sample = mu_0 + sigma * jax.random.normal(subkey, shape=(n,))
        z = (sample.mean() - mu_0) / (sigma / jnp.sqrt(n))
        p_value = 2 * (1 - __import__("jax").scipy.stats.norm.cdf(jnp.abs(z)))
        if p_value <= alpha:
            rejections += 1
    
    print(f"拒绝率: {rejections/n_experiments:.4f}")
    print(f"期望值 (α):   {alpha}")
    

  3. 比较两组数据上的 t 检验和 Mann-Whitney U 检验。生成一组均值略高的数据,看看哪种检验能检测出差异。

    import jax
    import jax.numpy as jnp
    
    key = jax.random.PRNGKey(99)
    k1, k2 = jax.random.split(key)
    
    group_a = jax.random.normal(k1, shape=(25,)) * 5 + 100
    group_b = jax.random.normal(k2, shape=(25,)) * 5 + 103  # 均值略高
    
    # 双样本 t 检验(假设等方差)
    n_a, n_b = len(group_a), len(group_b)
    mean_a, mean_b = group_a.mean(), group_b.mean()
    pooled_var = ((n_a - 1) * group_a.var() + (n_b - 1) * group_b.var()) / (n_a + n_b - 2)
    se = jnp.sqrt(pooled_var * (1/n_a + 1/n_b))
    t_stat = (mean_a - mean_b) / se
    print(f"t 检验统计量: {t_stat:.4f}")
    
    # Mann-Whitney:统计 group_a 的值小于 group_b 的值的次数
    u_stat = jnp.sum(group_a[:, None] < group_b[None, :])
    print(f"Mann-Whitney U:   {u_stat}")
    print(f"\nA 组均值: {mean_a:.2f}, B 组均值: {mean_b:.2f}")