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ùn)練集進(jìn)一步劃分為訓(xùn)練集和驗(yàn)證集
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

import lightgbm as lgb

# LightGBM模型參數(shù)
params_lgb = {
'learning_rate': 0.02, # 學(xué)習(xí)率,控制每一步的步長(zhǎng),用于防止過擬合。典型值范圍:0.01 - 0.1
'boosting_type': 'gbdt', # 提升方法,這里使用梯度提升樹(Gradient Boosting Decision Tree,簡(jiǎn)稱GBDT)
'objective': 'mse', # 損失函數(shù)
'metric': 'rmse', # 評(píng)估指標(biāo)
'num_leaves': 127, # 每棵樹的葉子節(jié)點(diǎn)數(shù)量,控制模型復(fù)雜度。較大值可以提高模型復(fù)雜度但可能導(dǎo)致過擬合
'verbose': -1, # 控制 LightGBM 輸出信息的詳細(xì)程度,-1表示無輸出,0表示最少輸出,正數(shù)表示輸出更多信息
'seed': 42, # 隨機(jī)種子,用于重現(xiàn)模型的結(jié)果
'n_jobs': -1, # 并行運(yùn)算的線程數(shù)量,-1表示使用所有可用的CPU核心
'feature_fraction': 0.8, # 每棵樹隨機(jī)選擇的特征比例,用于增加模型的泛化能力
'bagging_fraction': 0.9, # 每次迭代時(shí)隨機(jī)選擇的樣本比例,用于增加模型的泛化能力
'bagging_freq': 4 # 每隔多少次迭代進(jìn)行一次bagging操作,用于增加模型的泛化能力
}

model_lgb = lgb.LGBMRegressor(**params_lgb)
model_lgb.fit(X_train, y_train, eval_set=[(X_val, y_val)],

使用LightGBM模型對(duì)房?jī)r(jià)進(jìn)行預(yù)測(cè),并通過劃分訓(xùn)練集、驗(yàn)證集和測(cè)試集的方式來訓(xùn)練模型、驗(yàn)證其性能,以確保模型的泛化能力,接下來也將對(duì)這個(gè)模型進(jìn)行力圖的繪制,數(shù)據(jù)集是一個(gè)包含了房?jī)r(jià)預(yù)測(cè)相關(guān)的特征信息數(shù)據(jù),如中位收入、房齡、平均房間數(shù)、平均臥室數(shù)、人口數(shù)、平均家庭人口數(shù)、緯度和經(jīng)度,以及對(duì)應(yīng)的房?jī)r(jià)。

基礎(chǔ)力圖繪制

import shap
# 構(gòu)建 shap解釋器
explainer = shap.TreeExplainer(model_lgb)
# 計(jì)算測(cè)試集的shap值
shap_values = explainer.shap_values(X_test)

# 繪制單個(gè)樣本的SHAP解釋(Force Plot)
sample_index = 7 # 選擇一個(gè)樣本索引進(jìn)行解釋
shap.force_plot(explainer.expected_value, shap_values[sample_index], X_test.iloc[sample_index], matplotlib=True)
plt.savefig("SHAP力圖_1.pdf", format='pdf', bbox_inches='tight')

這是一個(gè)基礎(chǔ)的SHAP力圖,目前在許多文章中采用了類似的展示形式,然而,這種樣式仍有許多值得我們深入探討的地方,例如,當(dāng)特征數(shù)量過多時(shí),如果我們只想展示部分關(guān)鍵特征,該如何實(shí)現(xiàn)?又如,特征帶有度量單位時(shí),如何在力圖上清晰地展示?這些都是可以改進(jìn)的方向,作者在一篇文獻(xiàn)中發(fā)現(xiàn)了類似的SHAP力圖如下:

接下來我們通過一步步解讀參數(shù),根據(jù)原理去繪制類似的力圖。

explainer.expected_value

