特征选择与稀疏学习是机器学习中重要的技术,主要用于提升模型的性能和可解释性,特别是在高维数据场景中(如文本处理、生物信息学)。下面分别讲解两者,并探讨它们之间的联系与应用。
1. 特征选择
特征选择(Feature Selection)是指在高维数据中,从原始特征集合中挑选出对模型最有用的特征子集,去除冗余或无关的特征。
1.1 目标
- 降低模型复杂度。
- 提高模型泛化性能(减少过拟合)。
- 提升训练速度。
- 增强模型的可解释性。
1.2 方法分类
-
过滤法(Filter)
-
概念:根据统计指标或相关性对特征进行打分,选择分数较高的特征。
-
常用方法:
- 方差阈值:去除方差过低的特征。
- 卡方检验:评估特征与目标变量的独立性。
- 互信息(Mutual Information):衡量特征与目标变量之间的信息增益。
-
优点:速度快,易于实现,与模型无关。
-
缺点:忽略特征间的交互作用。
-
示例代码:
from sklearn.feature_selection import SelectKBest, chi2 X_new = SelectKBest(chi2, k=10).fit_transform(X, y)
-
-
包裹法(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)
-
-
嵌入法(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 常见模型
-
LASSO 回归
-
用于线性回归任务,通过 L1 正则化实现稀疏解。
-
损失函数:
-
from sklearn.linear_model import Lasso
model = Lasso(alpha=0.1)
model.fit(X_train, y_train)
-
稀疏编码
- 通过构造稀疏表示来表示数据的潜在结构,常用于图像处理和信号处理。
-
稀疏支持向量机(Sparse SVM)
- 对传统 SVM 引入 L1 正则化,自动选择关键特征。
-
稀疏主成分分析(Sparse PCA)
- 在 PCA 中引入稀疏性,限制每个主成分的非零系数数量。
3. 特征选择与稀疏学习的关系
-
目标一致性:两者都试图从高维数据中提取少量关键特征。
-
实现方法的交集:稀疏学习是特征选择的一种有效方式,通过引入稀疏约束自动实现特征选择。
-
区别:
- 特征选择是一个明确的过程,通常先选择特征再建模。
- 稀疏学习将特征选择融入到模型训练过程中,属于嵌入法的一种。
4. 应用场景
-
文本分类
- 使用 TF-IDF 提取特征后,通过稀疏学习选择关键词。
- 模型:LASSO 回归、稀疏逻辑回归。
-
基因数据分析
- 基因表达数据维度极高,特征选择和稀疏学习有助于找到关键基因。
-
推荐系统
- 在稀疏的用户行为矩阵中,通过稀疏编码或稀疏分解实现特征提取。
-
图像处理
- 稀疏编码可用于图像压缩和特征提取。
案例:糖尿病数据集预测
任务: 利用糖尿病数据集(Diabetes Dataset),使用 LASSO 回归 进行特征选择,并对目标进行预测。
1. 数据集介绍
糖尿病数据集是 sklearn 自带的一个小型数据集,包含10个生物学特征(如年龄、性别、体质指数等)和目标变量(糖尿病进展指标)。
- 特征:10个连续变量。
- 样本:442条记录。
- 目标:预测目标变量的数值。
特征变量
这些特征是对患者生物学信息的标准化数值,主要包含以下内容:
-
年龄(age) :患者年龄。
-
性别(sex) :患者性别。
-
体质指数(bmi) :患者体重与身高的比例。
-
平均血压(bp) :患者血压的平均值。
-
六种血清指标:
- 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. 输出结果
问题分析
-
MSE 过大的可能原因:
- 目标值的范围较大: 数据集中目标变量的范围是 0 到 346,MSE 的数值会随着目标值范围的增大而变大。
- 模型欠拟合: 由于 LASSO 是线性模型,而糖尿病数据集可能存在非线性关系,因此模型未能捕捉所有信息。
- 正则化参数的选择问题: 当前使用的正则化强度 α=0.1 可能过强,导致部分特征的权重被过多压缩。
-
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}")
附录:完整代码
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")