XGBoost模型优化:基于相关系数剔除多重共线性与穷举法进行特征选择

机器学习向量数据库大模型

picture.image

✨ 欢迎关注 ✨

本节介绍: XGBoost模型相关系数剔除多重共线性与穷举优化特征选择 。数据采用模拟数据,作者根据个人对机器学习的理解进行代码实现与图表输出,仅供参考。 完整 数据和代码将在稍后上传至交流群,付费成员可在交流群中获取下载。需要的朋友可关注公众文末提供的购买方式。 购买前请咨询,避免不必要的问题。

✨ 实现流程 ✨

  • 数据加载与预处理:首先读取数据并划分为特征(X)和目标变量(y),然后将数据分为训练集和测试集
  • 特征重要性分析:使用XGBoost回归模型训练数据并提取特征的重要性,绘制特征重要性图,帮助识别对目标变量影响最大的特征
  • 多重共线性剔除:基于相关系数对特征进行筛选,剔除高度相关的特征,以减少多重共线性对模型的影响
  • 穷举法优化特征组合:通过穷举法生成所有可能的特征组合,使用交叉验证计算每个组合的R²分数,选择最优特征组合
  • 超参数调优:使用网格搜索(GridSearchCV)对XGBoost模型进行超参数优化,选择最佳的模型配置
  • 模型训练与预测:使用最佳模型训练数据,并对训练集和测试集进行预测
  • 模型评估与可视化:计算并展示训练集和测试集的RMSE、MAE、R²等评估指标,绘制相关系数热力图、残差图以及SHAP值可视化,进一步解释模型的预测结果

接下来,从代码层面对每个步骤进行详细的解释,逐步分析各个模块的功能和实现细节,本项目的原始文献是采用的模型是随机森林RF,这里替换为xgboost模型并对可视化进行了一些优化

✨ 基础代码 ✨

  
import pandas as pd  
import numpy as np  
import matplotlib.pyplot as plt  
plt.rcParams['font.family'] = 'Times New Roman'  
plt.rcParams['axes.unicode_minus'] = False  
import warnings  
# 忽略所有警告  
warnings.filterwarnings("ignore")  
df = pd.read_excel('2025-6-4公众号Python机器学习AI.xlsx')  
df

picture.image

加载一个包含643个样本和135个特征的数据集,并进行字体设置、忽略警告以及导入所需的库,数据从名为2025-6-4公众号Python机器学习AI.xlsx的Excel文件中读取

  
from sklearn.model_selection import train_test_split  
# 划分特征和目标变量  
X = df.drop(['序号', 'Tensile strength/MPa'], axis=1)  
y = df['Tensile strength/MPa']  
# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,   
                                                    random_state=42)  
import xgboost as xgb  
from sklearn.model_selection import train_test_split  
import pandas as pd  
  
# 构建XGBoost回归模型(默认参数)  
xgb_model = xgb.XGBRegressor(random_state=42)  
xgb_model.fit(X_train, y_train)  
  
# 提取特征重要性  
feature_importance = xgb_model.feature_importances_  
  
# 构建特征重要性 DataFrame  
feature_importance_df = pd.DataFrame({  
    'Feature': X.columns,  
    'Importance': feature_importance  
})  
  
# 按重要性降序排序  
feature_importance_df = feature_importance_df.sort_values(by='Importance', ascending=False)  
import matplotlib.cm as cm  
import matplotlib.colors as mcolors  
  
# 按特征重要性降序排列,并选取前15个特征  
top_features = feature_importance_df.head(15)  
importances = top_features['Importance']  
features = top_features['Feature']  
  
# 配色方案  
norm = mcolors.Normalize(vmin=importances.min(), vmax=importances.max())  
colors = cm.viridis(norm(importances))    
  
# 绘制单个模型的特征重要性柱状图  
plt.figure(figsize=(12, 8), dpi=1200)  # 调整图像大小以配合更大的字体  
plt.barh(features, importances, color=colors)  
plt.title("Top 15 Feature Importances", fontsize=20)  # 设置标题字体大小  
plt.xlabel("Importance", fontsize=20)  # 设置 x 轴标签字体大小  
plt.ylabel("Features", fontsize=20)  # 设置 y 轴标签字体大小  
plt.xticks(fontsize=18)  # 设置 x 轴刻度字体大小  
plt.yticks(fontsize=18)  # 设置 y 轴刻度字体大小  
plt.gca().invert_yaxis()  # 让特征重要性高的在顶部  
plt.tight_layout()  
plt.savefig("1.pdf", format='pdf', bbox_inches='tight', dpi=1200)  
plt.show()                                                    