explainer.expected_value 是SHAP解釋器中的一個(gè)關(guān)鍵參數(shù),它代表了模型在沒有任何特征輸入時(shí)的預(yù)測(cè)值,即模型輸出的基準(zhǔn)值或平均值,在回歸問題中,這通常是模型在整個(gè)訓(xùn)練數(shù)據(jù)集上的平均預(yù)測(cè)值,這個(gè)值作為SHAP力圖中的基礎(chǔ)線,所有特征的SHAP值都相對(duì)于這個(gè)基準(zhǔn)值進(jìn)行調(diào)整,從而顯示出每個(gè)特征對(duì)最終預(yù)測(cè)的貢獻(xiàn)。

shap_values[sample_index]

shap_values[sample_index] 表示SHAP解釋器對(duì)第 sample_index 個(gè)樣本計(jì)算出的各個(gè)特征的SHAP值。

X_test.iloc[sample_index]

X_test.iloc[sample_index] 返回的是測(cè)試集 X_test 中第 sample_index 個(gè)樣本的特征值也就是前文shap對(duì)應(yīng)的樣本,可以發(fā)現(xiàn)它本身是不帶度量單位的,接下來根據(jù)這個(gè)原理去繪制帶度量單位的shap力圖。

帶度量單位的shap力圖

base_value = explainer.expected_value  # 基礎(chǔ)值,一般是模型在訓(xùn)練集上的平均輸出
shap_values = shap_values[sample_index] # 每個(gè)特征的SHAP值
features = np.array([
'MedInc=-0.096140 ($1000)', # 中位收入,單位為千美元
'HouseAge=0.749907 (years)', # 房齡,單位為年
'AveRooms=-0.195315 (rooms/house)', # 每個(gè)家庭的平均房間數(shù)
'AveBedrms=-0.111900 (bedrooms/house)', # 每個(gè)家庭的平均臥室數(shù)
'Population=-0.367422 (people)', # 人口數(shù)
'AveOccup=0.053259 (people/house)', # 每個(gè)家庭的平均人口數(shù)
'Latitude=-0.807184 (degrees)', # 緯度,單位為度
'Longitude=0.749004 (degrees)'])# 經(jīng)度,單位為度 特征名稱和數(shù)值
# 創(chuàng)建力圖
shap.force_plot(base_value, shap_values, features,
matplotlib=True, # 使用Matplotlib來顯示圖像
show=False)

plt.savefig("SHAP力圖_2.pdf", format='pdf', bbox_inches='tight')

根據(jù)特定樣本的特征值和SHAP值生成并保存一個(gè)解釋模型預(yù)測(cè)的力圖,可以發(fā)現(xiàn)該力圖對(duì)于每個(gè)特征都存在一個(gè)其對(duì)應(yīng)的單位,但是存在折疊,或許在實(shí)際應(yīng)用中我們只希望展示部分特征就可以了,而不是每個(gè)特征都進(jìn)行展示,只需要添加參數(shù)調(diào)整閾值就好了。

特征展示控制

# 創(chuàng)建力圖
shap.force_plot(base_value, shap_values, features,
matplotlib=True, # 使用Matplotlib來顯示圖像
show=False,
contribution_threshold=0.1) # 調(diào)整閾值以控制顯示哪些特征

plt.savefig("SHAP力圖_3.pdf", format='pdf', bbox_inches='tight')

通過添加 contribution_threshold=0.1 參數(shù),我們可以調(diào)整SHAP力圖中的顯示閾值,對(duì)比兩幅力圖后可以發(fā)現(xiàn),特征 HouseAge 已不在當(dāng)前的力圖中顯示,因?yàn)樗鼘?duì)預(yù)測(cè)結(jié)果的貢獻(xiàn)較小。這種調(diào)整并未改變圖表的整體信息表達(dá),同時(shí)也使圖表更加簡(jiǎn)潔,讀者可以根據(jù)具體需求自行調(diào)整閾值,以更好地控制特征的展示效果。

文章轉(zhuǎn)自微信公眾號(hào)@Python機(jī)器學(xué)習(xí)AI

上一篇:

不止 SHAP 力圖:LIME 實(shí)現(xiàn)任意黑盒模型的單樣本解釋

下一篇:

用圖表說話:如何有效呈現(xiàn)回歸預(yù)測(cè)模型結(jié)果

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)