一個(gè)可以進(jìn)行機(jī)器學(xué)習(xí)特征選擇的Python工具
特征選擇 是在數(shù)據(jù)集中尋找和選擇最有用的特征的過程,是 機(jī)器學(xué)習(xí) pipeline中的一個(gè)關(guān)鍵步驟。不必要的特征降低了訓(xùn)練速度,降低了模型的可解釋性,最重要的是,降低了測(cè)試集的泛化性能。
我發(fā)現(xiàn)自己一遍又一遍地為機(jī)器學(xué)習(xí)問題應(yīng)用特別的特征選擇方法,這讓我感到沮喪,于是我在 Python 中構(gòu)建了一個(gè)特征選擇類可在GitHub上找到。 FeatureSelector包括一些最常見的特征選擇方法:
- 缺失值百分比高的特征
- 共線性(高相關(guān)性)的特征
- 在基于樹的模型中零重要性的特征
- 低重要性的特征
- 具有單一唯一值的特征
在本文中,我們將在一個(gè)樣例機(jī)器學(xué)習(xí)數(shù)據(jù)集上使用 FeatureSelector。我們將看到它如何允許我們快速實(shí)現(xiàn)這些方法,從而實(shí)現(xiàn)更有效的工作流。
完整的代碼可在GitHub上獲得,我鼓勵(lì)任何貢獻(xiàn)。 Feature Selector正在開發(fā)中,并將根據(jù)社區(qū)的需要不斷改進(jìn)!
樣例數(shù)據(jù)集
在本例中,我們將使用Kaggle上的Home Credit Default Risk machine learning competition數(shù)據(jù)。(要開始競(jìng)賽,請(qǐng)參見本文)。整個(gè)數(shù)據(jù)集可下載,這里我們將使用一個(gè)例子來演示。
這個(gè)比賽是一個(gè)監(jiān)督分類問題,這是一個(gè)很好的數(shù)據(jù)集,因?yàn)樗性S多缺失的值,許多高度相關(guān)(共線)的特征,和一些不相關(guān)的特征,這對(duì)機(jī)器學(xué)習(xí)模型沒有幫助。
創(chuàng)建實(shí)例
要?jiǎng)?chuàng)建 FeatureSelector類的實(shí)例,我們需要傳入一個(gè)結(jié)構(gòu)化數(shù)據(jù)集,其中包含行和列中的特征。我們可以使用一些只有特征的方法,但是基于重要性的方法也需要訓(xùn)練標(biāo)簽。由于我們有一個(gè)監(jiān)督分類任務(wù),我們將使用一組特征和一組標(biāo)簽。
(確保在與feature_selector.py相同的目錄中運(yùn)行這個(gè)腳本)
方法
特征選擇器有五種方法來查找要?jiǎng)h除的特征。我們可以訪問任何已識(shí)別的特征并手動(dòng)從數(shù)據(jù)中刪除它們,或者使用特征選擇器中的“remove”函數(shù)。
在這里,我們將詳細(xì)介紹每種識(shí)別方法,并展示如何同時(shí)運(yùn)行所有5種方法。 FeatureSelector還具有一些繪圖功能,因?yàn)榭梢暬瘷z查數(shù)據(jù)是機(jī)器學(xué)習(xí)的關(guān)鍵組件。
缺失值
查找要?jiǎng)h除的特征的第一種方法很簡(jiǎn)單:看看哪些特征的缺失值的比例大于某個(gè)閾值。下面的調(diào)用標(biāo)識(shí)了缺失值超過60%的特征。
- fs.identify_missing(missing_threshold = 0.6)
- 17 features with greater than 0.60 missing values.
我們可以看到dataframe中每一列缺失值的比例:
- fs.missing_stats.head()
要查看要?jiǎng)h除的特征,我們?cè)L問 FeatureSelector的 ops屬性,這是一個(gè)Python字典,值為特征列表。
- missing_features = fs.ops['missing']
- missing_features[:5]
- ['OWN_CAR_AGE',
- 'YEARS_BUILD_AVG',
- 'COMMONAREA_AVG',
- 'FLOORSMIN_AVG',
- 'LIVINGAPARTMENTS_AVG']
最后,我們繪制了所有特征缺失值的分布圖:
- fs.plot_missing()
共線性的特征
共線性特征是彼此高度相關(guān)的特征。在機(jī)器學(xué)習(xí)中,由于方差大、模型可解釋性差,導(dǎo)致測(cè)試集泛化性能下降。
方法 identify_collinear根據(jù)指定的相關(guān)系數(shù)值查找共線特征。對(duì)于每一對(duì)相關(guān)的特征,它識(shí)別出要?jiǎng)h除的特征之一(因?yàn)槲覀冎恍枰獎(jiǎng)h除一個(gè)):
- fs.identify_collinear(correlation_threshold = 0.98)
- 21 features with a correlation magnitude greater than 0.98.
我們可以用關(guān)聯(lián)做出一個(gè)清晰的可視化,那就是熱圖。這顯示了在閾值以上至少有一個(gè)相關(guān)性特征的所有特征:
- fs.plot_collinear()
如前所述,我們可以訪問將要?jiǎng)h除的相關(guān)特征的整個(gè)列表,或者查看dataframe中高度相關(guān)的特征對(duì)。
- # list of collinear features to remove
- collinear_features = fs.ops['collinear']
- # dataframe of collinear features
- fs.record_collinear.head()
如果我們想要研究我們的數(shù)據(jù)集,我們還可以通過將 plot_all=True傳遞給調(diào)用來繪制數(shù)據(jù)中所有關(guān)聯(lián)的圖表:
零重要性特征
前兩種方法可以應(yīng)用于任何結(jié)構(gòu)化數(shù)據(jù)集,并且是確定性的——對(duì)于給定的閾值,每次結(jié)果都是相同的。下一種方法只適用于有監(jiān)督的機(jī)器學(xué)習(xí)問題,在這種問題中,我們有訓(xùn)練模型的標(biāo)簽,并且是不確定的。 identify_zero_importance函數(shù)根據(jù)梯度提升機(jī)(GBM)學(xué)習(xí)模型查找不重要的特征。
使用基于樹的機(jī)器學(xué)習(xí)模型,例如增強(qiáng)集成,我們可以找到特征重要性。重要性的絕對(duì)值沒有相對(duì)值重要,相對(duì)值可以用來確定任務(wù)的最相關(guān)的特征。我們還可以通過刪除零重要性的特征來進(jìn)行特征選擇。在基于樹的模型中,不使用零重要性的特征來分割任何節(jié)點(diǎn),因此我們可以在不影響模型性能的情況下刪除它們。
FeatureSelector使用LightGBM庫中的梯度提升機(jī)查找特征重要性。為了減少方差,將GBM的10次訓(xùn)練的特征重要性計(jì)算平均值。此外,使用帶有驗(yàn)證集的early stop(可以選擇關(guān)閉驗(yàn)證集)對(duì)模型進(jìn)行訓(xùn)練,以防止對(duì)訓(xùn)練數(shù)據(jù)的過擬合。
下面的代碼調(diào)用該方法,提取零重要性特征:
我們傳入的參數(shù)如下:
任務(wù):對(duì)應(yīng)問題的“分類”或“回歸”
eval_metric:用于早期停止的指標(biāo)(如果禁用了早期停止,則沒有必要使用該指標(biāo))
n_iteration:訓(xùn)練次數(shù),用來對(duì)特征重要性取平均
early ly_stop:是否使用early stop來訓(xùn)練模型
這次我們得到了兩個(gè)帶有 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),在右邊,我們有相對(duì)于特征數(shù)量的累積重要性。垂直線是在累積重要性的“閾值”處繪制的,在本例中是99%。
對(duì)于基于重要性的方法,有兩個(gè)注意事項(xiàng)值得記?。?/p>
- 梯度提升機(jī)的訓(xùn)練是隨機(jī)的,這意味著每次運(yùn)行模型時(shí)特征輸入都會(huì)發(fā)生變化
這應(yīng)該不會(huì)產(chǎn)生重大影響(最重要的特征不會(huì)突然變得最不重要),但是它會(huì)改變一些特征的順序。它還可以影響識(shí)別的零重要性特征的數(shù)量。如果特征的重要性每次都發(fā)生變化,不要感到驚訝!
- 為了訓(xùn)練機(jī)器學(xué)習(xí)模型,首先對(duì)特征進(jìn)行“獨(dú)熱編碼”。這意味著一些重要性為0的特征可能是在建模過程中添加的獨(dú)熱編碼特征。
當(dāng)我們到達(dá)特征刪除階段時(shí),有一個(gè)選項(xiàng)可以刪除任何添加的獨(dú)熱編碼特征。然而,如果我們?cè)谔卣鬟x擇之后進(jìn)行機(jī)器學(xué)習(xí),我們還是要對(duì)特征進(jìn)行一次獨(dú)熱編碼!
低重要性特征
下一個(gè)方法建立在零重要性函數(shù)的基礎(chǔ)上,利用模型的特征輸入進(jìn)行進(jìn)一步的選擇。函數(shù) identify_low_importance查找對(duì)總重要性沒什么貢獻(xiàn)的最低重要性的特征。
例如,下面的調(diào)用找到了最不重要的特征,這些特征對(duì)于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.
基于累積重要性圖和這些信息,梯度提升機(jī)認(rèn)為許多特征與學(xué)習(xí)無關(guān)。同樣,這種方法的結(jié)果將在每次訓(xùn)練運(yùn)行時(shí)發(fā)生變化。
要查看dataframe中的所有重要特征:
- fs.feature_importances.head(10)
low_importance方法借鑒了使用主成分分析(PCA)的一種方法,這種方法通常只保留需要保留一定百分比的方差(如95%)的PC。占總重要性的百分比是基于相同的思想。
基于特征重要性的方法只有在我們使用基于樹的模型進(jìn)行預(yù)測(cè)時(shí)才真正適用。除了隨機(jī)性之外,基于重要性的方法是一種黑盒方法,因?yàn)槲覀儾恢罏槭裁茨P驼J(rèn)為這些特征是無關(guān)的。如果使用這些方法,請(qǐng)多次運(yùn)行它們以查看結(jié)果的變化,也許還可以創(chuàng)建具有不同參數(shù)的多個(gè)數(shù)據(jù)集進(jìn)行測(cè)試!
單一唯一值的特征
最后一個(gè)方法是相當(dāng)基本的:找到任何只有一個(gè)惟一值的列。只有一個(gè)惟一值的特征對(duì)機(jī)器學(xué)習(xí)沒有用處,因?yàn)檫@個(gè)特征的方差為零。例如,基于樹的模型永遠(yuǎn)不能對(duì)只有一個(gè)值的特征進(jìn)行分割(因?yàn)闆]有分組來劃分觀察結(jié)果)。
這里沒有參數(shù)選擇,不像其他方法:
- fs.identify_single_unique()
- 4 features with a single unique value.
我們可以繪制每個(gè)類別中唯一值的數(shù)量直方圖:
- fs.plot_unique()
需要記住的一點(diǎn)是,在默認(rèn)情況下計(jì)算panda中的惟一值之前先刪除 NaNs 。
去除特征
一旦我們確定了要丟棄的特征,我們有兩個(gè)選項(xiàng)來刪除它們。所有要?jiǎng)h除的特征都存儲(chǔ)在 FeatureSelector的 ops字典中,我們可以使用列表手動(dòng)刪除特征。另一個(gè)選項(xiàng)是使用“remove”內(nèi)置函數(shù)。
對(duì)于這個(gè)方法,我們傳入用于刪除特征的 方法。如果我們想使用所有實(shí)現(xiàn)的方法,我們只需傳入 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.
此方法返回一個(gè)刪除了特征的dataframe。還可以刪除機(jī)器學(xué)習(xí)過程中創(chuàng)建的獨(dú)熱編碼特征:
- train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
- Removed 187 features including one-hot features.
在繼續(xù)操作之前,檢查將被刪除的特征可能是一個(gè)好主意!原始數(shù)據(jù)集存儲(chǔ)在 FeatureSelector的 data 屬性中作為備份!
一次運(yùn)行所有方法
我們可以使用 identify_all而不是單獨(dú)使用這些方法。這需要每個(gè)方法的參數(shù)字典:
請(qǐng)注意,由于我們重新運(yùn)行了模型,總特征的數(shù)量將發(fā)生變化。然后可以調(diào)用“remove”函數(shù)來刪除這些特征。
總結(jié)
在訓(xùn)練機(jī)器學(xué)習(xí)模型之前,F(xiàn)eature Selector類實(shí)現(xiàn)了幾個(gè)常見的刪除特征的操作。它提供了識(shí)別要?jiǎng)h除的特征以及可視化功能。方法可以單獨(dú)運(yùn)行,也可以一次全部運(yùn)行,以實(shí)現(xiàn)高效的工作流。
missing、 collinear和 single_unique方法是確定的,而基于特征重要性的方法將隨著每次運(yùn)行而改變。特征選擇,就像機(jī)器學(xué)習(xí)領(lǐng)域,很大程度上是經(jīng)驗(yàn)主義的,需要測(cè)試多個(gè)組合來找到最佳答案。在pipeline中嘗試幾種配置是最佳實(shí)踐,特征選擇器提供了一種快速評(píng)估特征選擇參數(shù)的方法。