← 返回《数据科学的统计基础》
📑 查看全课大纲(第 27 / 41 节)

列联表的独立性检验

约 28 分钟

📺 正在播放小象官方高清录播(支持倍速与清晰度调节)

列联表的独立性检验

小象实战讲义 · 数据科学的统计基础

在实际数据分析中,我们常常需要探究两个或多个分类变量之间是否存在关联。例如,性别是否影响对某种产品的偏好?不同地区的用户流失率是否有显著差异?列联表的独立性检验为我们提供了解决这类问题的标准统计工具。本节将从二维列联表入手,系统讲解卡方独立性检验的原理、步骤与计算,并进一步探讨高维列联表的分析方法及其在揭示复杂关联中的重要性。

💡 核心导读

  • 列联表是什么:学习如何用一张表格(列联表)来汇总和展示两个或多个分类变量的联合频数分布。
  • 二维独立性检验:掌握如何利用卡方拟合优度检验,判断二维列联表中两个分类变量是否相互独立。
  • 检验统计量与分布:推导并理解独立性检验的卡方统计量公式及其在原假设下的渐近分布。
  • 高维列联表分析:了解如何将独立性检验推广到三维及以上,并认识“辛普森悖论”——忽略第三个变量可能导致完全相反的结论。
  • 实战应用与陷阱:通过真实案例(如死刑判决与肤色),深刻理解条件独立性的概念及数据分析中考虑所有相关维度的重要性。

二维列联表与独立性假设

在上一节的拟合优度检验中,我们处理的是单个分类变量的分布是否符合某个理论分布。然而,许多实际问题涉及两个或多个分类变量。例如,研究性别(男、女)与是否色盲(正常、色盲)的关系。用于展示这类两个分类变量交叉分类频数的表格,称为二维列联表

二维列联表的定义与记号

设我们有两个分类指标 AABB。指标 AArr 个水平(A1,A2,,ArA_1, A_2, \dots, A_r),指标 BBss 个水平(B1,B2,,BsB_1, B_2, \dots, B_s)。从总体中抽取 nn 个样本,记录每个样本在 AABB 上的类别。以 nijn_{ij} 表示属于 AiA_i 且属于 BjB_j 的样本个数(观测频数)。将所有 nijn_{ij} 排列成的 r×sr \times s 表格,即为二维列联表。

B1B_1B2B_2\cdotsBsB_s行和
A1A_1n11n_{11}n12n_{12}\cdotsn1sn_{1s}n1n_{1\cdot}
A2A_2n21n_{21}n22n_{22}\cdotsn2sn_{2s}n2n_{2\cdot}
\vdots\vdots\vdots\ddots\vdots\vdots
ArA_rnr1n_{r1}nr2n_{r2}\cdotsnrsn_{rs}nrn_{r\cdot}
列和n1n_{\cdot 1}n2n_{\cdot 2}\cdotsnsn_{\cdot s}nn

其中,行和与列和定义为: ni=j=1snij,nj=i=1rnij,n=i=1rj=1snij.n_{i\cdot} = \sum_{j=1}^{s} n_{ij}, \quad n_{\cdot j} = \sum_{i=1}^{r} n_{ij}, \quad n = \sum_{i=1}^{r}\sum_{j=1}^{s} n_{ij}.

pij=P(AiBj)p_{ij} = P(A_i \cap B_j) 为样本同时属于 AiA_iBjB_j 的概率。相应的边缘概率为: pi=j=1spij=P(Ai),pj=i=1rpij=P(Bj).p_{i\cdot} = \sum_{j=1}^{s} p_{ij} = P(A_i), \quad p_{\cdot j} = \sum_{i=1}^{r} p_{ij} = P(B_j).

独立性假设

我们感兴趣的问题是:指标 AA 和指标 BB 是否相互独立? 根据概率论,若 AABB 独立,则对任意 i,ji, j,有: P(AiBj)=P(Ai)P(Bj).P(A_i \cap B_j) = P(A_i) P(B_j).

因此,检验两个变量独立性的原假设与备择假设可表述为: H0:pij=pipj,对所有 i=1,,r;j=1,,s.H1:至少存在一对 (i,j) 使得 pijpipj.\begin{aligned} H_0: & \quad p_{ij} = p_{i\cdot} p_{\cdot j}, \quad \text{对所有 } i=1,\dots,r;, j=1,\dots,s. \ H_1: & \quad \text{至少存在一对 } (i,j) \text{ 使得 } p_{ij} \neq p_{i\cdot} p_{\cdot j}. \end{aligned}

卡方独立性检验

