在上圖的三個小節中,A、D、G分別展示了隨著特征數量減少,交叉驗證誤差的變化??梢钥吹?,每條折線代表了交叉驗證的過程,模型通過反復訓練和測試來找到使誤差最小的特征子集,這種方法能有效避免過擬合問題,接下來作者將嘗試這樣的一個特征賽選過程
隨機森林是集成學習的一種,通過構建多棵決策樹來完成分類或回歸任務,它的優勢在于能夠自動評估特征的重要性,但為了進一步提高模型性能,可以使用遞歸特征消除(RFE)方法,逐步去除不重要的特征,保留對模型影響最大的特征
RFE的原理是基于一個基礎模型,不斷移除最不重要的特征,直到獲得最佳特征子集,結合交叉驗證,RFE可以保證在不同數據劃分下都能找到最佳的特征組合,進一步提升模型的穩健性,詳細的解釋參考往期文章——特征選擇(嵌入法)—— 遞歸特征消除 RFE、 RFE-CV
本文將基于一個多特征二分類數據集,使用RFE結合隨機森林進行特征選擇,并可視化展示每折結果及最優特征數組合
代碼實現
導入必要的庫和數據
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
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'])
df.head()
數據集來源于一個名為“Chabuhou.csv”的文件,目標變量為電擊復律(Electrical_cardioversion),將使用BorutaShap篩選出對目標變量預測最有用的特征
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFECV
from sklearn.model_selection import StratifiedKFold
# 初始化隨機森林分類器
clf = RandomForestClassifier(random_state=42)
# 定義StratifiedKFold用于交叉驗證
cv = StratifiedKFold(n_splits=5)
# 遞歸特征消除和交叉驗證
rfecv = RFECV(estimator=clf, step=1, cv=cv, scoring='accuracy')
rfecv.fit(X_train, y_train)
# 打印最佳特征數量
print(f"Optimal number of features: {rfecv.n_features_}")
# 獲取交叉驗證每一折的分數
cv_results = rfecv.cv_results_
# 取出5次交叉驗證的單獨分數
fold_scores = [cv_results[f'split{i}_test_score'] for i in range(5)]
mean_scores = cv_results['mean_test_score'] # 計算平均得分
# 輸出選擇的特征列
selected_features = X_train.columns[rfecv.support_]
print(f"Selected features: {list(selected_features)}")
df_selected = df[selected_features]
df_selected.head()
這里使用遞歸特征消除(RFECV)結合隨機森林分類器對特征進行篩選,找出了對模型準確性影響最大的18個特征。通過5折交叉驗證評估每個特征子集的性能,最終選擇了使模型表現最佳的特征組合,這些特征包括“年齡”、“BMI”、“左房直徑”等生理和手術相關的指標,表明它們在預測結果(如心房顫動類型)時最具影響力,結果表格展示了優化后的特征數據集,列出了篩選出的特征及其對應的樣本數據,方便后續的模型訓練和分析,這一步驟不僅提升了模型的精度,還減少了不必要的特征,增強了模型的可解釋性和計算效率
plt.figure(figsize=(12, 8), dpi=1200)
plt.title('Recursive Feature Elimination with Cross-Validation (RFCV)', fontsize=16, fontweight='bold', pad=20)
plt.xlabel('Number of features selected', fontsize=14, labelpad=15)
plt.ylabel('Cross-validation score (accuracy)', fontsize=14, labelpad=15)
# 設置背景顏色
plt.gca().set_facecolor('#f7f7f7')
# 繪制每一條灰色線,表示5次交叉驗證
for i in range(5):
plt.plot(range(1, len(fold_scores[i]) + 1), fold_scores[i], marker='o', color='gray', linestyle='-',
linewidth=0.8, alpha=0.6)
# 繪制淡黑色線,表示平均交叉驗證得分
plt.plot(range(1, len(mean_scores) + 1), mean_scores, marker='o', color='#696969', linestyle='-',
linewidth=3, label='Mean CV Accuracy')
# 繪制最佳特征數的垂直線
plt.axvline(x=rfecv.n_features_, color='#E76F51', linestyle='--', linewidth=2, label=f'Optimal = {rfecv.n_features_}')
plt.legend(fontsize=12, loc='best', frameon=True, shadow=True, facecolor='white', framealpha=0.9)
plt.grid(True, which='both', linestyle='--', linewidth=0.5, alpha=0.7)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)
plt.savefig('分類.pdf', format='pdf', bbox_inches='tight')
plt.show()
圖形展示了遞歸特征消除結合交叉驗證(RFECV)在特征選擇過程中的表現,橫軸表示被選擇的特征數量,縱軸表示交叉驗證的準確率(accuracy)
從圖中可以看出,選擇18個特征時,模型的交叉驗證準確率達到了峰值,意味著這是一個最佳特征子集,進一步增加特征沒有帶來顯著的準確率提升,反而可能增加模型的復雜度或導致輕微的過擬合,因此,18個特征是最優的選擇
在模型優化和特征選擇過程中,目標函數的選擇至關重要,不同的目標函數會影響模型的優化方向以及最終的評估結果,比如,分類問題中常用的目標函數包括準確率(accuracy)、ROC AUC、F1-score等,如果數據集存在類別不均衡問題,單純依賴準確率可能會誤導模型的性能評估,因為模型可能通過偏向多數類獲得較高的準確率,這時,選擇ROC AUC或F1-score作為目標函數,能夠更好地衡量模型在區分不同類別時的表現。因此,在特征選擇和模型評估過程中,目標函數的合理選擇能夠有效提升模型的泛化能力,避免因不合適的評估標準導致模型過擬合或效果不理想