import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_excel('california.xlsx')
from sklearn.model_selection import train_test_split, KFold
X = df.drop(['price'],axis=1)
y = df['price']
# 劃分訓(xùn)練集和測(cè)試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
df.head()
從Excel文件中讀取數(shù)據(jù),將特征變量與目標(biāo)變量(房?jī)r(jià) price)分離,并劃分為訓(xùn)練集和測(cè)試集,用于機(jī)器學(xué)習(xí)模型的訓(xùn)練和評(píng)估。數(shù)據(jù)集中包括了房齡(HouseAge)、中位收入(MedInc)、平均房間數(shù)(AveRooms)等特征,目標(biāo)變量為房?jī)r(jià)(price)
from sklearn.metrics import root_mean_squared_error
from catboost import CatBoostRegressor
# CatBoost模型參數(shù)
params_cat = {
'learning_rate': 0.02, # 學(xué)習(xí)率,控制每一步的步長(zhǎng),用于防止過(guò)擬合。典型值范圍:0.01 - 0.1
'iterations': 1000, # 弱學(xué)習(xí)器(決策樹(shù))的數(shù)量
'depth': 6, # 決策樹(shù)的深度,控制模型復(fù)雜度
'eval_metric': 'RMSE', # 評(píng)估指標(biāo),這里使用均方根誤差(Root Mean Squared Error,簡(jiǎn)稱RMSE)
'random_seed': 42, # 隨機(jī)種子,用于重現(xiàn)模型的結(jié)果
'verbose': 500 # 控制CatBoost輸出信息的詳細(xì)程度,每100次迭代輸出一次
}
# 準(zhǔn)備k折交叉驗(yàn)證
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = []
best_score = np.inf
best_model = None
# 交叉驗(yàn)證
for fold, (train_index, val_index) in enumerate(kf.split(X_train, y_train)):
X_train_fold, X_val_fold = X_train.iloc[train_index], X_train.iloc[val_index]
y_train_fold, y_val_fold = y_train.iloc[train_index], y_train.iloc[val_index]
model = CatBoostRegressor(**params_cat)
model.fit(X_train_fold, y_train_fold, eval_set=(X_val_fold, y_val_fold), early_stopping_rounds=100)
# 預(yù)測(cè)并計(jì)算得分
y_val_pred = model.predict(X_val_fold)
score = root_mean_squared_error(y_val_fold, y_val_pred) # RMSE
scores.append(score)
print(f'第 {fold + 1} 折 RMSE: {score}')
# 保存得分最好的模型
if score < best_score:
best_score = score
best_model = model
print(f'最佳 RMSE: {best_score}')
通過(guò)使用5折交叉驗(yàn)證來(lái)訓(xùn)練CatBoost回歸模型,每一折模型都會(huì)基于訓(xùn)練集進(jìn)行訓(xùn)練,并在驗(yàn)證集上進(jìn)行評(píng)估,計(jì)算出對(duì)應(yīng)的RMSE(均方根誤差),在每一折訓(xùn)練中,模型會(huì)自動(dòng)調(diào)整參數(shù)以避免過(guò)擬合,使用早停策略來(lái)選擇最佳的迭代次數(shù),最終,程序會(huì)輸出每一折的RMSE得分,并保存得分最好的模型,最后輸出整個(gè)交叉驗(yàn)證中最優(yōu)模型的RMSE,表示模型在驗(yàn)證集上取得的最低預(yù)測(cè)誤差,這一過(guò)程有助于評(píng)估模型的穩(wěn)健性并防止過(guò)擬合,為PDP解釋做準(zhǔn)備
2D PDP解釋
from sklearn.inspection import PartialDependenceDisplay
# 選擇兩個(gè)特征繪制2D PDP
features = ['MedInc', 'AveOccup']
# 使用 contour_kw 參數(shù)繪制2D PDP
fig, ax = plt.subplots(figsize=(10, 6), dpi=1200)
PartialDependenceDisplay.from_estimator(
best_model,
X_test,
features=[features],
kind='average',
grid_resolution=50,
contour_kw={'cmap': 'viridis', 'alpha': 0.8},
ax=ax
)
plt.suptitle('2D Partial Dependence Plot for MedInc and AveOccup')
plt.savefig("2D Partial Dependence Plot for MedInc and AveOccup.pdf", format='pdf',bbox_inches='tight')
plt.show()
使用PartialDependenceDisplay生成一個(gè)2D部分依賴圖(PDP),用于展示兩個(gè)特征(MedInc和AveOccup)對(duì)目標(biāo)變量(房?jī)r(jià))的影響,代碼中的best_model是之前訓(xùn)練好的CatBoost模型,X_test是測(cè)試集中的特征數(shù)據(jù),features指定了感興趣的兩個(gè)特征,即中位收入(MedInc)和平均家庭規(guī)模(AveOccup)
2D PDP圖通過(guò)將MedInc(中位收入)和AveOccup(平均家庭規(guī)模)組合的不同值映射到房?jī)r(jià)預(yù)測(cè)結(jié)果的等高線圖上,展示了模型對(duì)這兩個(gè)特征共同作用的反應(yīng),圖中的顏色表示房?jī)r(jià)的預(yù)測(cè)值,顏色從左到右逐漸變化,反映出隨著中位收入增加,房?jī)r(jià)預(yù)測(cè)值也逐步增加,同時(shí),等高線代表了不同的房?jī)r(jià)預(yù)測(cè)范圍,等高線的數(shù)值越大,表示在這些區(qū)域中房?jī)r(jià)預(yù)測(cè)越高,通過(guò)觀察可以發(fā)現(xiàn),MedInc的增大對(duì)房?jī)r(jià)的影響更加顯著,而AveOccup的影響相對(duì)較小,但它們的共同作用仍然對(duì)房?jī)r(jià)預(yù)測(cè)產(chǎn)生綜合影響,這一可視化有助于直觀地理解兩個(gè)特征如何相互配合影響目標(biāo)變量的趨勢(shì)
3D?PDP解釋
from mpl_toolkits.mplot3d import Axes3D
def plot_3d_pdp_scatter(model, X, features, grid_resolution=20):
"""
繪制三個(gè)特征的3D PDP散點(diǎn)圖,不固定任何特征值。
參數(shù):
- model: 訓(xùn)練好的機(jī)器學(xué)習(xí)模型(例如:隨機(jī)森林,XGBoost等)。
- X: 數(shù)據(jù)集(特征矩陣)。
- features: 需要分析的三個(gè)特征名列表,格式為 ['feature1', 'feature2', 'feature3']。
- grid_resolution: 網(wǎng)格分辨率,決定網(wǎng)格點(diǎn)的密度
"""
# 獲取三個(gè)特征的數(shù)據(jù)
feature_1, feature_2, feature_3 = features
# 構(gòu)建網(wǎng)格
feature_1_vals = np.linspace(X[feature_1].min(), X[feature_1].max(), grid_resolution)
feature_2_vals = np.linspace(X[feature_2].min(), X[feature_2].max(), grid_resolution)
feature_3_vals = np.linspace(X[feature_3].min(), X[feature_3].max(), grid_resolution)
# 生成三維網(wǎng)格
grid_1, grid_2, grid_3 = np.meshgrid(feature_1_vals, feature_2_vals, feature_3_vals)
# 將網(wǎng)格數(shù)據(jù)轉(zhuǎn)換為數(shù)據(jù)框的格式,傳遞給模型進(jìn)行預(yù)測(cè)
grid_points = np.c_[grid_1.ravel(), grid_2.ravel(), grid_3.ravel()]
X_grid = np.zeros((grid_points.shape[0], X.shape[1])) # 創(chuàng)建空白矩陣,維度與X相同
X_grid[:, X.columns.get_loc(feature_1)] = grid_points[:, 0]
X_grid[:, X.columns.get_loc(feature_2)] = grid_points[:, 1]
X_grid[:, X.columns.get_loc(feature_3)] = grid_points[:, 2]
# 對(duì)網(wǎng)格數(shù)據(jù)進(jìn)行預(yù)測(cè)
preds = model.predict(X_grid)
# 繪制3D散點(diǎn)圖
fig = plt.figure(figsize=(10, 8),dpi=1200)
ax = fig.add_subplot(111, projection='3d')
# 使用散點(diǎn)圖繪制三維特征,并使用預(yù)測(cè)值作為顏色
sc = ax.scatter(grid_1.ravel(), grid_2.ravel(), grid_3.ravel(), c=preds, cmap='viridis', alpha=0.8)
# 添加顏色條
plt.colorbar(sc, ax=ax, label='Prediction')
ax.set_xlabel(feature_1)
ax.set_ylabel(feature_2)
ax.set_zlabel(feature_3)
plt.title(f'3D Partial Dependence Scatter Plot for {feature_1}, {feature_2}, and {feature_3}')
plt.savefig("3D.pdf", format='pdf', bbox_inches='tight')
plt.show()
features = ['MedInc', 'AveOccup', 'HouseAge']
plot_3d_pdp_scatter(best_model, X_test, features)
通過(guò)構(gòu)建三維網(wǎng)格實(shí)現(xiàn)3D PDP(部分依賴圖)的可視化,展示了三個(gè)特征(MedInc,AveOccup,HouseAge)對(duì)目標(biāo)變量(房?jī)r(jià))預(yù)測(cè)的影響,具體做法是,首先為每個(gè)特征構(gòu)建取值范圍并生成三維網(wǎng)格,然后將這些網(wǎng)格點(diǎn)組合成一組數(shù)據(jù)點(diǎn),傳遞給訓(xùn)練好的模型進(jìn)行預(yù)測(cè)。接著,代碼使用三維散點(diǎn)圖顯示這些特征組合下的預(yù)測(cè)值,其中顏色代表房?jī)r(jià)預(yù)測(cè)值,顏色從深到淺依次表示房?jī)r(jià)從低到高,通過(guò)這種3D可視化,可以清晰地看到這三個(gè)特征對(duì)房?jī)r(jià)預(yù)測(cè)的共同作用和交互影響,例如,中位收入較高和房齡較新的區(qū)域往往房?jī)r(jià)預(yù)測(cè)較高,而家庭規(guī)模的影響較小但仍有一定作用,這種可視化方法幫助深入理解模型對(duì)多個(gè)特征組合的反應(yīng)
def plot_3d_pdp(model, X, features, fixed_feature=None, fixed_value=None, grid_resolution=50):
"""
繪制三個(gè)特征的3D PDP圖,其中一個(gè)特征固定值,并加上熱度條。
參數(shù):
- model: 訓(xùn)練好的機(jī)器學(xué)習(xí)模型(例如:隨機(jī)森林,XGBoost等)。
- X: 數(shù)據(jù)集(特征矩陣)。
- features: 需要分析的三個(gè)特征名列表,格式為 ['feature1', 'feature2', 'feature3']。
- fixed_feature: 需要固定的特征名(默認(rèn)為features列表中的第三個(gè)特征)。
- fixed_value: 第三個(gè)特征的固定值(可以是其均值、中位數(shù)或任意值,默認(rèn)為其均值)。
- grid_resolution: 網(wǎng)格分辨率,決定網(wǎng)格點(diǎn)的密度。
"""
feature_1, feature_2, feature_3 = features
# 如果沒(méi)有指定固定特征,默認(rèn)將第三個(gè)特征固定
if fixed_feature is None:
fixed_feature = feature_3
# 如果沒(méi)有指定固定值,則使用該特征的均值
if fixed_value is None:
fixed_value = X[fixed_feature].mean()
# 構(gòu)建網(wǎng)格,針對(duì)兩個(gè)未固定的特征
if fixed_feature == feature_1:
varying_features = [feature_2, feature_3]
elif fixed_feature == feature_2:
varying_features = [feature_1, feature_3]
else:
varying_features = [feature_1, feature_2]
feature_1_vals = np.linspace(X[varying_features[0]].min(), X[varying_features[0]].max(), grid_resolution)
feature_2_vals = np.linspace(X[varying_features[1]].min(), X[varying_features[1]].max(), grid_resolution)
grid_1, grid_2 = np.meshgrid(feature_1_vals, feature_2_vals)
# 構(gòu)建網(wǎng)格數(shù)據(jù),傳遞給模型進(jìn)行預(yù)測(cè)
grid_points = np.c_[grid_1.ravel(), grid_2.ravel()]
X_grid = np.zeros((grid_points.shape[0], X.shape[1])) # 創(chuàng)建空白矩陣,維度與X相同
X_grid[:, X.columns.get_loc(varying_features[0])] = grid_points[:, 0]
X_grid[:, X.columns.get_loc(varying_features[1])] = grid_points[:, 1]
X_grid[:, X.columns.get_loc(fixed_feature)] = fixed_value # 固定特征值
# 對(duì)網(wǎng)格數(shù)據(jù)進(jìn)行預(yù)測(cè)
preds = model.predict(X_grid).reshape(grid_1.shape)
# 繪制3D圖像
fig = plt.figure(figsize=(10, 8), dpi=1200)
ax = fig.add_subplot(111, projection='3d')
# 繪制等高線圖
surface = ax.plot_surface(grid_1, grid_2, preds, cmap='viridis', alpha=0.8)
# 添加顏色熱度條
fig.colorbar(surface, ax=ax, shrink=0.5, aspect=10)
ax.set_xlabel(varying_features[0])
ax.set_ylabel(varying_features[1])
ax.set_zlabel('Prediction')
plt.title(f'3D Partial Dependence Plot for {varying_features[0]}, {varying_features[1]} with {fixed_feature}={fixed_value}')
plt.savefig("3D one.pdf", format='pdf', bbox_inches='tight')
plt.show()
features = ['MedInc', 'AveOccup', 'HouseAge']
plot_3d_pdp(best_model, X_test, features, fixed_feature='HouseAge')
在進(jìn)行模型解釋時(shí),如果對(duì)所有特征進(jìn)行可視化展示(如3個(gè)特征),會(huì)形成一個(gè)三維正方體圖像,代表所有特征組合下的模型預(yù)測(cè)值,雖然這種全方位的可視化非常全面,但對(duì)于實(shí)際理解模型各特征如何結(jié)合影響預(yù)測(cè)來(lái)說(shuō),復(fù)雜度較高,因此,固定一個(gè)特征值可以簡(jiǎn)化分析,并展示另外兩個(gè)特征的組合如何影響預(yù)測(cè)結(jié)果,通過(guò)固定某個(gè)特征,能更容易觀察這兩個(gè)特征對(duì)目標(biāo)變量的影響,同時(shí)保持模型預(yù)測(cè)的復(fù)雜性
代碼通過(guò)生成一個(gè)3D部分依賴圖,固定HouseAge的特定值(默認(rèn)是其均值或用戶指定值),然后分析MedInc(中位收入)和AveOccup(平均家庭規(guī)模)對(duì)房?jī)r(jià)預(yù)測(cè)的影響。代碼首先創(chuàng)建了一個(gè)包含MedInc和AveOccup的網(wǎng)格,將這兩個(gè)特征在不同取值下組合,然后傳遞給模型進(jìn)行預(yù)測(cè),最后,通過(guò)3D等高線圖將預(yù)測(cè)結(jié)果可視化,其中顏色表示房?jī)r(jià)的預(yù)測(cè)值
在圖中,HouseAge被固定為31.14歲,表示房齡固定情況下中位收入(MedInc)和平均家庭規(guī)模(AveOccup)如何共同作用影響房?jī)r(jià)預(yù)測(cè)。顏色從深紫色到亮黃色逐漸變化,表明預(yù)測(cè)值從低到高,可以觀察到,中位收入對(duì)房?jī)r(jià)預(yù)測(cè)的影響相對(duì)明顯,隨著MedInc的增大,房?jī)r(jià)預(yù)測(cè)值顯著增加;而AveOccup的影響較為平緩,整體變化不大,通過(guò)這張圖,能更直觀地看到這兩個(gè)特征的組合如何在特定房齡下影響房?jī)r(jià)預(yù)測(cè)
本文章轉(zhuǎn)載微信公眾號(hào)@Python機(jī)器學(xué)習(xí)AI
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)