特征选择入门:单变量特征选择|原理+方法+Python实战全攻略

单变量特征选择是机器学习中最简单、最高效的特征筛选方法,核心逻辑是“逐个评估每个特征与目标变量的相关性”,筛选出对预测结果最有用的特征。它无需复杂模型,仅通过统计检验就能完成筛选,适合作为特征选择的“第一步”或“快速粗筛工具”。


一、单变量特征选择是什么?一句话看懂

单变量特征选择 = 对每个特征“单独打分”,只留分数高的特征。

核心逻辑:

  • 不考虑特征之间的相互关系,只看“单个特征”与“目标变量”的关联强度
  • 用统计方法给每个特征评一个“重要性分数”
  • 按分数排序,筛选出Top K个或分数达标的特征

形象比喻:招聘筛选简历

目标变量是“是否录用”,每个特征是简历上的一项(学历、工作年限、技能证书等):

  • 单变量特征选择就像HR逐个看每项指标:“学历是否达标?”“工作年限够不够?”
  • 只保留“单项表现好”的指标(特征),忽略单项表现差的,最终形成“合格简历清单”(筛选后的特征集)

二、3种核心方法(必学)

根据特征类型(分类/连续)和任务类型(分类/回归),选择对应的统计方法:

1. 卡方检验(Chi-square Test)

适用场景
  • 特征是分类变量(如性别:男/女、学历:本科/硕士)
  • 目标变量是分类变量(如是否购买:是/否、疾病类型:A/B/C)
核心原理

检验“特征类别”与“目标类别”是否独立:

  • 假设特征与目标独立(无关联),计算“实际观测频数”与“理论期望频数”的差异
  • 差异越大(卡方统计量越大),说明特征与目标关联越强
公式(简单理解)

χ2=∑(Oij−Eij)2Eij \chi^2 = \sum \frac{(O_{ij} - E_{ij})^2}{E_{ij}} χ2=Eij(OijEij)2

  • OijO_{ij}Oij:实际观测频数(如“男性+购买”的人数)
  • EijE_{ij}Eij:理论期望频数(假设独立时,“男性+购买”的预期人数),计算方式:
    Eij=行合计×列合计总样本数E_{ij} = \frac{行合计 \times 列合计}{总样本数}Eij=总样本数行合计×列合计
选择规则
  • 卡方统计量越大 → 特征越重要
  • p值 < 0.05 → 特征与目标显著相关,保留;反之剔除

2. F检验(F-test/ANOVA)

适用场景
  • 特征是连续变量(如收入、年龄、成绩)
  • 目标变量是分类变量(如客户等级:高/中/低、疾病是否发生:是/否)
核心原理

通过方差分析判断“不同类别下,特征的均值是否有显著差异”:

  • 组间方差:不同类别间的特征均值差异(如高、中、低客户的收入均值差异)
  • 组内方差:同一类别内的特征波动(如高客户内部的收入波动)
  • F值 = 组间方差 / 组内方差 → F值越大,说明类别间差异越显著,特征越重要
公式(简单理解)

F=组间方差组内方差 F = \frac{组间方差}{组内方差} F=组内方差组间方差

  • 组间方差:衡量类别间差异,∑i=1kni(Xˉi−Xˉ)2k−1\frac{\sum_{i=1}^k n_i (\bar{X}_i - \bar{X})^2}{k-1}k1i=1kni(XˉiXˉ)2(k=类别数,nin_ini=第i类样本数)
  • 组内方差:衡量类别内波动,∑i=1k∑j=1ni(Xij−Xˉi)2N−k\frac{\sum_{i=1}^k \sum_{j=1}^{n_i} (X_{ij} - \bar{X}_i)^2}{N-k}Nki=1kj=1ni(XijXˉi)2(N=总样本数)
选择规则
  • F值越大 → 特征越重要
  • p值 < 0.05 → 特征与目标显著相关,保留;反之剔除

3. 互信息(Mutual Information)

适用场景
  • 特征和目标变量不限类型(分类/连续均可)
  • 存在非线性关系(如特征与目标是U型、对数关系)
核心原理

衡量两个变量之间的“信息共享程度”:

  • 互信息越大,说明特征包含的“关于目标的信息”越多,关联越强
  • 不依赖线性假设,能捕捉复杂非线性关系
公式(简单理解)

I(X;Y)=∑x∈X∑y∈Yp(x,y)log⁡p(x,y)p(x)p(y) I(X;Y) = \sum_{x \in X} \sum_{y \in Y} p(x,y) \log \frac{p(x,y)}{p(x)p(y)} I(X;Y)=xXyYp(x,y)logp(x)p(y)p(x,y)

  • p(x,y)p(x,y)p(x,y):特征X和目标Y的联合概率(同时取x和y的概率)
  • p(x)p(x)p(x)p(y)p(y)p(y):特征X和目标Y的边缘概率(各自取某值的概率)
选择规则
  • 互信息值越大 → 特征越重要,按值排序选择Top K个

方法选择速查表(直接照选)

