在上圖中,你看到的正是通過SHAP值分析心臟病預測模型的重要特征展示。每個點代表一個數據樣本,顏色越紅表明該特征原始值越高,越藍則越低,你可以清晰地看到,例如“thal”和“ca”等特征在預測模型中具有較高的特征貢獻度,它們直接影響模型的最終輸出
接下來,將介紹如何通過代碼組合shap可視化蜂巢圖和特征貢獻圖,讓復雜的機器學習模型變得更加透明和易于解釋
數據讀取處理
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['axes.unicode_minus'] = False
import warnings
warnings.filterwarnings("ignore")
df = pd.read_csv('Dataset.csv')
# 劃分特征和目標變量
X = df.drop(['target'], axis=1)
y = df['target']
# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
random_state=42, stratify=df['target'])
df.head()
用于加載數據集、劃分特征與目標變量,并將數據集按8:2的比例分為訓練集和測試集,以便進行后續的機器學習模型訓練和評估,此數據集為一個二分類數據集
模型構建
import xgboost as xgb
from sklearn.model_selection import GridSearchCV
# XGBoost模型參數
params_xgb = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合。典型值范圍:0.01 - 0.1
'booster': 'gbtree', # 提升方法,這里使用梯度提升樹(Gradient Boosting Tree)
'objective': 'binary:logistic', # 損失函數,這里使用邏輯回歸,用于二分類任務
'max_leaves': 127, # 每棵樹的葉子節點數量,控制模型復雜度。較大值可以提高模型復雜度但可能導致過擬合
'verbosity': 1, # 控制 XGBoost 輸出信息的詳細程度,0表示無輸出,1表示輸出進度信息
'seed': 42, # 隨機種子,用于重現模型的結果
'nthread': -1, # 并行運算的線程數量,-1表示使用所有可用的CPU核心
'colsample_bytree': 0.6, # 每棵樹隨機選擇的特征比例,用于增加模型的泛化能力
'subsample': 0.7, # 每次迭代時隨機選擇的樣本比例,用于增加模型的泛化能力
'eval_metric': 'logloss' # 評價指標,這里使用對數損失(logloss)
}
# 初始化XGBoost分類模型
model_xgb = xgb.XGBClassifier(**params_xgb)
# 定義參數網格,用于網格搜索
param_grid = {
'n_estimators': [100, 200, 300, 400, 500], # 樹的數量
'max_depth': [3, 4, 5, 6, 7], # 樹的深度
'learning_rate': [0.01, 0.02, 0.05, 0.1], # 學習率
}
# 使用GridSearchCV進行網格搜索和k折交叉驗證
grid_search = GridSearchCV(
estimator=model_xgb,
param_grid=param_grid,
scoring='neg_log_loss', # 評價指標為負對數損失
cv=5, # 5折交叉驗證
n_jobs=-1, # 并行計算
verbose=1 # 輸出詳細進度信息
)
# 訓練模型
grid_search.fit(X_train, y_train)
# 使用最優參數訓練模型
best_model = grid_search.best_estimator_
通過網格搜索找到最優的XGBoost模型參數,并訓練最終模型,為后續SHAP值計算提供最佳的模型基礎
shap值計算
import shap
explainer = shap.TreeExplainer(best_model)
# 計算shap值為numpy.array數組
shap_values_numpy = explainer.shap_values(X)
shap_values_numpy
針對訓練好的XGBoost模型和完整的數據集計算SHAP值,以解釋每個特征對模型預測的貢獻
SHAP值特征貢獻的蜂巢圖
plt.figure()
shap.summary_plot(shap_values_numpy, X, feature_names=X.columns, plot_type="dot", show=False)
plt.savefig("SHAP_numpy summary_plot.pdf", format='pdf',bbox_inches='tight')
SHAP值排序的特征重要性柱狀圖
plt.figure(figsize=(10, 5), dpi=1200)
shap.summary_plot(shap_values_numpy, X, plot_type="bar", show=False)
plt.title('SHAP_numpy Sorted Feature Importance')
plt.tight_layout()
plt.savefig("SHAP_numpy Sorted Feature Importance.pdf", format='pdf',bbox_inches='tight')
plt.show()
結合蜂巢圖與特征重要性圖的雙軸SHAP可視化圖
# 創建主圖(用來畫蜂巢圖)
fig, ax1 = plt.subplots(figsize=(10, 8), dpi=1200)
# 在主圖上繪制蜂巢圖,并保留熱度條
shap.summary_plot(shap_values_numpy, X, feature_names=X.columns, plot_type="dot", show=False, color_bar=True)
plt.gca().set_position([0.2, 0.2, 0.65, 0.65]) # 調整圖表位置,留出右側空間放熱度條
# 獲取共享的 y 軸
ax1 = plt.gca()
# 創建共享 y 軸的另一個圖,繪制特征貢獻圖在頂部x軸
ax2 = ax1.twiny()
shap.summary_plot(shap_values_numpy, X, plot_type="bar", show=False)
plt.gca().set_position([0.2, 0.2, 0.65, 0.65]) # 調整圖表位置,與蜂巢圖對齊
# 在頂部 X 軸添加一條橫線
ax2.axhline(y=13, color='gray', linestyle='-', linewidth=1) # 注意y值應該對應頂部
# 調整透明度
bars = ax2.patches # 獲取所有的柱狀圖對象
for bar in bars:
bar.set_alpha(0.2) # 設置透明度
# 設置兩個x軸的標簽
ax1.set_xlabel('Shapley Value Contribution (Bee Swarm)', fontsize=12)
ax2.set_xlabel('Mean Shapley Value (Feature Importance)', fontsize=12)
# 移動頂部的 X 軸,避免與底部 X 軸重疊
ax2.xaxis.set_label_position('top') # 將標簽移動到頂部
ax2.xaxis.tick_top() # 將刻度也移動到頂部
# 設置y軸標簽
ax1.set_ylabel('Features', fontsize=12)
plt.tight_layout()
plt.savefig("SHAP_combined_with_top_line_corrected.pdf", format='pdf', bbox_inches='tight')
plt.show()
首先創建一個雙軸圖表,通過繪制SHAP值的蜂巢圖和特征重要性柱狀圖,分別展示每個特征對模型預測的貢獻及其平均特征重要性,蜂巢圖在下方的X軸展示各特征的SHAP值分布,顏色代表特征值大小,而柱狀圖在上方的X軸展示每個特征的平均SHAP值作為重要性排序,代碼調整了圖表的位置以對齊蜂巢圖與柱狀圖,并通過添加頂部X軸和橫線來突出特征的平均貢獻,最后將生成的雙軸圖保存為PDF文件
本文章轉載微信公眾號@Python機器學習AI