开发也能看懂的大模型:特征选择和稀疏学习

813 阅读9分钟

特征选择稀疏学习是机器学习中重要的技术,主要用于提升模型的性能和可解释性,特别是在高维数据场景中(如文本处理、生物信息学)。下面分别讲解两者,并探讨它们之间的联系与应用。


1. 特征选择

特征选择(Feature Selection)是指在高维数据中,从原始特征集合中挑选出对模型最有用的特征子集,去除冗余或无关的特征。

1.1 目标

  • 降低模型复杂度。
  • 提高模型泛化性能(减少过拟合)。
  • 提升训练速度。
  • 增强模型的可解释性。

1.2 方法分类

  1. 过滤法(Filter)

    • 概念:根据统计指标或相关性对特征进行打分,选择分数较高的特征。

    • 常用方法

      • 方差阈值:去除方差过低的特征。
      • 卡方检验:评估特征与目标变量的独立性。
      • 互信息(Mutual Information):衡量特征与目标变量之间的信息增益。
    • 优点:速度快,易于实现,与模型无关。

    • 缺点:忽略特征间的交互作用。

    • 示例代码:

      from sklearn.feature_selection import SelectKBest, chi2
      X_new = SelectKBest(chi2, k=10).fit_transform(X, y)
      
  2. 包裹法(Wrapper)

    • 概念:通过训练模型评估不同特征子集的效果,选取最佳子集。

    • 常用方法

      • 递归特征消除(Recursive Feature Elimination, RFE)。
    • 优点:考虑了特征间的交互作用。

    • 缺点:计算代价高,容易过拟合。

    • 示例代码:

      from sklearn.feature_selection import RFE
      from sklearn.ensemble import RandomForestClassifier
      model = RandomForestClassifier()
      rfe = RFE(model, n_features_to_select=5)
      X_new = rfe.fit_transform(X, y)
      
  3. 嵌入法(Embedded)

    • 概念:通过正则化(如 L1 范数)或基于树的模型自动选择重要特征。

    • 常用方法

      • LASSO 回归(L1 正则化): 通过对模型中的回归系数施加 L1范数惩罚,使得某些系数精确等于零,从而筛选出重要特征。
      • 基于重要性评分的特征选择(如随机森林): 通过模型训练后的特征重要性,筛选掉对目标变量影响较小的特征,减小模型的复杂度,提高模型的泛化性能。
    • 优点:嵌入模型中,效率高。

    • 缺点:依赖于具体模型的选择。

    • 示例代码:

      from sklearn.linear_model import Lasso
      model = Lasso(alpha=0.1)
      model.fit(X, y)
      importance = model.coef_
      

2. 稀疏学习

稀疏学习是一类通过引入稀疏约束来优化模型的技术,目的是在高维数据中找到稀疏解(即多数特征的系数为零)。

2.1 目标

  • 强制特征选择:让模型自动选择少量关键特征。
  • 降维:将高维特征压缩为稀疏表示。
  • 提升模型的泛化能力。

2.2 核心思想

稀疏学习通常依赖 正则化 技术,将稀疏约束引入到损失函数中:

  • L1 正则化(Lasso) :通过惩罚权重的绝对值,迫使部分权重变为零,从而达到稀疏性。
  • Elastic Net:结合 L1 和 L2 正则化,既能稀疏化特征又能解决多重共线性问题。

2.3 常见模型

  1. LASSO 回归

    • 用于线性回归任务,通过 L1 正则化实现稀疏解。

    • 损失函数:

image.png

from sklearn.linear_model import Lasso
model = Lasso(alpha=0.1)
model.fit(X_train, y_train)
  1. 稀疏编码

    • 通过构造稀疏表示来表示数据的潜在结构,常用于图像处理和信号处理。
  2. 稀疏支持向量机(Sparse SVM)

    • 对传统 SVM 引入 L1 正则化,自动选择关键特征。
  3. 稀疏主成分分析(Sparse PCA)

    • 在 PCA 中引入稀疏性,限制每个主成分的非零系数数量。

