機器學習中的"食材挑選術":特征選擇方法
想象你要做一道美食,面對琳瑯滿目的食材,優秀的廚師不會把所有原料都扔進鍋里,而是會選擇最適合的幾種。
在機器學習中,特征選擇就是這個挑選過程,從原始數據中選擇對預測目標最有用的特征(列),就像挑選優質食材一樣重要。
1. 什么是特征選擇?
特征選擇是機器學習中一個至關重要的步驟,它從原始數據的眾多特征中挑選出對模型最有價值的子集。
簡單來說,就是從一堆可能影響結果的因素中,找出那些真正重要的因素,把不重要的、重復的或者有干擾的特征去掉。
為什么要做特征選擇呢?主要有以下幾個原因:
- 提高模型性能:少而精的特征能幫助模型更專注于重要的信息,避免被無關特征干擾,從而提高準確性。
- 加快訓練速度:特征少了,模型需要處理的數據量就小了,訓練時間自然也就縮短了。
- 降低過擬合風險:過多的特征可能讓模型記住噪聲,而不是學習到真正的規律。特征選擇能幫助模型更好地泛化。
- 提升可解釋性:特征少了,模型的決策過程更容易理解,這對很多實際應用場景非常重要。
2. 三大特征選擇方法
根據特征選擇與模型訓練過程的關系,主要可以分為以下三類方法:
2.1. 過濾式:先"篩"后"用"
過濾式方法就像用篩子篩沙子一樣,先根據特征本身的統計特性對特征進行評估和篩選,然后再把選出來的特征交給模型使用。
這個過程完全獨立于機器學習模型。
常見的過濾式方法包括:
- 方差閾值:去掉那些幾乎不變的特征(方差低于某個閾值)
- 卡方檢驗:評估分類問題中特征與目標變量的獨立性
- 相關系數:計算特征與目標變量之間的相關性
下面的代碼演示如何使用過濾式方法來進行特征選擇,使用卡方檢驗(SelectBest):
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.model_selection import train_test_split
# 加載數據集
iris = load_iris()
X, y = iris.data, iris.target
# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 創建過濾式選擇器,選擇2個最佳特征
selector = SelectKBest(score_func=f_classif, k=2)
X_train_selected = selector.fit_transform(X_train, y_train)
X_test_selected = selector.transform(X_test)
# 查看選中的特征
selected_features = selector.get_support(indices=True)
print(f"選中的特征索引: {selected_features}")
print(f"特征得分: {selector.scores_}")
# 輸出特征選擇后的數據維度
print(f"原始訓練集特征數: {X_train.shape[1]}")
print(f"選擇后訓練集特征數: {X_train_selected.shape[1]}")
## 輸出結果:
'''
選中的特征索引: [2 3]
特征得分: [ 74.7572012 33.41979913 713.45534904 526.54162416]
原始訓練集特征數: 4
選擇后訓練集特征數: 2
'''
最后選擇的特征是2和3,也就是后2個特征(特征索引是從0開始的)。
從特征得分來看看,后2個特征也是得分最高的。
2.2. 包裹式:帶著模型一起選
包裹式方法就像帶著模型去"試衣"一樣,把特征子集當作不同的"衣服",讓模型試穿(訓練)后看看效果如何。
根據模型的表現(比如準確性)來決定哪些特征組合最好。
常見的包裹式方法包括:
- 遞歸特征消除(
RFE):不斷移除最不重要的特征,直到達到指定數量 - 窮舉搜索:嘗試所有可能的特征組合(計算成本很高)
下面的代碼示例使用遞歸特征消除(RFE):
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
# 創建隨機森林分類器
model = RandomForestClassifier(random_state=42)
# 創建遞歸特征消除選擇器
selector = RFE(model, n_features_to_select=2, step=1)
selector = selector.fit(X_train, y_train)
# 查看選中的特征
selected_features = selector.get_support(indices=True)
print(f"選中的特征: {selected_features}")
print(f"特征排名: {selector.ranking_}")
# 特征選擇后的數據
X_train_selected = selector.transform(X_train)
X_test_selected = selector.transform(X_test)
# 輸出特征選擇后的數據維度
print(f"原始訓練集特征數: {X_train.shape[1]}")
print(f"選擇后訓練集特征數: {X_train_selected.shape[1]}")
## 輸出結果:
'''
選中的特征: [2 3]
特征排名: [2 3 1 1]
原始訓練集特征數: 4
選擇后訓練集特征數: 2
'''
選擇的特征也是2和3,從特征排名來看,前兩個特征排名2和3,后兩個特征并列排名第一。
2.3. 嵌入式:在模型里自然選擇
嵌入式方法就像在模型里內置了一個"挑食"機制,讓模型在訓練過程中自然地傾向于使用某些特征,而忽略其他特征。
這種方法通常通過正則化來實現。
常見的嵌入式方法包括:
- L1正則化(
Lasso):會自動將不重要特征的系數縮放到零 - 樹模型中的特征重要性:如隨機森林、梯度提升樹等模型自帶的特征重要性評分
代碼示例:
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LassoCV
# 創建帶L1正則化的邏輯回歸模型
model = LassoCV(random_state=42)
# 創建嵌入式選擇器
selector = SelectFromModel(model, threshold='median')
selector = selector.fit(X_train, y_train)
# 查看選中的特征
selected_features = selector.get_support(indices=True)
print(f"選中的特征: {selected_features}")
# 特征選擇后的數據
X_train_selected = selector.transform(X_train)
X_test_selected = selector.transform(X_test)
# 輸出特征選擇后的數據維度
print(f"原始訓練集特征數: {X_train.shape[1]}")
print(f"選擇后訓練集特征數: {X_train_selected.shape[1]}")
## 輸出結果:
'''
選中的特征: [2 3]
原始訓練集特征數: 4
選擇后訓練集特征數: 2
'''
同樣,最終選擇的特征也是2和3。
3. 三種方法的對比
選擇哪種特征選擇方法,取決于你的具體需求和場景,下面是三種方法的比較:
| 方法類型 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 過濾式 | 計算效率高,不依賴模型 | 可能忽略特征與模型的關系 | 特征數量較少,對模型不敏感的情況 |
| 包裹式 | 直接考慮模型性能,效果通常較好 | 計算開銷大,容易過擬合 | 特征數量適中,對性能要求高的情況 |
| 嵌入式 | 計算效率較高,考慮了特征與模型的關系 | 通常需要模型本身支持特征選擇 | 需要模型具有稀疏性的情況 |
4. 總結
特征選擇是機器學習流程中不可忽略的重要環節。
在實際應用中,我們可以嘗試多種方法,觀察它們對模型性能的影響,有時候,結合多種方法甚至能取得更好的效果。
記住,特征選擇不是一成不變的規則,而是一門需要根據數據和模型不斷調整的藝術。

浙公網安備 33010602011771號