特征类型 目标类型 推荐方法
分类特征 分类目标 卡方检验
连续特征 分类目标 F检验(ANOVA)
任意特征 任意目标(含非线性) 互信息
连续特征 回归目标 皮尔逊相关系数(单变量扩展)

三、单变量特征选择完整流程(必背)

  1. 数据预处理
    • 区分特征类型(分类/连续)和目标类型(分类/回归)
    • 处理缺失值(填充/删除)
    • 连续特征标准化(F检验、互信息等方法对尺度敏感)
  2. 选择统计方法:按上述速查表选择卡方检验、F检验或互信息
  3. 计算特征分数:对每个特征单独计算统计量(卡方值、F值、互信息值)和p值
  4. 筛选特征
    • 按分数排序,选择Top K个(如Top 10)
    • 按p值筛选,保留p < 0.05的特征(卡方/F检验)
  5. 模型训练与评估:用筛选后的特征训练模型,对比筛选前后的性能

四、Python 完整实战:葡萄酒分类特征选择

1. 导入库+加载数据

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectKBest, f_classif, chi2, mutual_info_classif
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score

# 加载葡萄酒数据集(13个特征,3类目标)
wine = load_wine()
X = pd.DataFrame(wine.data, columns=wine.feature_names)
y = pd.Series(wine.target, name='wine_type')

print("样本数:", X.shape[0])
print("特征数:", X.shape[1])
print("特征名:", list(X.columns))
print("目标类别:", list(wine.target_names))
X.head()

2. 数据预处理(拆分+标准化)

# 1. 拆分训练集/测试集(7:3)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

# 2. 标准化连续特征(F检验、互信息需标准化)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 转换为DataFrame(方便后续查看)
X_train_scaled = pd.DataFrame(X_train_scaled, columns=X.columns)
X_test_scaled = pd.DataFrame(X_test_scaled, columns=X.columns)

3. 方法1:F检验(连续特征+分类目标)

# 1. 初始化选择器:选择Top 10个最重要特征
selector_f = SelectKBest(score_func=f_classif, k=10)
X_train_f = selector_f.fit_transform(X_train_scaled, y_train)
X_test_f = selector_f.transform(X_test_scaled)

# 2. 查看结果
selected_features_f = X.columns[selector_f.get_support()]
feature_scores_f = pd.Series(selector_f.scores_[selector_f.get_support()], index=selected_features_f)
feature_pvalues_f = pd.Series(selector_f.pvalues_[selector_f.get_support()], index=selected_features_f)

print("=== F检验筛选的特征 ===")
print("选择的特征:", list(selected_features_f))
print("\n特征分数(F值):")
print(feature_scores_f.sort_values(ascending=False))
print("\n特征p值:")
print(feature_pvalues_f.sort_values(ascending=True))

4. 方法2:互信息(捕捉非线性关系)

# 1. 初始化选择器:选择Top 10个最重要特征
selector_mi = SelectKBest(score_func=mutual_info_classif, k=10)
X_train_mi = selector_mi.fit_transform(X_train_scaled, y_train)
X_test_mi = selector_mi.transform(X_test_scaled)

# 2. 查看结果
selected_features_mi = X.columns[selector_mi.get_support()]
feature_scores_mi = pd.Series(selector_mi.scores_[selector_mi.get_support()], index=selected_features_mi)

print("\n=== 互信息筛选的特征 ===")
print("选择的特征:", list(selected_features_mi))
print("\n特征互信息值:")
print(feature_scores_mi.sort_values(ascending=False))

5. 特征分数可视化

# 可视化F检验特征分数
plt.figure(figsize=(12, 6))
feature_scores_f.sort_values().plot(kind='barh', color='skyblue')
plt.title("F检验特征重要性分数", fontsize=12)
plt.xlabel("F值(越大越重要)")
plt.grid(alpha=0.3, axis='x')
plt.tight_layout()
plt.show()

# 可视化互信息特征分数
plt.figure(figsize=(12, 6))
feature_scores_mi.sort_values().plot(kind='barh', color='lightcoral')
plt.title("互信息特征重要性分数", fontsize=12)
plt.xlabel("互信息值(越大越重要)")
plt.grid(alpha=0.3, axis='x')
plt.tight_layout()
plt.show()

6. 模型训练与性能对比

# 定义训练评估函数
def train_evaluate(X_train, X_test, y_train, y_test, title):
    model = LogisticRegression(max_iter=1000, random_state=42)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    print(f"\n=== {title} ===")
    print(f"准确率: {acc:.4f}")
    print("分类报告:")
    print(classification_report(y_test, y_pred, target_names=wine.target_names))
    return acc

# 1. 原始特征(13个)训练
acc_original = train_evaluate(X_train_scaled, X_test_scaled, y_train, y_test, "原始特征模型")

# 2. F检验筛选后(10个)训练
acc_f = train_evaluate(X_train_f, X_test_f, y_train, y_test, "F检验筛选后模型")

# 3. 互信息筛选后(10个)训练
acc_mi = train_evaluate(X_train_mi, X_test_mi, y_train, y_test, "互信息筛选后模型")

