import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
df = pd.read_csv('Chabuhou.csv')

# 劃分特征和目標變量
X = df.drop(['Electrical_cardioversion'], axis=1)
y = df['Electrical_cardioversion']
# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
random_state=42, stratify=df['Electrical_cardioversion'])

使用一個心臟電復律的數據集,目標是預測特定條件下患者是否需要電復律,特征變量(如年齡、心率、血壓等)經過清洗和預處理后,分為訓練集和測試集。

模型選擇與參數優化

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)

# 輸出最優參數
print("Best parameters found: ", grid_search.best_params_)
print("Best Log Loss score: ", -grid_search.best_score_)

# 使用最優參數訓練模型
best_model = grid_search.best_estimator_

from sklearn.metrics import classification_report
pred = best_model.predict(X_test) # 預測測試集
print(classification_report(y_test, pred)) # 輸出模型完整評價指標

選用XGBoost分類模型,模型參數通過網格搜索優化,以找到最佳的學習率、樹的深度等參數,最后輸出此情況下的最優模型的詳細評價指標。

SHAP值分析特征貢獻度

測試集特征貢獻度排名可視化

import shap
# 構建 shap解釋器
explainer = shap.TreeExplainer(best_model)
# 計算測試集的shap值
shap_values = explainer.shap_values(X_test)
# 特征標簽
labels = X_train.columns
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = 'Times new Roman'
plt.rcParams['font.size'] = 13

plt.figure(figsize=(15, 5))
shap.summary_plot(shap_values, X_test, plot_type="bar", show=False)
plt.title("X_test")
plt.xlabel('')
plt.tight_layout()
plt.show()

SHAP值是一種解釋模型預測的方法,通過計算每個特征對預測結果的貢獻度,我們可以了解哪些特征對模型的影響最大,并依據這些貢獻度來排序特征,從而篩選出重要特征。

特征排序

# 計算每個特征的平均絕對SHAP值
mean_shap_values = np.abs(shap_values).mean(axis=0)

# 獲取特征標簽
labels = X_train.columns

# 根據平均絕對SHAP值對特征進行排序
sorted_indices = np.argsort(mean_shap_values)[::-1] # 從大到小排序
sorted_labels = labels[sorted_indices]
sorted_shap_values = mean_shap_values[sorted_indices]

# 對特征變量按照模型特征貢獻度排序
X = df.drop(['Electrical_cardioversion'], axis=1).iloc[:, sorted_indices]

使用sorted_indices重新排列數據集的特征,使得最重要的特征排在前面,這樣排列后的數據集便于后續在不同特征組合下評估模型性能,特別是在進行逐步特征添加和蒙特卡洛模擬時,可以優先考慮貢獻度大的特征。

蒙特卡洛模擬與特征組合

from sklearn.model_selection import cross_val_score

# 劃分特征和目標變量
X = df.drop(['Electrical_cardioversion'], axis=1).iloc[:, sorted_indices]
y = df['Electrical_cardioversion']

# 設置隨機種子
np.random.seed(42)
n_features = X.shape[1]
mc_no = 20 # 蒙特卡洛模擬的次數
cv_scores = np.zeros(n_features) # 記錄交叉驗證分數

# 獲取最佳模型的所有參數
best_params = best_model.get_params()

# 過濾出你感興趣的參數,結合默認參數和網格搜索的最佳參數
params_xgb = {
'learning_rate': best_params['learning_rate'],
'booster': best_params['booster'],
'objective': best_params['objective'],
'max_leaves': best_params['max_leaves'],
'verbosity': best_params['verbosity'],
'seed': best_params['seed'],
'nthread': best_params['nthread'],
'colsample_bytree': best_params['colsample_bytree'],
'subsample': best_params['subsample'],
'eval_metric': best_params['eval_metric'],
'n_estimators': best_params['n_estimators'],
'max_depth': best_params['max_depth'],
}

model = xgb.XGBClassifier(**params_xgb)

# 蒙特卡洛模擬
for j in np.arange(mc_no):
# 每次模擬都重新劃分數據集
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, train_size=0.8, random_state=j)

# 逐步增加特征數量并進行交叉驗證
for i in range(1, n_features + 1):
X_train_subset = X_train.iloc[:, :i]
scores = cross_val_score(model, X_train_subset, y_train, cv=5, scoring='accuracy', n_jobs=-1)
cv_scores[i - 1] += scores.mean()

# 計算平均交叉驗證分數
cv_scores /= mc_no

# 繪圖
plt.figure(figsize=(10, 6))
plt.plot(np.arange(1, n_features + 1), cv_scores)
plt.xlabel('Number of features selected')
plt.ylabel('Cross validation score (correct classifications)')
plt.title('Feature Selection Impact on Model Performance (with Cross Validation)')
plt.grid(True)
plt.tight_layout()
plt.show()

在確定了特征的貢獻度之后,我們利用蒙特卡洛模擬,逐步增加特征數量,觀察不同特征組合下模型的交叉驗證分數,通過繪制不同特征組合下模型的交叉驗證分數,可以直觀地看到增加特征數量對模型性能的影響,可以發現特征并不是越多越好而是會存在一個峰值讓模型精確度達到最高。

這里使用蒙特卡洛模擬的原因是它能夠通過隨機采樣和重復實驗,有效地應對數據中的不確定性,提供對模型在不同特征組合下性能的穩健估計,從而幫助優化特征選擇和提升模型的整體表現。

# 找到最優的特征數
optimal_feature_count = np.argmax(cv_scores) + 1 # 獲取最佳特征數(加1是因為索引從0開始)
optimal_features = X.columns[:optimal_feature_count] # 獲取最佳特征對應的列名

# 輸出最優的特征數和特征名稱
print("Optimal number of features:", optimal_feature_count)
print("Optimal features:", optimal_features.tolist()) # 輸出最佳特征的名稱列表
print("Best CV score:", cv_scores[optimal_feature_count - 1]) # 輸出最佳交叉驗證分數

輸出具體哪幾個特征組合在蒙特卡洛模擬中表現最佳,后續讀者就可以根據賽選出來的特征確定最后的模型,通過這樣做不僅能夠提升精確度,還能減少計算開銷,提升模型的訓練速度和魯棒性。

文章轉自微信公眾號@Python機器學習AI

上一篇:

精確度與參數的完美融合:用可視化解讀模型優化過程

下一篇:

Python實現數據預處理:常見異常值檢驗方法解析

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費