机器学习--特征选择
一、方法介绍
(一)定义
在机器学习中,特征选择是一个至关重要的环节,其目的是从原始特征集合中挑选出最具代表性和信息量的特征子集,使得在该子集上构建的机器学习模型能够达到最佳的预测或分类效果。
在实际的数据集里,往往存在大量的特征,其中一些特征可能与目标变量高度相关,对模型的预测有重要贡献;而另一些特征可能是冗余的、不相关的甚至会对模型产生干扰,增加模型的复杂度和噪声。
(二)特征选择方法
特征选择方法通常可以分为三类:过滤式方法、包裹式方法和嵌入式方法。
1.过滤式方法:独立于模型,在模型训练之前基于数据的内在特性对特征进行评估和选择,计算速度快,但可能无法充分考虑特征与特定模型的相互作用。
2.包裹式方法:以特定的机器学习模型为基础,将特征选择过程视为一个搜索问题,通过在特征子集空间中进行搜索,以模型在验证集上的性能作为评价标准来选择最优特征子集,这种方法通常能获得较好的效果,但计算成本较高。
3.嵌入式方法:将特征选择与模型训练过程相结合,在模型训练的过程中自动进行特征选择,例如Lasso回归通过在损失函数中添加L1正则化项,使得模型在训练过程中自动将一些不重要的特征的系数收缩为零,从而实现特征选择的目的。
(三)应用
在生物信息学中,通过特征选择可以从大量的基因表达数据中筛选出与疾病相关的关键基因;
在自然语言处理中,能够从众多的文本特征中选择出最能代表文本主题和语义的特征,提高文本分类和情感分析等任务的准确性;
在图像识别领域,有助于从海量的图像特征中提取出最具判别力的特征,降低模型的复杂度,提高识别效率。
二、基于树的特征选择方法
基于树的特征选择方法是机器学习中一种重要且广泛应用的特征选择技术,它主要基于决策树或树集成模型来评估和选择特征。
(一)决策树
决策树是一种基于树结构的分类或回归模型,其核心思想是通过对特征进行递归的划分,将样本空间逐步划分为不同的子空间,使得每个子空间内的样本尽可能属于同一类别或具有相似的数值。在决策树的构建过程中,通过计算每个特征的信息增益,并选择信息增益最大的特征作为分裂特征,决策树能够自动地对特征进行排序和筛选,在树的生长过程中,那些对分类或回归没有太大贡献的特征往往不会被选择为分裂特征,从而实现了特征选择的效果。
(二)树集成模型
树集成模型如随机森林(Random Forest)和梯度提升树(Gradient Boosting Tree)等,也被广泛用于特征选择。在随机森林中,包含了多个决策树,通过对训练数据进行有放回的抽样构建多个子数据集,然后分别训练决策树,最后综合多个决策树的结果进行预测。在这个过程中,可以通过计算每个特征在所有决策树中的平均重要性得分来评估特征的重要性。
(三)优点与缺点
1.不需要对数据进行复杂的预处理和归一化操作,能够处理各种类型的数据,包括数值型、分类型等。
2.树模型具有很好的可解释性,通过观察树的结构和特征的分裂情况,可以直观地了解每个特征对模型决策的影响。
3.树集成模型的计算成本相对较高,特别是在处理大规模数据集时,需要消耗较多的时间和计算资源。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
try:
# 加载糖尿病数据集
diabetes = load_diabetes()
X = diabetes.data
y = diabetes.target
# 数据集划分(添加stratify保证数据分布一致性)
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42,
shuffle=True
)
# 创建并训练GBM模型(添加提前停止机制)
gbm = GradientBoostingRegressor(
n_estimators=200,
learning_rate=0.05,
max_depth=3,
random_state=42,
n_iter_no_change=10, # 添加提前停止
validation_fraction=0.1
)
gbm.fit(X_train, y_train)
# 模型评估
y_pred = gbm.predict(X_test)
r2 = r2_score(y_test, y_pred)
print(f"\n模型性能评估:")
print(f"测试集 R² 分数: {r2:.4f}")
print(f"使用特征数: {X.shape[1]}")
print(f"最佳迭代次数: {gbm.n_estimators_}")
# 特征重要性处理
feature_importance = gbm.feature_importances_
sorted_idx = np.argsort(feature_importance)[::-1] # 降序排列
sorted_features = np.array(diabetes.feature_names)[sorted_idx]
sorted_importance = feature_importance[sorted_idx]
# 可视化优化
plt.style.use('seaborn')
plt.figure(figsize=(10, 6))
# 创建颜色渐变效果
colors = plt.cm.viridis(np.linspace(0.3, 1, len(sorted_idx)))
bars = plt.barh(
range(len(sorted_idx)),
sorted_importance,
align='center',
color=colors,
edgecolor='black'
)
# 添加数据标签
for bar in bars:
width = bar.get_width()
plt.text(
width + 0.005,
bar.get_y() + bar.get_height()/2,
f'{width:.3f}',
va='center',
fontsize=9
)
plt.yticks(range(len(sorted_idx)), sorted_features)
plt.xlabel('Feature Importance Score', fontsize=12)
plt.title('Diabetes Dataset Feature Importance (GBM)', fontsize=14, pad=20)
plt.gca().invert_yaxis() # 反转y轴
plt.xlim(0, max(sorted_importance)*1.15) # 为标签留出空间
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
# 保存图表
plt.savefig('feature_importance.png', dpi=300, bbox_inches='tight')
plt.show()
except Exception as e:
print(f"\n程序执行出错: {str(e)}")
print("建议检查:")
print("1. 确保scikit-learn版本 >= 0.22 (提前停止功能需要)")
print("2. 检查Python依赖包是否安装完整")
print("3. 确认数据集加载是否正常")
# 添加版本检查
import sklearn
print(f"\n当前环境版本:")
print(f"scikit-learn: {sklearn.__version__}")
print(f"numpy: {np.__version__}")
print(f"matplotlib: {plt.matplotlib.__version__}")
可以发现最重要的两个特征变量是BMI和S5;
(二)自动特征选择
依旧使用糖尿病数据集,自动特征选择的代码如下:
import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.feature_selection import RFECV
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
# 加载糖尿病数据集
diabetes = load_diabetes()
X = diabetes.data
y = diabetes.target
# 将数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 初始化 GBM 模型
gbm = GradientBoostingRegressor(random_state=42)
# 使用网格搜索优化 GBM 超参数
param_grid = {
'n_estimators': [50, 100, 200],
'learning_rate': [0.01, 0.1, 0.2],
'max_depth': [2, 3, 4]
}
grid_search = GridSearchCV(estimator=gbm, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
# 获取最佳模型
best_gbm = grid_search.best_estimator_
# 初始化 RFECV 进行特征选择
rfecv = RFECV(estimator=best_gbm, step=1, cv=5, scoring='neg_mean_squared_error')
# 进行特征选择
rfecv.fit(X_train, y_train)
# 获取选择的特征
X_train_selected = rfecv.transform(X_train)
X_test_selected = rfecv.transform(X_test)
# 用选择的特征重新训练 GBM 模型
best_gbm.fit(X_train_selected, y_train)
# 预测测试集
y_pred = best_gbm.predict(X_test_selected)
# 计算 MSE
mse = mean_squared_error(y_test, y_pred)
print(f"Test MSE with selected features: {mse}")
# 输出选择的特征索引
print(f"Selected feature indices: {np.where(rfecv.support_)[0]}")
# 可视化特征选择过程
plt.figure()
plt.xlabel("Number of features selected")
plt.ylabel("Cross validation score (negative MSE)")
plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_)
plt.show()