import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_excel('california.xlsx')
from sklearn.model_selection import train_test_split
X = df.drop(['price'],axis=1)
y = df['price']
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 然后將訓練集進一步劃分為訓練集和驗證集
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42) # 0.125 x 0.8 = 0.1
# 數據集標準化
x_mean = X_train.mean()
x_std = X_train.std()
y_mean = y.mean()
y_std = y.std()
X_train = (X_train - x_mean)/x_std
y_train = (y_train-y_mean)/y_std
X_val = (X_val - x_mean)/x_std
y_val = (y_val - y_mean)/y_std
X_test = (X_test - x_mean)/x_std
y_test = (y_test - y_mean)/y_std
import lightgbm as lgb
# LightGBM模型參數
params_lgb = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合。典型值范圍:0.01 - 0.1
'boosting_type': 'gbdt', # 提升方法,這里使用梯度提升樹(Gradient Boosting Decision Tree,簡稱GBDT)
'objective': 'mse', # 損失函數
'metric': 'rmse', # 評估指標
'num_leaves': 127, # 每棵樹的葉子節點數量,控制模型復雜度。較大值可以提高模型復雜度但可能導致過擬合
'verbose': -1, # 控制 LightGBM 輸出信息的詳細程度,-1表示無輸出,0表示最少輸出,正數表示輸出更多信息
'seed': 42, # 隨機種子,用于重現模型的結果
'n_jobs': -1, # 并行運算的線程數量,-1表示使用所有可用的CPU核心
'feature_fraction': 0.8, # 每棵樹隨機選擇的特征比例,用于增加模型的泛化能力
'bagging_fraction': 0.9, # 每次迭代時隨機選擇的樣本比例,用于增加模型的泛化能力
'bagging_freq': 4 # 每隔多少次迭代進行一次bagging操作,用于增加模型的泛化能力
}
model_lgb = lgb.LGBMRegressor(**params_lgb)
model_lgb.fit(X_train, y_train, eval_set=[(X_val, y_val)],
eval_metric='rmse')
將數據集劃分為訓練集、驗證集和測試集,并對其進行標準化處理,然后使用LightGBM模型進行訓練,設置參數以防止過擬合和提高泛化能力,到目前為止就構建了一個LighGBM模型,對這個預測結果進行一個簡單的可視化
pred_train = model_lgb.predict(X_train)
pred_val = model_lgb.predict(X_val)
pred_test = model_lgb.predict(X_test)
y_train_h = y_train*y_std+y_mean
pred_train_h = pred_train*y_std+y_mean
y_val_h = y_val*y_std+y_mean
pred_val_h = pred_val*y_std+y_mean
y_test_h = y_test*y_std+y_mean
pred_test_h = pred_test*y_std+y_mean
import seaborn as sns
colors = sns.color_palette("husl", 3)
plt.figure(figsize=(15,5),dpi=300)
plt.subplot(3,1,1)
plt.scatter(y_train_h, pred_train_h, label='訓練集', alpha=0.3, color=colors[0])
plt.xlabel('真實值')
plt.ylabel('預測值')
plt.legend()
plt.subplot(3,1,2)
plt.scatter(y_val_h, pred_val_h, label='驗證集', alpha=0.3, color=colors[1])
plt.xlabel('真實值')
plt.ylabel('預測值')
plt.legend()
plt.subplot(3,1,3)
plt.scatter(y_test_h, pred_test_h, label='測試集', alpha=0.3, color=colors[2])
plt.xlabel('真實值')
plt.ylabel('預測值')
plt.legend()
plt.tight_layout()
plt.show()
將模型預測結果與真實值進行比較并可視化,但這種簡單的可視化無法深入解釋模型的決策過程,但是我們可以借助SHAP值進一步分析模型特征的重要性和貢獻度
import shap
# 構建 shap解釋器
explainer = shap.TreeExplainer(model_lgb)
# 計算測試集的shap值
shap_values = explainer.shap_values(X_train)
# 特征標簽
labels = X_train.columns
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = 'Times new Roman'
plt.rcParams['font.size'] = 13
#cmap="?"配色viridis Spectral coolwar mRdYlGn RdYlBu RdBu RdGy PuOr BrBG PRGn PiYG
plt.figure()
shap.summary_plot(shap_values, X_train, feature_names=labels, plot_type="dot")
摘要圖是SHAP常用的一種可視化方法,用于顯示特征的重要性和特征值的影響方向,摘要圖結合了特征重要性和特征效應圖,展示了每個特征的SHAP值的分布情況,幫助我們理解每個特征對模型預測的貢獻,這張可視化結果可在眾多論文當中看見,當然你也可以通過參數cmap改變配色避免審美疲勞(”viridis”:從黃色到藍綠色。”Spectral”:從紅色到藍色,適用于有正負影響的特征。”coolwarm”:從冷到暖的顏色圖。”RdYlGn”:從紅到綠的顏色圖。”RdYlBu”:從紅到藍的顏色圖。”RdBu”:紅藍雙色圖。”RdGy”:紅灰雙色圖。”PuOr”:從紫色到橙色的顏色圖。”BrBG”:從棕色到藍綠色的顏色圖。”PRGn”:從紫色到綠色的顏色圖。”PiYG”:從粉紅色到綠色的顏色圖),接下來從不同角度對可視化進行解讀
顏色:
粉紅色點:表示特征值在這個觀察模型中對模型預測產生了正面影響藍色點:表示該特征值在這個觀察中對模型預測產生負面影響
水平軸(shap值):
顯示每個特征對預測結果的影響大小,點越遠離中心線(零點),表示該特征對模型輸出的影響越大正的shap值表示正面影響,負的shap值表示負面影響
垂直軸(特征排列):
圖中垂直排列的特征按影響力從上到小進行排序,上方的特征對模型輸出的總影響更大,而下方的特征影響較小
特征影響力解釋:
最上方特征(如:MedInc):
顯示了大量的正面和負面影響,表明其在不同的觀察值對模型預測的結果有很大不同的影響
中部特征(如:AveRooms):
也顯示出兩種顏色的點,但點的分布更集中,影響相對較小底部特征(如:Population):對模型的影響最小,且大部分影響較為接近于零值,表示這些特征對模型預測的貢獻較小
其中如何去理解每個特征的SHAP值這句話>shap_values值反應的其實就是每一個樣本,每一個特征對輸出結果的影響
print("shap維度:",shap_values.shape)
print("測試集維度:",X_train.shape)
可以看見shap_values和測試集(這里做的摘要圖是對測試集進行操作)維度是一致的,也就是每一個shap值實際和原始數據每一個點是一一對應的,當然也可以對所有數據集在一張畫布上展示每一個特征的排序
# 計算訓練集和測試集的SHAP值
shap_values_train = explainer.shap_values(X_train)
shap_values_val = explainer.shap_values(X_val)
shap_values_test = explainer.shap_values(X_test)
# 繪制SHAP值總結圖(Summary Plot)
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
shap.summary_plot(shap_values_train, X_train, plot_type="bar", show=False)
plt.title("X_train")
plt.xlabel('') # 移除 x 軸標簽避免x軸重疊
plt.subplot(1, 3, 2)
shap.summary_plot(shap_values_val, X_val, plot_type="bar", show=False)
plt.title("X_val")
plt.subplot(1, 3, 3)
shap.summary_plot(shap_values_test, X_test, plot_type="bar", show=False)
plt.title("X_test")
plt.xlabel('')
plt.tight_layout()
plt.show()
這里計算的就不在是每一個點的shap值,而是計算的每一個特征的重要程度,特征按影響力從大到小進行排序,如何進行計算的呢?
np.abs(shap_values_train).mean(axis=0) # 利用測試集進行演示
就是把SHAP_value樣本取絕對值的平均值從而得到每個特征的重要程度
shap.dependence_plot('MedInc', shap_values, X_train, interaction_index='AveOccup')
依賴圖用于顯示一個特征的SHAP值與該特征值之間的關系,并可以展示特征之間的交互作用在這里shap.dependence_plot函數的參數解釋如下:
‘MedInc’:這是你想要研究的特征名
shap_values:這是通過SHAP計算得到的特征重要性值
X_train:這是用于生成SHAP值的訓練數據interaction_index=’AveOccup’:這是指定與主特征(MedInc)交互的特征,SHAP會在圖中顯示兩者的交互效果最后對這個依賴圖進行解讀:
正相關關系:在這里隨著MedInc的增加,目標變量AveOccup也隨之增加 影響的程度:MedInc的值在 3 到 6 的范圍內,SHAP 值變化并不明顯,表明,在這個范圍內,MedInc對模型預測的目標變量影響并不大,反之成立
交互效果:通過觀察圖中的顏色變化,可以了解主特征與交互特征之間的關系以及它們對模型預測的共同影響
# 繪制單個樣本的SHAP解釋(Force Plot)
sample_index = 7 # 選擇一個樣本索引進行解釋
shap.force_plot(explainer.expected_value, shap_values_test[sample_index], X_test.iloc[sample_index], matplotlib=True)
力圖用于直觀地展示單個樣本的SHAP值及其對模型預測結果的影響,通過力圖,可以清晰地看到每個特征對該樣本預測值的貢獻
力圖可視化解釋:
基線值:圖中的起點表示模型的基線值(expected_value)也就是可視化當中的base valuc
特征貢獻:每個特征的貢獻通過帶顏色的條表示,條的長度表示該特征對最終預測值的影響大小,紅色條表示正向貢獻,即該特征使預測值增加,藍色條表示負向貢獻,即該特征使預測值減少預測值:終點表示模型對該樣本的最終預測值,這是基線值加上所有特征貢獻的總和,在這里為-0.31
shap_interaction_values = explainer.shap_interaction_values(X_train)
shap.summary_plot(shap_interaction_values, X_train)
用于展示特征之間交互作用的重要性和影響的一種可視化方法
特征排序:特征按重要性排序,最重要的特征在圖的頂部,每個特征的總重要性值是其與所有其他特征交互作用的重要性值之和
SHAP交互作用值分布:每個點表示一個樣本的交互作用值,交互作用值越大,表示該特征與另一個特征的交互對模型預測的影響越大顏色表示交互特征:顏色表示與主特征交互的特征,使用顏色漸變來表示不同的特征交互效果
# 創建 shap.Explanation 對象
shap_explanation = shap.Explanation(values=shap_values_test[0:500,:],
base_values=explainer.expected_value,
data=X_test.iloc[0:500,:], feature_names=X_test.columns)
# 繪制熱圖
shap.plots.heatmap(shap_explanation)
熱圖解讀:
左側y軸為重要性特征排名,特征按影響力從大到小進行排序,右側y軸為其可視化,圖像中顏色深淺表示SHAP值的大小,也就是該特征下值對模型的影響,顏色越深SHAP值絕對值越大越影響模型,頂部為模型在這些數值下的預測結果可視化,這里只從測試集中選擇了500個數據進行可視化,太多的數據會影響運行時間,以及可視化的精美,讀者自行取舍
通過熱圖,可以有效地探索和理解復雜模型的特征重要性和特征之間的相互關系,從而提高模型的解釋性和可解釋性