# 对比结果
print("\n=== 性能对比 ===")
print(f"原始特征准确率: {acc_original:.4f}")
print(f"F检验筛选准确率: {acc_f:.4f}")
print(f"互信息筛选准确率: {acc_mi:.4f}")

7. 优化:选择最优特征数量K

# 测试不同K值(5-13)的性能
k_values = list(range(5, X.shape[1]+1))
acc_scores = []

for k in k_values:
    # F检验选择K个特征
    selector = SelectKBest(score_func=f_classif, k=k)
    X_train_k = selector.fit_transform(X_train_scaled, y_train)
    X_test_k = selector.transform(X_test_scaled)
    
    # 训练模型
    model = LogisticRegression(max_iter=1000, random_state=42)
    model.fit(X_train_k, y_train)
    acc = accuracy_score(y_test, model.predict(X_test_k))
    acc_scores.append(acc)

# 可视化K值与准确率关系
plt.figure(figsize=(10, 6))
plt.plot(k_values, acc_scores, marker='o', color='green', linewidth=2)
plt.title("特征数量K与模型准确率关系", fontsize=12)
plt.xlabel("选择的特征数量K")
plt.ylabel("测试集准确率")
plt.xticks(k_values)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

# 最优K值
best_k = k_values[np.argmax(acc_scores)]
best_acc = max(acc_scores)
print(f"\n最优特征数量K: {best_k}")
print(f"最优准确率: {best_acc:.4f}")

8. 混淆矩阵可视化(最优模型)

# 用最优K值训练模型
selector_best = SelectKBest(score_func=f_classif, k=best_k)
X_train_best = selector_best.fit_transform(X_train_scaled, y_train)
X_test_best = selector_best.transform(X_test_scaled)

model_best = LogisticRegression(max_iter=1000, random_state=42)
model_best.fit(X_train_best, y_train)
y_pred_best = model_best.predict(X_test_best)

# 绘制混淆矩阵
cm = confusion_matrix(y_test, y_pred_best)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=wine.target_names, yticklabels=wine.target_names)
plt.title(f"最优模型混淆矩阵(K={best_k})", fontsize=12)
plt.xlabel("预测类别")
plt.ylabel("真实类别")
plt.tight_layout()
plt.show()

五、单变量特征选择的优缺点(必背)

优点

  1. 简单易懂:原理基于基础统计检验,本科生也能快速理解
  2. 计算高效:逐个评估特征,无复杂迭代,适合中小型数据集
  3. 适用性广:支持分类/回归任务,可搭配卡方、F检验、互信息等多种方法
  4. 快速粗筛:能快速剔除完全无关的特征,减少后续建模复杂度
  5. 无模型依赖:不依赖复杂模型,仅通过统计量就能筛选,结果稳定

缺点

  1. 忽略特征交互:独立评估每个特征,无法捕捉“特征A+特征B”的协同作用(如“高学历+多年经验”才重要)
  2. 无法处理多重共线性:若两个特征高度相关且都重要,可能误删其中一个
  3. 线性假设局限:卡方检验、F检验依赖线性关系,对非线性关系捕捉能力弱(需用互信息弥补)
  4. 可能丢失关键信息:过度依赖单个特征的相关性,可能遗漏“单独看不重要但组合重要”的特征

六、与其他特征选择方法对比

方法 核心逻辑 优点 缺点 适用场景
单变量特征选择 逐个评估特征与目标的相关性 简单、快速、无模型依赖 忽略特征交互、不处理共线性 快速粗筛、特征独立、中小型数据
L1正则化(Lasso) 惩罚系数绝对值,使部分系数为0 嵌入建模、处理高维数据 对共线性敏感、随机删除相关特征 高维数据、稀疏建模
递归特征消除(RFE) 训练模型逐步删除最不重要特征 考虑特征交互、精度高 计算量大、依赖模型 特征交互强、对精度要求高
树模型特征重要性(RF/XGBoost) 基于节点分裂增益评估重要性 捕捉非线性、抗共线性 计算量大、可能过拟合 非线性数据、复杂特征关系

七、适用场景与替代方案

优先用单变量特征选择的情况

  1. 数据预处理阶段快速粗筛(剔除完全无关特征)
  2. 特征数量较多(几十到几百个)且特征间独立
  3. 任务是线性关系为主(如逻辑回归、线性回归)
  4. 对计算效率要求高,无需复杂建模

考虑其他方法的情况

  1. 特征间存在强交互作用(如“年龄+收入”共同影响消费):用RFE或树模型
  2. 特征高度相关(多重共线性):用L2正则化或ElasticNet
  3. 数据存在复杂非线性关系:用互信息或树模型
  4. 高维数据(上千个特征):用L1正则化或树模型

八、最简单总结(背诵版)

  1. 单变量特征选择 = 逐个给特征打分,只留高分特征
  2. 核心方法:分类特征用卡方检验,连续特征用F检验,非线性用互信息
  3. 优点:简单、快速、高效,适合快速粗筛
  4. 缺点:忽略特征交互,不处理共线性
  5. 最佳用法:作为特征选择的第一步,后续用更复杂方法精筛
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