3. 特征选择与稀疏学习的关系

  • 目标一致性:两者都试图从高维数据中提取少量关键特征。

  • 实现方法的交集:稀疏学习是特征选择的一种有效方式,通过引入稀疏约束自动实现特征选择。

  • 区别

    • 特征选择是一个明确的过程,通常先选择特征再建模。
    • 稀疏学习将特征选择融入到模型训练过程中,属于嵌入法的一种。

4. 应用场景

  1. 文本分类

    • 使用 TF-IDF 提取特征后,通过稀疏学习选择关键词。
    • 模型:LASSO 回归、稀疏逻辑回归。
  2. 基因数据分析

    • 基因表达数据维度极高,特征选择和稀疏学习有助于找到关键基因。
  3. 推荐系统

    • 在稀疏的用户行为矩阵中,通过稀疏编码或稀疏分解实现特征提取。
  4. 图像处理

    • 稀疏编码可用于图像压缩和特征提取。

案例:糖尿病数据集预测

任务: 利用糖尿病数据集(Diabetes Dataset),使用 LASSO 回归 进行特征选择,并对目标进行预测。


1. 数据集介绍

糖尿病数据集是 sklearn 自带的一个小型数据集,包含10个生物学特征(如年龄、性别、体质指数等)和目标变量(糖尿病进展指标)。

  • 特征:10个连续变量。
  • 样本:442条记录。
  • 目标:预测目标变量的数值。

特征变量

这些特征是对患者生物学信息的标准化数值,主要包含以下内容:

  1. 年龄(age) :患者年龄。

  2. 性别(sex) :患者性别。

  3. 体质指数(bmi) :患者体重与身高的比例。

  4. 平均血压(bp) :患者血压的平均值。

  5. 六种血清指标

    • T-CHO(tc)
    • LDL-C(ldl)
    • HDL-C(hdl)
    • TCH/HDL 比值(tch)
    • LTG(ltg)
    • GLU(glu)

目标变量

  • y:糖尿病进展的量化指标(疾病的严重程度),为一个连续值。

2. 案例实现

步骤 1:加载数据

from sklearn.datasets import load_diabetes
import pandas as pd

# 加载数据集
data = load_diabetes()
X, y = data.data, data.target

# 转换为 DataFrame,便于观察
df = pd.DataFrame(X, columns=data.feature_names)
df['target'] = y

# 查看数据集基本信息
print(df.head())

load_diabetes() : 加载糖尿病数据集。

  • data.data: 数据的特征值(10 个变量)。
  • data.target: 目标变量(糖尿病指标,连续值)。

步骤 2:LASSO 特征选择

from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 数据预处理:标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

# 使用 LASSO 模型
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)

# 输出特征权重
feature_importance = pd.DataFrame({
    'Feature': data.feature_names,
    'Weight': lasso.coef_
}).sort_values(by='Weight', ascending=False)
print(feature_importance)
  • StandardScaler: 对数据进行标准化,使每个特征的均值为 0,标准差为 1,提高模型的收敛性。

  • fit_transform: 先计算每个特征的均值和标准差,再对数据进行转换。

  • 将数据集按 8:2 的比例划分为训练集和测试集。

  • random_state=42: 固定随机种子,确保结果可重复。

  • Lasso(alpha=0.1) : 初始化 LASSO 模型,alpha 是正则化强度的超参数,较大的值会使更多特征权重趋于零。

  • fit: 使用训练数据拟合模型。

  • lasso.coef_ : 获取每个特征对应的回归系数。

  • 创建一个 DataFrame,展示特征名称和权重,并按权重从高到低排序。


步骤 3:模型评估

from sklearn.metrics import mean_squared_error, r2_score

# 使用 LASSO 的结果进行预测
y_pred_train = lasso.predict(X_train)
y_pred_test = lasso.predict(X_test)

# 计算训练和测试集的 MSE 和 R²
train_mse = mean_squared_error(y_train, y_pred_train)
test_mse = mean_squared_error(y_test, y_pred_test)
train_r2 = r2_score(y_train, y_pred_train)
test_r2 = r2_score(y_test, y_pred_test)

print(f"训练集 MSE: {train_mse:.2f}, R²: {train_r2:.2f}")
print(f"测试集 MSE: {test_mse:.2f}, R²: {test_r2:.2f}")
  • mean_squared_error: 计算均方误差(MSE),MSE 值越小,模型的预测误差越小,性能越好。

  • r2_score: 计算决定系数(R²),用于衡量回归模型对数据的拟合优度,值越接近 1,模型越优。