我们可以将列联表中的 nn 个观测视为来自多项分布 Multinomial(n;p11,p12,,prs)\text{Multinomial}(n; p_{11}, p_{12}, \dots, p_{rs}) 的一个样本。检验 H0H_0 本质上是一个拟合优度检验:检验观测频数 nijn_{ij} 是否与独立假设下的理论频数相吻合。

理论频数的估计

在原假设 H0H_0 下,pij=pipjp_{ij} = p_{i\cdot} p_{\cdot j}。然而,边缘概率 pip_{i\cdot}pjp_{\cdot j} 通常是未知的,需要从数据中估计。根据多项分布的性质,其极大似然估计(MLE)为样本比例: p^i=nin,p^j=njn.\hat{p}{i\cdot} = \frac{n{i\cdot}}{n}, \quad \hat{p}{\cdot j} = \frac{n{\cdot j}}{n}.

因此,在原假设下,单元格 (i,j)(i, j)理论频数估计值为: e^ij=np^ip^j=nninnjn=ninjn.\hat{e}{ij} = n \cdot \hat{p}{i\cdot} \cdot \hat{p}{\cdot j} = n \cdot \frac{n{i\cdot}}{n} \cdot \frac{n_{\cdot j}}{n} = \frac{n_{i\cdot} \cdot n_{\cdot j}}{n}.

检验统计量及其分布

仿照 Pearson 卡方拟合优度检验,我们构造统计量,衡量观测频数 nijn_{ij} 与理论频数估计值 e^ij\hat{e}{ij} 之间的总体差异: T=i=1rj=1s(nije^ij)2e^ij.T = \sum{i=1}^{r} \sum_{j=1}^{s} \frac{(n_{ij} - \hat{e}{ij})^2}{\hat{e}{ij}}.

在原假设 H0H_0 成立且样本量 nn 足够大时,统计量 TT 近似服从自由度为 (r1)(s1)(r-1)(s-1) 的卡方分布: Taχ(r1)(s1)2.T \stackrel{a}{\sim} \chi^2_{(r-1)(s-1)}.

自由度推导:拟合优度检验的自由度计算公式为:自由度 = 组数 - 1 - 估计的参数个数。

  1. 总组数(单元格数)为 r×sr \times s
  2. 在原假设下,我们需要估计的参数是 p1,,prp_{1\cdot}, \dots, p_{r\cdot}p1,,psp_{\cdot 1}, \dots, p_{\cdot s}。但它们满足两个约束条件:ipi=1\sum_i p_{i\cdot}=1jpj=1\sum_j p_{\cdot j}=1。因此,独立参数的个数为 (r1)+(s1)(r-1) + (s-1)
  3. 代入公式:自由度=rs1[(r1)+(s1)]=rsrs+1=(r1)(s1)\text{自由度} = rs - 1 - [(r-1)+(s-1)] = rs - r - s + 1 = (r-1)(s-1)

检验步骤与案例回顾

以“性别与色盲”的经典案例(r=2,s=2r=2, s=2)为例,检验步骤如下:

  1. 建立假设H0H_0:性别与是否色盲相互独立;H1H_1:不独立。
  2. 计算理论频数:利用公式 e^ij=(ninj)/n\hat{e}{ij} = (n{i\cdot} n_{\cdot j}) / n 计算每个单元格的理论频数。
  3. 计算检验统计量T=i,j(nije^ij)2/e^ijT = \sum_{i,j} (n_{ij} - \hat{e}{ij})^2 / \hat{e}{ij}
  4. 确定拒绝域:给定显著性水平 α\alpha(如 0.05),拒绝域为 T>χ(r1)(s1),α2T > \chi^2_{(r-1)(s-1), \alpha}
  5. 做出决策:若 TT 落入拒绝域,则拒绝 H0H_0,认为两个变量不独立(即有关联)。

在该案例中,计算得 T27.14T \approx 27.14,自由度为 1,在 α=0.01\alpha=0.01 水平下 χ1,0.0126.64\chi^2_{1, 0.01} \approx 6.64。由于 27.14>6.6427.14 > 6.64,我们拒绝原假设,认为性别与色盲存在显著关联。从数据上看,男性色盲比例(38/4807.9%38/480 \approx 7.9%)显著高于女性色盲比例(6/5201.2%6/520 \approx 1.2%)。

import numpy as np
from scipy.stats import chi2_contingency, chi2

# 性别与色盲的观测数据 (2x2列联表)
# 行:性别 (男, 女)
# 列:色盲 (正常, 色盲)
observed = np.array([[442, 38],
                     [514, 6]])

# 使用scipy进行卡方独立性检验
chi2_stat, p_value, dof, expected = chi2_contingency(observed, correction=False) # 不进行连续性校正