picture.image

使用默认参数XGBoost回归模型对数据进行训练,并通过特征重要性排名来选出前15个最重要的特征,目的是减少特征数量并提高模型性能,同时在进行多重共线性剔除时也能够借助特征重要性排名来优化特征选择

这里需要注意的是特征贡献排名是通过xgb_model.feature_importances_进行获取的不同的获取方法会导致模型特征贡献排名存在差异从而导致后续的特征处理,可以参考往期文章——特征选择:评估指标差异对XGBoost特征筛选与模型性能排名的影响

picture.image

通过相关系数的计算和可视化,展示特征之间的相关性,使用饼图来表示每对特征的相关系数及其显著性。尽管XGBoost模型本身对多重共线性不敏感,但为了避免在模型解读(如SHAP解释)时出现高度线性相关特征之间的解释误差,仍然需要考虑并剔除多重共线性

  
# 多重共线性剔除  
threshold = 0.95  
features_to_keep = top_n_feature_names[:]    
features_to_remove_collinearity = []   
importance_dict = feature_importance_df.set_index('Feature')['Importance'].to_dict()  
  
# 迭代检查每一对特征  
cols_to_check = top_n_feature_names[:]  # 我们将迭代这个列表的副本  
already_removed_in_this_pass = set()  # 确保一个特征只被移除一次  
  
for i in range(len(cols_to_check)):  
    for j in range(i + 1, len(cols_to_check)):  
        feat1 = cols_to_check[i]  
        feat2 = cols_to_check[j]  
  
        # 如果其中一个特征已经被标记为移除,则跳过这对  
        if feat1 in already_removed_in_this_pass or feat2 in already_removed_in_this_pass:  
            continue  
  
        # 获取相关系数  
        if feat1 in corr_matrix_top_n.index and feat2 in corr_matrix_top_n.columns:  
            correlation = corr_matrix_top_n.loc[feat1, feat2]  
        else:  
            continue  
  
        if abs(correlation) > threshold:  
            print(f"发现高度相关特征对: '{feat1}' 和 '{feat2}', 相关系数: {correlation:.4f}")  
  
            importance1 = importance_dict.get(feat1, 0)  # 使用.get避免KeyError  
            importance2 = importance_dict.get(feat2, 0)  
  
            if importance1 < importance2:  
                if feat1 in features_to_keep:  
                    features_to_keep.remove(feat1)  # 从列表中移除  
                    features_to_remove_collinearity.append(feat1)  
                    already_removed_in_this_pass.add(feat1)  
                    print(f"  剔除 '{feat1}' (重要性: {importance1:.4f}),保留 '{feat2}' (重要性: {importance2:.4f})")  
            elif importance2 < importance1:  
                if feat2 in features_to_keep:  
                    features_to_keep.remove(feat2)  # 从列表中移除  
                    features_to_remove_collinearity.append(feat2)  
                    already_removed_in_this_pass.add(feat2)  
                    print(f"  剔除 '{feat2}' (重要性: {importance2:.4f}),保留 '{feat1}' (重要性: {importance1:.4f})")  
            else:  # 重要性相同  
                if feat2 in features_to_keep:  
                    features_to_keep.remove(feat2)  # 从列表中移除  
                    features_to_remove_collinearity.append(feat2)  
                    already_removed_in_this_pass.add(feat2)  
                    print(f"  重要性相同。剔除 '{feat2}' (索引靠后/任意选择),保留 '{feat1}'")  
  
print("-" * 30)  
print("最终保留的特征 (经过多重共线性剔除后):")  
print(features_to_keep)  
print(f"共保留 {len(features_to_keep)} 个特征。")  
print("-" * 30)  
print("因多重共线性而被剔除的特征 (来自Top N列表):")  
print(features_to_remove_collinearity)  
print(f"共剔除 {len(features_to_remove_collinearity)} 个特征。")  
print("-" * 30)

picture.image

通过计算特征之间的相关系数,剔除相关系数超过0.95(这是一个阈值)的特征对,剔除规则是:在两个高度相关的特征中,保留重要性更高的特征(根据XGBoost模型特征重要性确定),剔除重要性较低的特征;如果两者重要性相同,则根据特征在原始列表中的顺序剔除后出现的特征

  
feature_names = top_n_feature_names  # 特征名称  
feature_importances = feature_importance_df.iloc[0:15]['Importance']  # 特征重要性  
selected_features = features_to_keep  # 保留的特征  
  
# 设置颜色:保留的特征为红色,剔除的特征为蓝色  
colors = ['red' if feature in selected_features else 'blue' for feature in feature_names]  
  
