4. 单变量特征选择(卡方检验)
卡方检验(Chi-Square Test)是一种经典的统计假设检验方法,在特征工程中常用于衡量类别型特征与类别型目标变量之间的相关性。它通过计算观测频数与期望频数之间的偏差,判断两个变量是否独立,从而筛选出对分类任务最有价值的特征。
4.1 卡方检验原理
卡方检验的核心思想是:如果两个变量相互独立,那么观测频数应该与期望频数非常接近;如果偏差很大,则说明变量之间存在关联。检验统计量计算公式如下:
卡方统计量公式:
χ² = Σ [(Oi - Ei)² / Ei]
其中:
- Oi:第 i 个单元格的观测频数
- Ei:第 i 个单元格的期望频数(在独立假设下计算)
- 求和遍历所有单元格(特征取值 × 类别取值)
期望频数 Ei 的计算方式为:
Ei = (行合计 × 列合计) / 总样本数
卡方值越大,说明观测值与期望值差异越大,原假设(变量独立)越可能被拒绝,即特征与目标变量的关联性越强。在特征选择中,我们通常选择卡方统计量较大(或 p 值较小)的特征。
适用条件:卡方检验要求特征和目标变量均为离散型(类别型)数据。对于连续型特征,需要先进行分箱(离散化)处理,或改用方差分析(ANOVA)等其他方法。
4.2 适用于分类问题的特征选择
卡方检验特别适合以下场景:
- 文本分类:词频或 TF-IDF 特征与文档类别之间的关联筛选
- 离散特征筛选:如性别、地区、职业等级等类别变量与二分类/多分类目标
- 高维稀疏数据:如 One-Hot 编码后的特征矩阵,卡方检验计算效率高
下表总结了卡方检验与其他单变量筛选方法的对比:
| 方法 | 特征类型 | 目标类型 | 适用场景 |
|---|---|---|---|
| 卡方检验 | 类别型 | 类别型 | 分类问题,离散特征筛选 |
| 方差分析(ANOVA) | 连续型 | 类别型 | 分类问题,连续特征筛选 |
| 皮尔逊相关系数 | 连续型 | 连续型 | 回归问题,线性关系检测 |
| 互信息 | 任意 | 任意 | 非线性关系检测,通用 |
注意事项:卡方检验对样本量敏感。当某个单元格的期望频数小于 5 时,卡方近似可能不准确,此时建议使用 Fisher 精确检验或合并稀疏类别。
4.3 Python 实现:SelectKBest + chi2
在 scikit-learn 中,SelectKBest 配合 chi2 评分函数可以快速实现基于卡方检验的特征选择。以下是一个完整的实现示例:
# 导入所需库
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.preprocessing import LabelBinarizer
# 加载示例数据(Iris 数据集)
iris = load_iris()
X = iris.data # 特征矩阵(连续值)
y = iris.target # 目标变量(3 个类别)
# 注意:chi2 要求特征为非负值,这里对特征进行 Min-Max 缩放
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
# 使用 SelectKBest + chi2 选择 Top-2 特征
selector = SelectKBest(score_func=chi2, k=2)
X_selected = selector.fit_transform(X_scaled, y)
# 输出结果
print("原始特征数量:", X.shape[1])
print("筛选后特征数量:", X_selected.shape[1])
print("\n各特征卡方统计量:")
for i, score in enumerate(selector.scores_):
print(f" 特征 {i+1} ({iris.feature_names[i]}): χ² = {score:.4f}")
print("\n各特征 p 值:")
for i, pval in enumerate(selector.pvalues_):
print(f" 特征 {i+1} ({iris.feature_names[i]}): p = {pval:.6f}")
print("\n被选中的特征索引:", selector.get_support(indices=True))
print("被选中的特征名称:", [iris.feature_names[i] for i in selector.get_support(indices=True)])
输出示例:
原始特征数量: 4
筛选后特征数量: 2
各特征卡方统计量:
特征 1 (sepal length (cm)): χ² = 10.8178
特征 2 (sepal width (cm)): χ² = 3.7107
特征 3 (petal length (cm)): χ² = 116.3126
特征 4 (petal width (cm)): χ² = 67.0484
各特征 p 值:
特征 1 (sepal length (cm)): p = 0.004477
特征 2 (sepal width (cm)): p = 0.156402
特征 3 (petal length (cm)): p = 0.000000
特征 4 (petal width (cm)): p = 0.000000
被选中的特征索引: [2 3]
被选中的特征名称: ['petal length (cm)', 'petal width (cm)']
4.4 关键参数与调优建议
| 参数 | 说明 | 建议 |
|---|---|---|
| k | 保留的特征数量 | 根据特征总数和模型复杂度调整,常用 10~50 |
| score_func | 评分函数 | 分类问题用 chi2 或 f_classif |
| p 值阈值 | 显著性水平 | 常用 0.05 或 0.01,可结合 Bonferroni 校正 |
实用技巧:
- 对于文本分类任务,可以先使用
CountVectorizer或TfidfVectorizer生成词频矩阵,再应用卡方检验筛选关键词特征。 - 如果特征数量非常大(如 > 10000),可以先使用卡方检验快速筛选到 500~1000 个特征,再结合其他方法(如 L1 正则化)进一步精筛。
- 卡方检验对稀疏矩阵支持良好,适合处理 One-Hot 编码后的高维稀疏数据。
4.5 常见问题与避坑指南
- 特征必须为非负值:
chi2评分函数要求输入特征为非负,否则会报错。使用前需进行 Min-Max 缩放或绝对值处理。 - 稀疏矩阵支持:
SelectKBest + chi2原生支持 scipy 稀疏矩阵,无需额外转换,适合文本分类等高维稀疏场景。 - 多重比较问题:当同时检验大量特征时,p 值可能因多重比较而膨胀。可考虑使用 Bonferroni 校正或 FDR(错误发现率)控制。
- 特征间相关性:卡方检验是单变量方法,无法处理特征间的冗余和交互作用。筛选后建议结合模型特征重要性或递归特征消除(RFE)进一步优化。
重要提醒:卡方检验仅衡量特征与目标之间的独立性强弱,并不保证筛选出的特征组合在模型中表现最优。建议将卡方检验作为初步筛选步骤,后续再结合交叉验证和模型性能评估进行最终特征选择。