print("观测频数表:")
print(observed)
print("\n理论频数表(在原假设下):")
print(expected)
print(f"\n卡方统计量 T = {chi2_stat:.4f}")
print(f"自由度 df = {dof}")
print(f"P值 = {p_value:.6f}")

# 手动计算卡方统计量以验证
n = observed.sum()
row_totals = observed.sum(axis=1)
col_totals = observed.sum(axis=0)
expected_manual = np.outer(row_totals, col_totals) / n
chi2_manual = ((observed - expected_manual)**2 / expected_manual).sum()

print(f"\n手动计算的理论频数:")
print(expected_manual)
print(f"手动计算的卡方统计量 T = {chi2_manual:.4f}")

# 判断在alpha=0.01水平下是否拒绝原假设
alpha = 0.01
critical_value = chi2.ppf(1 - alpha, dof)
print(f"\n显著性水平 α = {alpha} 下的临界值:χ²({dof}, {alpha}) = {critical_value:.4f}")
if chi2_stat > critical_value:
    print(f"结论:由于 T ({chi2_stat:.4f}) > {critical_value:.4f},拒绝原假设,认为性别与色盲不独立。")
else:
    print(f"结论:无法拒绝原假设。")

高维列联表与条件独立性

现实问题往往更加复杂,可能涉及三个或更多分类变量。此时,我们面对的是高维列联表。对高维列联表的分析,不仅能检验完全独立性,还能检验更有趣的条件独立性

三维列联表的问题类型

假设有三个分类指标 AArr 水平)、BBss 水平)、CCtt 水平),观测频数为 nijkn_{ijk}。我们可能关心三类假设:

  1. 完全独立A,B,CA, B, C 三者相互独立,即 P(AiBjCk)=P(Ai)P(Bj)P(Ck)P(A_i \cap B_j \cap C_k) = P(A_i)P(B_j)P(C_k)
  2. 边缘独立:一个变量与另两个变量的联合独立,例如 AA(B,C)(B, C) 独立,即 P(AiBjCk)=P(Ai)P(BjCk)P(A_i \cap B_j \cap C_k) = P(A_i)P(B_j \cap C_k)
  3. 条件独立:在给定第三个变量的条件下,另两个变量独立。例如,给定 CC 的条件下 AABB 独立,即 P(AiBjCk)=P(AiCk)P(BjCk)P(A_i \cap B_j | C_k) = P(A_i | C_k) P(B_j | C_k),对所有 kk 成立。

前两类问题可以转化为二维列联表的检验。第三类条件独立性检验在实践中尤为重要。

条件独立性检验的似然比检验

考虑原假设 H0H_0:给定 CC 的条件下,AABB 独立。 在原假设下,联合概率可分解为: pijk=P(Ck)P(AiCk)P(BjCk).p_{ijk} = P(C_k) \cdot P(A_i | C_k) \cdot P(B_j | C_k).

利用多项分布 MLE 的性质,可以得到原假设下 pijkp_{ijk} 的估计量为: p^ijk(0)=nknniknknjknk=niknjknnk.\hat{p}{ijk}^{(0)} = \frac{n{\cdot \cdot k}}{n} \cdot \frac{n_{i \cdot k}}{n_{\cdot \cdot k}} \cdot \frac{n_{\cdot j k}}{n_{\cdot \cdot k}} = \frac{n_{i \cdot k} \cdot n_{\cdot j k}}{n \cdot n_{\cdot \cdot k}}.

对应的理论频数估计值为: e^ijk=np^ijk(0)=niknjknk.\hat{e}{ijk} = n \cdot \hat{p}{ijk}^{(0)} = \frac{n_{i \cdot k} \cdot n_{\cdot j k}}{n_{\cdot \cdot k}}.

在全模型(无约束)下,pijkp_{ijk} 的 MLE 为 p^ijk=nijk/n\hat{p}{ijk} = n{ijk} / n。 我们可以构造似然比统计量(或使用 Pearson 卡方统计量)进行检验。在大样本下,有: 2lnΛ=2i=1rj=1sk=1tnijkln(nijke^ijk)aχν2.-2 \ln \Lambda = 2 \sum_{i=1}^{r}\sum_{j=1}^{s}\sum_{k=1}^{t} n_{ijk} \ln\left(\frac{n_{ijk}}{\hat{e}{ijk}}\right) \stackrel{a}{\sim} \chi^2{\nu}.