# 创建柱状图  
plt.figure(figsize=(10, 6), dpi=300)  
bars = plt.bar(feature_names, feature_importances, color=colors, edgecolor='black', alpha=0.85)  
  
# 添加图例  
red_patch = plt.Line2D([0], [0], color='red', lw=4, label='Features of exhaustion')  # 红色图例  
blue_patch = plt.Line2D([0], [0], color='blue', lw=4, label='Removed features')  # 蓝色图例  
plt.legend(handles=[red_patch, blue_patch], loc='upper right', fontsize=12)  
  
# 设置图形标题和标签  
plt.title('Feature Importances', fontsize=16)  
plt.xlabel('Features', fontsize=14)  
plt.ylabel('Feature-Importances', fontsize=14)  
plt.xticks(rotation=45, fontsize=10, ha='right')  
plt.tight_layout()  
plt.savefig("3.pdf", format='pdf', bbox_inches='tight', dpi=1200)  
plt.show()

picture.image

这里简单绘制一个柱状图,展示前15个特征的重要性,其中保留的特征用红色表示,剔除的特征用蓝色表示,同时添加了图例、标题和标签

  
# 划分特征和目标变量 final_features 是选择的特征  
X = df.drop(['序号', 'Tensile strength/MPa'], axis=1)[final_features]  
y = df['Tensile strength/MPa']  
# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,   
                                                    random_state=42)  
from sklearn.model_selection import cross_val_score, KFold  
# 初始化结果存储  
results = []  
# 设置随机种子  
random_state = 1314  
# 创建KFold对象  
kf = KFold(n_splits=5, shuffle=True, random_state=random_state)  
  
# 逐个特征组合建模并评估  
for combination in all_combinations:  
    selected_features = list(combination)  
    X_train_subset = X_train[selected_features]  
    X_test_subset = X_test[selected_features]  
  
    # 创建随机森林模型(默认参数)  
    rf_model = xgb.XGBRegressor(random_state=random_state)  
  
    # 进行5折交叉验证,计算平均 R^2 分数  
    cv_scores = cross_val_score(rf_model, X_train_subset, y_train, cv=kf, scoring='r2')  
    mean_cv_score = np.mean(cv_scores)  
  
    # 记录结果  
    results.append({  
        'Features': selected_features,  
        'Mean CV R^2': mean_cv_score  
    })  
  
# 将结果转换为 DataFrame 并按 R^2 分数排序  
results_df = pd.DataFrame(results)  
results_df = results_df.sort_values(by='Mean CV R^2', ascending=False).reset_index(drop=True)                                                  

picture.image

通过穷举法生成所有特征组合,并使用5折交叉验证评估每个组合在XGBoost回归模型下的R²分数,最终将结果按R²分数排序,帮助选择最优的特征组合

穷举法确实确保了所有可能的特征组合都被遍历和评估,这样可以全面找到最优的特征组合。然而,由于它需要对所有特征组合进行评估,随着特征数量的增加,运行时间会呈指数级增长。因此,对于特征数量较多的情况,计算开销非常大

相比之下,递归特征筛选(RFE)是一种基于模型的特征选择方法,通过递归地去除不重要的特征来优化特征子集,它通常不需要遍历所有可能的组合,效率较高。但它可能无法探索到所有特征组合的情况,可能会错过一些最优组合,可以参考往期文章——期刊配图:结合lightgbm回归模型与K折交叉验证的特征筛选可视化

  
best_row = results_df.loc[results_df['Mean CV R^2'].idxmax()]  
# 划分特征和目标变量  
X = df[best_row[0]]  
y = df['Tensile strength/MPa']  
# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,   
                                                    random_state=42)  
from sklearn.model_selection import GridSearchCV  
  
# 定义XGBoost模型  
xgb_model = xgb.XGBRegressor(random_state=random_state)  
  
param_grid = {  
    'n_estimators': [50, 80],             # 减少树的数量范围  
    'max_depth': [5, 10, 15],             # 限制树的深度  
    'learning_rate': [0.01, 0.1, 0.2],    # 学习率(XGBoost的特有超参数)  
    'subsample': [0.7, 0.8, 0.9],         # 子样本比例  
    'colsample_bytree': [0.7, 0.8, 0.9],  # 每棵树的特征子集比例  
    'min_child_weight': [1, 5, 10]         # 每个叶子节点的最小样本权重  
}  
  
# 设置更严格的交叉验证  
cv = KFold(n_splits=5, shuffle=True, random_state=random_state)  
  
# 网格搜索  
grid_search = GridSearchCV(estimator=xgb_model, param_grid=param_grid,  
                           cv=cv, scoring='neg_mean_absolute_error', n_jobs=-1, verbose=2)  
  