步骤 4:分析与可视化

import matplotlib.pyplot as plt

# 特征重要性可视化
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['Feature'], feature_importance['Weight'], color='skyblue')
plt.xlabel('Weight')
plt.title('Feature Importance using LASSO')
plt.show()
  • barh: 绘制水平条形图,展示每个特征的权重。

  • 特征权重的绝对值越大,表明该特征对模型预测的贡献越大。


3. 输出结果

image.png

image.png

问题分析

  1. MSE 过大的可能原因:

    • 目标值的范围较大: 数据集中目标变量的范围是 0 到 346,MSE 的数值会随着目标值范围的增大而变大。
    • 模型欠拟合: 由于 LASSO 是线性模型,而糖尿病数据集可能存在非线性关系,因此模型未能捕捉所有信息。
    • 正则化参数的选择问题: 当前使用的正则化强度 α=0.1 可能过强,导致部分特征的权重被过多压缩。
  2. R² 值较低的可能原因:

    • 数据中可能包含一些对目标变量无关或弱相关的特征,降低了模型的拟合效果。
    • 模型类型的局限性(LASSO 的线性假设)使其无法有效捕捉复杂的关系。

改进建议

1. 优化模型参数

  • 使用交叉验证自动调整正则化参数 α:

    from sklearn.linear_model import LassoCV
    
    lasso_cv = LassoCV(cv=5).fit(X_train, y_train)
    print(f"Optimal alpha: {lasso_cv.alpha_}")
    
  • 选择最优的 α 后重新训练模型,可能提升 R² 和降低 MSE。

2. 更换模型

  • 尝试使用非线性模型(如随机森林、梯度提升树)捕捉复杂关系。
from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error,r2_score
from sklearn.preprocessing import StandardScaler
import pandas as pd

# 加载糖尿病数据集
data = load_diabetes()
X, y = data.data, data.target

# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

# 创建随机森林模型
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)

# 预测
y_pred_train = rf.predict(X_train)
y_pred_test = rf.predict(X_test)

# 计算均方误差 (MSE)
train_mse = mean_squared_error(y_train, y_pred_train)
test_mse = mean_squared_error(y_test, y_pred_test)
train_r2 = r2_score(y_train, y_pred_train)
test_r2 = r2_score(y_test, y_pred_test)

# 输出结果
#print(f"训练集 MSE: {train_mse:.2f}")
#print(f"测试集 MSE: {test_mse:.2f}")
print(f"训练集 MSE: {train_mse:.2f}, R²: {train_r2:.2f}")
print(f"测试集 MSE: {test_mse:.2f}, R²: {test_r2:.2f}")

image.png

附录:完整代码

from sklearn.datasets import load_diabetes
import pandas as pd
from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt


# 加载数据集
data = load_diabetes()
X, y = data.data, data.target

# 转换为 DataFrame,便于观察
df = pd.DataFrame(X, columns=data.feature_names)
df['target'] = y

# 查看数据集基本信息
print(df.head())



# 数据预处理:标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

# 使用 LASSO 模型
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)

# 输出特征权重
feature_importance = pd.DataFrame({
    'Feature': data.feature_names,
    'Weight': lasso.coef_
}).sort_values(by='Weight', ascending=False)
print(feature_importance)



# 使用 LASSO 的结果进行预测
y_pred_train = lasso.predict(X_train)
y_pred_test = lasso.predict(X_test)

# 计算训练和测试集的 MSE 和 R²
train_mse = mean_squared_error(y_train, y_pred_train)
test_mse = mean_squared_error(y_test, y_pred_test)
train_r2 = r2_score(y_train, y_pred_train)
test_r2 = r2_score(y_test, y_pred_test)

print(f"训练集 MSE: {train_mse:.2f}, R²: {train_r2:.2f}")
print(f"测试集 MSE: {test_mse:.2f}, R²: {test_r2:.2f}")


# 特征重要性可视化
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['Feature'], feature_importance['Weight'], color='skyblue')
plt.xlabel('Weight')
plt.title('Feature Importance using LASSO')
plt.saveConfig("output.png")