作者:Will Koehrsen
編譯:ronghuaiyang
導讀
用這個工具可以高效的構建機器學習工作流程。一起來了解一下這個工具吧。
特徵選擇是在數據集中尋找和選擇最有用的特徵的過程,是機器學習pipeline中的一個關鍵步驟。不必要的特徵降低了訓練速度,降低了模型的可解釋性,最重要的是,降低了測試集的泛化性能。
我發現自己一遍又一遍地為機器學習問題應用特別的特徵選擇方法,這讓我感到沮喪,於是我在Python中構建了一個特徵選擇類可在GitHub上找到。 FeatureSelector包括一些最常見的特徵選擇方法:
- 缺失值百分比高的特徵
- 共線性(高相關性)的特徵
- 在基於樹的模型中零重要性的特徵
- 低重要性的特徵
- 具有單一唯一值的特徵
在本文中,我們將在一個樣例機器學習數據集上使用 FeatureSelector。我們將看到它如何允許我們快速實現這些方法,從而實現更有效的工作流。
完整的代碼可在GitHub上獲得,我鼓勵任何貢獻。 Feature Selector正在開發中,並將根據社區的需要不斷改進!
樣例數據集
在本例中,我們將使用Kaggle上的Home Credit Default Risk machine learning competition數據。(要開始競賽,請參見本文)。整個數據集可下載,這裡我們將使用一個例子來演示。
樣例數據,TARGET是分類的標籤
這個比賽是一個監督分類問題,這是一個很好的數據集,因為它有許多缺失的值,許多高度相關(共線)的特徵,和一些不相關的特徵,這對機器學習模型沒有幫助。
創建實例
要創建 FeatureSelector類的實例,我們需要傳入一個結構化數據集,其中包含行和列中的特徵。我們可以使用一些只有特徵的方法,但是基於重要性的方法也需要訓練標籤。由於我們有一個監督分類任務,我們將使用一組特徵和一組標籤。
(確保在與feature_selector.py相同的目錄中運行這個腳本)
方法
特徵選擇器有五種方法來查找要刪除的特徵。我們可以訪問任何已識別的特徵並手動從數據中刪除它們,或者使用特徵選擇器中的「remove」函數。
在這裡,我們將詳細介紹每種識別方法,並展示如何同時運行所有5種方法。 FeatureSelector還具有一些繪圖功能,因為可視化檢查數據是機器學習的關鍵組件。
缺失值
查找要刪除的特徵的第一種方法很簡單:看看哪些特徵的缺失值的比例大於某個閾值。下面的調用標識了缺失值超過60%的特徵。
fs.identify_missing(missing_threshold = 0.6)
17 features with greater than 0.60 missing values.
我們可以看到dataframe中每一列缺失值的比例:
fs.missing_stats.head()
要查看要刪除的特徵,我們訪問 FeatureSelector的 ops屬性,這是一個Python字典,值為特徵列表。
missing_features = fs.ops['missing']
missing_features[:5]
['OWN_CAR_AGE',
'YEARS_BUILD_AVG',
'COMMONAREA_AVG',
'FLOORSMIN_AVG',
'LIVINGAPARTMENTS_AVG']
最後,我們繪製了所有特徵缺失值的分布圖:
fs.plot_missing()
共線性的特徵
共線性特徵是彼此高度相關的特徵。在機器學習中,由於方差大、模型可解釋性差,導致測試集泛化性能下降。
方法 identify_collinear根據指定的相關係數值查找共線特徵。對於每一對相關的特徵,它識別出要刪除的特徵之一(因為我們只需要刪除一個):
fs.identify_collinear(correlation_threshold = 0.98)
21 features with a correlation magnitude greater than 0.98.
我們可以用關聯做出一個清晰的可視化,那就是熱圖。這顯示了在閾值以上至少有一個相關性特徵的所有特徵:
fs.plot_collinear()
如前所述,我們可以訪問將要刪除的相關特徵的整個列表,或者查看dataframe中高度相關的特徵對。
# list of collinear features to remove
collinear_features = fs.ops['collinear']
# dataframe of collinear features
fs.record_collinear.head()
如果我們想要研究我們的數據集,我們還可以通過將 plot_all=True傳遞給調用來繪製數據中所有關聯的圖表:
零重要性特徵
前兩種方法可以應用於任何結構化數據集,並且是確定性的——對於給定的閾值,每次結果都是相同的。下一種方法只適用於有監督的機器學習問題,在這種問題中,我們有訓練模型的標籤,並且是不確定的。 identify_zero_importance函數根據梯度提升機(GBM)學習模型查找不重要的特徵。
使用基於樹的機器學習模型,例如增強集成,我們可以找到特徵重要性。重要性的絕對值沒有相對值重要,相對值可以用來確定任務的最相關的特徵。我們還可以通過刪除零重要性的特徵來進行特徵選擇。在基於樹的模型中,不使用零重要性的特徵來分割任何節點,因此我們可以在不影響模型性能的情況下刪除它們。
FeatureSelector使用LightGBM庫中的梯度提升機查找特徵重要性。為了減少方差,將GBM的10次訓練的特徵重要性計算平均值。此外,使用帶有驗證集的early stop(可以選擇關閉驗證集)對模型進行訓練,以防止對訓練數據的過擬合。
下面的代碼調用該方法,提取零重要性特徵:
我們傳入的參數如下:
任務:對應問題的「分類」或「回歸」
eval_metric:用於早期停止的指標(如果禁用了早期停止,則沒有必要使用該指標)
n_iteration:訓練次數,用來對特徵重要性取平均
early ly_stop:是否使用early stop來訓練模型
這次我們得到了兩個帶有 plot_feature_importances的圖:
# plot the feature importances
fs.plot_feature_importances(threshold = 0.99, plot_n = 12)
124 features required for 0.99 of cumulative importance
在左邊,我們有 plot_n最重要的特徵(按照歸一化重要性繪製,總和為1),在右邊,我們有相對於特徵數量的累積重要性。垂直線是在累積重要性的「閾值」處繪製的,在本例中是99%。
對於基於重要性的方法,有兩個注意事項值得記住:
- 梯度提升機的訓練是隨機的,這意味著每次運行模型時特徵輸入都會發生變化
這應該不會產生重大影響(最重要的特徵不會突然變得最不重要),但是它會改變一些特徵的順序。它還可以影響識別的零重要性特徵的數量。如果特徵的重要性每次都發生變化,不要感到驚訝!
- 為了訓練機器學習模型,首先對特徵進行「獨熱編碼」。這意味著一些重要性為0的特徵可能是在建模過程中添加的獨熱編碼特徵。
當我們到達特徵刪除階段時,有一個選項可以刪除任何添加的獨熱編碼特徵。然而,如果我們在特徵選擇之後進行機器學習,我們還是要對特徵進行一次獨熱編碼!
低重要性特徵
下一個方法建立在零重要性函數的基礎上,利用模型的特徵輸入進行進一步的選擇。函數 identify_low_importance查找對總重要性沒什麼貢獻的最低重要性的特徵。
例如,下面的調用找到了最不重要的特徵,這些特徵對於99%的總重要性是不需要的:
fs.identify_low_importance(cumulative_importance = 0.99)
123 features required for cumulative importance of 0.99 after one hot encoding.
116 features do not contribute to cumulative importance of 0.99.
基於累積重要性圖和這些信息,梯度提升機認為許多特徵與學習無關。同樣,這種方法的結果將在每次訓練運行時發生變化。
要查看dataframe中的所有重要特徵:
fs.feature_importances.head(10)
low_importance方法借鑑了使用主成分分析(PCA)的一種方法,這種方法通常只保留需要保留一定百分比的方差(如95%)的PC。占總重要性的百分比是基於相同的思想。
基於特徵重要性的方法只有在我們使用基於樹的模型進行預測時才真正適用。除了隨機性之外,基於重要性的方法是一種黑盒方法,因為我們不知道為什麼模型認為這些特徵是無關的。如果使用這些方法,請多次運行它們以查看結果的變化,也許還可以創建具有不同參數的多個數據集進行測試!
單一唯一值的特徵
最後一個方法是相當基本的:找到任何只有一個惟一值的列。只有一個惟一值的特徵對機器學習沒有用處,因為這個特徵的方差為零。例如,基於樹的模型永遠不能對只有一個值的特徵進行分割(因為沒有分組來劃分觀察結果)。
這裡沒有參數選擇,不像其他方法:
fs.identify_single_unique()
4 features with a single unique value.
我們可以繪製每個類別中唯一值的數量直方圖:
fs.plot_unique()
需要記住的一點是,在默認情況下計算panda中的惟一值之前先刪除 NaNs 。
去除特徵
一旦我們確定了要丟棄的特徵,我們有兩個選項來刪除它們。所有要刪除的特徵都存儲在 FeatureSelector的 ops字典中,我們可以使用列表手動刪除特徵。另一個選項是使用「remove」內置函數。
對於這個方法,我們傳入用於刪除特徵的 方法。如果我們想使用所有實現的方法,我們只需傳入 methods='all'。
# Remove the features from all methods (returns a df)
train_removed = fs.remove(methods = 'all')
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run
Removed 140 features.
此方法返回一個刪除了特徵的dataframe。還可以刪除機器學習過程中創建的獨熱編碼特徵:
train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
Removed 187 features including one-hot features.
在繼續操作之前,檢查將被刪除的特徵可能是一個好主意!原始數據集存儲在 FeatureSelector的 data 屬性中作為備份!
一次運行所有方法
我們可以使用 identify_all而不是單獨使用這些方法。這需要每個方法的參數字典:
請注意,由於我們重新運行了模型,總特徵的數量將發生變化。然後可以調用「remove」函數來刪除這些特徵。
總結
在訓練機器學習模型之前,Feature Selector類實現了幾個常見的刪除特徵的操作。它提供了識別要刪除的特徵以及可視化功能。方法可以單獨運行,也可以一次全部運行,以實現高效的工作流。
missing、 collinear和 single_unique方法是確定的,而基於特徵重要性的方法將隨著每次運行而改變。特徵選擇,就像機器學習領域,很大程度上是經驗主義的,需要測試多個組合來找到最佳答案。在pipeline中嘗試幾種配置是最佳實踐,特徵選擇器提供了一種快速評估特徵選擇參數的方法。
英文原文:https://towardsdatascience.com/a-feature-selection-tool-for-machine-learning-in-python-b64dd23710f0
請長按或掃描二維碼關注本公眾號