其自由度 ν\nu 为: ν=rst1[(r1)t+(s1)t+(t1)]=(r1)(s1)t.\nu = rst - 1 - [ (r-1)t + (s-1)t + (t-1) ] = (r-1)(s-1)t. 推导逻辑与二维类似:总组数 rstrst,减去 1,再减去在原假设下需要估计的参数个数(给定每个 CkC_k 后,AA 的条件分布有 r1r-1 个自由参数,BB 的条件分布有 s1s-1 个自由参数,CC 的边缘分布有 t1t-1 个自由参数)。

辛普森悖论:一个警示性案例

一个著名的案例是 1970 年代美国佛罗里达州死刑判决的数据分析。

  • 二维分析:仅考虑被告肤色(白人/黑人)与是否判死刑,数据显示白人被告被判死刑的比例(11.9%)略高于黑人被告(10.2%),结论似乎是“不存在对黑人的歧视”。
  • 三维分析:加入被害人肤色作为第三个变量后,数据被拆分为两个二维表(被害人白人和被害人黑人)。分析发现:
    • 当被害人是白人时,黑人被告被判死刑的比例(17.5%)显著高于白人被告(12.6%)。
    • 当被害人是黑人时,黑人被告被判死刑的比例(5.8%)仍高于白人被告(0%)。
  • 结论反转:在控制被害人肤色这个条件后,在每一个子群体中,黑人被告都比白人被告更可能被判死刑。这揭示了潜在的种族歧视,而这一结论在忽略被害人肤色时被完全掩盖。

这种现象被称为辛普森悖论:在忽略一个重要变量(如被害人肤色)进行聚合分析时,可能会得到与分组分析(条件分析)完全相反的结论。它强烈警示我们,在进行关联性分析时,必须审慎考虑所有可能相关的变量,高维列联表分析是揭示复杂真相的关键工具。

import pandas as pd
import numpy as np
from scipy.stats import chi2_contingency

# 模拟死刑判决数据(基于案例描述简化)
# 维度:被告肤色 (0:白人, 1:黑人), 被害人肤色 (0:白人, 1:黑人), 判决 (0:非死刑, 1:死刑)
np.random.seed(321) # 固定随机种子
n = 1000

# 设置条件概率以反映案例中的模式
# P(死刑 | 被告, 被害人)
death_prob = {
    (0, 0): 0.126, # 白人被告,白人被害人
    (0, 1): 0.000, # 白人被告,黑人被害人
    (1, 0): 0.175, # 黑人被告,白人被害人
    (1, 1): 0.058, # 黑人被告,黑人被害人
}

# 生成数据
data = []
for i in range(n):
    # 随机生成被告和被害人肤色(这里简化,假设独立且等概率)
    defendant = np.random.choice([0, 1])
    victim = np.random.choice([0, 1])
    prob = death_prob[(defendant, victim)]
    death = np.random.binomial(1, prob)
    data.append([defendant, victim, death])

df = pd.DataFrame(data, columns=['defendant', 'victim', 'death'])

print("=== 三维列联表(被告 x 被害人 x 判决)===")
# 使用pandas的crosstab创建三维视图(两层)
print(pd.crosstab([df['defendant'], df['victim']], df['death'], margins=True))
print("\n")

print("=== 忽略被害人肤色:二维分析(被告 x 判决)===")
table_2d = pd.crosstab(df['defendant'], df['death'], margins=True)
print(table_2d)
chi2_2d, p_2d, dof_2d, exp_2d = chi2_contingency(table_2d.iloc[:2, :2], correction=False)
print(f"卡方独立性检验:χ²={chi2_2d:.3f}, p值={p_2d:.3f}, 自由度={dof_2d}")
if p_2d < 0.05:
    print("结论:在0.05水平下,被告肤色与判决显著相关。")
else:
    print("结论:在0.05水平下,无法拒绝被告肤色与判决独立的假设。")
print("\n")

print("=== 控制被害人肤色:分层二维分析 ===")
for victim_val in [0, 1]:
    victim_label = '白人' if victim_val == 0 else '黑人'
    subset = df[df['victim'] == victim_val]
    print(f"--- 被害人肤色: {victim_label} ---")
    table_sub = pd.crosstab(subset['defendant'], subset['death'], margins=True)
    print(table_sub)
    if table_sub.iloc[:2, :2].shape == (2,2): # 确保是2x2表
        chi2_sub, p_sub, dof_sub, exp_sub = chi2_contingency(table_sub.iloc[:2, :2], correction=False)
        print(f"条件独立性检验:χ²={chi2_sub:.3f}, p值={p_sub:.3f}")
        if p_sub < 0.05:
            print(f"结论:当被害人为{victim_label}时,被告肤色与判决显著相关。")
        else:
            print(f"结论:当被害人为{victim_label}时,无法拒绝条件独立的假设。")
    print()