# 训练模型  
grid_search.fit(X_train, y_train)  
  
# 使用最佳参数训练模型  
xgb_model = grid_search.best_estimator_  
  
# 打印最佳参数  
print(f"Best Parameters: {grid_search.best_params_}")                                                    

picture.image

最终对筛选出来的特征集合使用网格搜索对XGBoost回归模型进行超参数优化,进行5折交叉验证并找到最佳超参数组合,以优化模型在训练集上的表现。最终结果显示了最佳的超参数组合,其中包括colsample_bytree,learning_rate,max_depth等参数

picture.image

对训练的最优模型绘制训练集和测试集的散点图与边缘直方图,计算并显示模型的评估指标(如R²、RMSE、MAE),同时在图下方添加残差图,展示训练集和测试集的残差分布

  
import shap  
explainer = shap.TreeExplainer(xgb_model)  
shap_values = explainer.shap_values(X_test)  
plt.figure(dpi=1200)  
shap.summary_plot(shap_values, X_test, plot_type="bar", show=False)  
plt.tight_layout()  
plt.savefig("6.pdf", format='pdf', bbox_inches='tight', dpi=1200)  
plt.figure()  
shap.summary_plot(shap_values, X_test, feature_names=X_test.columns, plot_type="dot", show=False)  
plt.savefig("7.pdf", format='pdf', bbox_inches='tight', dpi=1200)

picture.image

使用SHAP库对XGBoost模型进行解释,生成了两种基础的SHAP图表:

  • 条形图(bar plot):显示特征对模型预测的平均贡献大小,可以用来直观理解哪些特征对模型预测影响最大
  • 点图(dot plot):展示每个特征的SHAP值分布,反映了不同样本中该特征对预测结果的影响

这两种SHAP图表帮助理解模型的决策过程,尤其适用于解释复杂的非线性模型。更多SHAP解释方法可以参考公众号往期文章

✨ 该文章案例 ✨

picture.image

在上传至交流群的文件中,像往期文章一样,将对案例进行逐步分析,确保读者能够达到最佳的学习效果。内容都经过详细解读,帮助读者深入理解模型的实现过程和数据分析步骤,从而最大化学习成果。

同时,结合提供的免费AI聚合网站进行学习,能够让读者在理论与实践之间实现融会贯通,更加全面地掌握核心概念。

✨ 购买介绍 ✨

本节介绍到此结束,有需要学习数据分析和Python机器学习相关的朋友欢迎到淘宝店铺:Python机器学习AI,或添加作者微信deep_ML联系,购买作者的公众号合集。截至目前为止,合集已包含近300多篇文章,购买合集的同时,还将提供免费稳定的AI大模型使用,包括但不限于ChatGPT、Deepseek、Claude等。

更新的内容包含数据、代码、注释和参考资料。 作者仅分享案例项目,不提供额外的答疑服务。项目中将提供详细的代码注释和丰富的解读,帮助您理解每个步骤 。 购买前请咨询,避免不必要的问题。

✨ 群友反馈 ✨

picture.image

✨ 淘宝店铺 ✨

picture.image

请大家打开淘宝扫描上方的二维码,进入店铺,获取更多Python机器学习和AI相关的内容,或者添加作者微信deep_ML联系 避免淘宝客服漏掉信息 ,希望能为您的学习之路提供帮助!

往期推荐

机器学习在临床数据分析中的应用:从数据预处理到Web应用实现的完整流程教学

期刊配图:基于SHAP算法的驱动因子相互作用贡献矩阵图

因果推断:利用EconML实现双重机器学习估计条件平均处理效应 (CATE)

期刊复现:基于部分线性模型的双重机器学习方法

期刊复现:基于XGBoost模型的网页工具SHAP力图解释单样本预测结果

期刊配图:nature cities通过ALE(累积局部效应)解析特征对模型影响

期刊复现:结合因果推断与SHAP可解释性的机器学习实现应用流程

期刊配图:一区SCI常用数据缺失率展示图可视化

因果推断:注册行为对后续消费影响的因果推断分析案例

nature communications:基于Light GBM与随机森林结合的多模型特征选择方法

因果推断与机器学习结合:探索酒店预订取消的影响因素

picture.image

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动 XR 技术的探索与实践
火山引擎开发者社区技术大讲堂第二期邀请到了火山引擎 XR 技术负责人和火山引擎创作 CV 技术负责人,为大家分享字节跳动积累的前沿视觉技术及内外部的应用实践,揭秘现代炫酷的视觉效果背后的技术实现。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论