📝 动手练一练

  1. 产品满意度调查:某公司对两款产品(A和B)在三个地区(东、西、中部)进行用户满意度调查(满意、一般、不满意),得到如下观测频数表。试问在 0.05 显著性水平下,产品类型与用户满意度是否独立?

    满意一般不满意合计
    产品 A1206020200
    产品 B908030200
    合计21014050400

    参考答案: 首先计算理论频数 e^ij=(ninj)/n\hat{e}{ij} = (n{i\cdot} n_{\cdot j}) / n。 例如,产品A且满意的理论频数 e^11=(200×210)/400=105\hat{e}_{11} = (200 \times 210) / 400 = 105。 类似计算其他单元格,得到理论频数表:

    满意一般不满意
    产品 A1057025
    产品 B1057025
    计算卡方统计量:
    χ2=(120105)2105+(90105)2105+(6070)270+(8070)270+(2025)225+(3025)2259.143.\chi^2 = \frac{(120-105)^2}{105} + \frac{(90-105)^2}{105} + \frac{(60-70)^2}{70} + \frac{(80-70)^2}{70} + \frac{(20-25)^2}{25} + \frac{(30-25)^2}{25} \approx 9.143.
    自由度 (r1)(s1)=(21)(31)=2(r-1)(s-1) = (2-1)(3-1)=2。查表得 χ2,0.0525.991\chi^2_{2, 0.05} \approx 5.991
    由于 9.143>5.9919.143 > 5.991,拒绝原假设,认为产品类型与用户满意度不独立。
  2. 三维列联表思考:在“死刑判决”案例中,如果我们想检验“在控制被告肤色的条件下,被害人肤色与判决是否独立”,应该如何表述原假设 H0H_0?并简述检验的基本思路。 参考答案: 原假设 H0H_0:给定被告肤色的条件下,被害人肤色与判决结果相互独立。即对所有被告肤色 dd,有 P(被害人肤色,判决被告肤色=d)=P(被害人肤色被告肤色=d)P(判决被告肤色=d)P(\text{被害人肤色}, \text{判决} | \text{被告肤色}=d) = P(\text{被害人肤色} | \text{被告肤色}=d) \cdot P(\text{判决} | \text{被告肤色}=d)。 基本思路:将数据按被告肤色分层,在每一层内(例如,仅白人被告的数据)构建一个关于被害人肤色与判决的二维列联表,并分别进行卡方独立性检验。也可以使用统一的似然比检验统计量,其自由度推导需考虑在给定被告肤色下,需要估计的条件概率参数个数。

本章小结

本节深入探讨了列联表分析的核心——独立性检验。

要点回顾

  1. 二维列联表是分析两个分类变量关联性的基础工具。其独立性检验通过比较观测频数与基于独立假设估计的理论频数来实现。
  2. 卡方检验统计量 T=(OE)2/ET = \sum (O-E)^2/E 在原假设下渐近服从自由度为 (r1)(s1)(r-1)(s-1) 的卡方分布。自由度的确定遵循“组数-1-估计参数个数”的原则。
  3. 高维列联表分析能揭示更复杂的变量关系,特别是条件独立性。给定第三个变量 CC 后,AABB 的条件独立性检验具有重要的实际意义。
  4. 辛普森悖论是一个关键警示:忽略潜在的重要混杂变量进行聚合分析,可能导致完全错误甚至相反的结论。在数据分析中,必须警惕并主动探索高维关联。

行动清单

  • 下次当你面对两个分类变量,想探究“它们有关系吗?”时,立刻想到构建列联表并计算卡方独立性检验。
  • 在报告关联性分析结果前,务必思考:“是否有其他重要的变量(如时间、地域、用户群体等)可能影响当前结论?”并尝试进行分层或高维分析。
  • 使用 Python 的 scipy.stats.chi2_contingency 函数可以快速完成二维列联表的卡方检验。对于高维分析,熟练掌握 pandas.crosstab 进行数据透视和分层是关键第一步。

— 小象教研组

配套学习资源与课件
  • 第5章课件:分布的检验(PDF · 3.8MB)
    下载
🎁 免费学习资源

领取《小象 11GB VIP 课件资料包与大厂真题手册》

包含全套实战 Jupyter 源码、清洗后数据集、大厂高频面试真题与专属学员答疑交流群。

  • 完整 Python / 数据分析 Jupyter 实战源码
  • 大厂真实业务数据集与练习题
  • 微信扫码添加课程顾问,免费获取网盘下载链接
微信二维码:扫码添加课程顾问微信扫码添加顾问