機器學習——特徵工程

gengvvip發表於2020-11-02

連結:https://mp.weixin.qq.com/s/zwXEfIBxIk3dIuhTQpJsXw

GITHUB:https://github.com/fengdu78/Data-Science-Notes/tree/master/9.feature-engineering/FeatureSelectorUsage

 


基於Python的特徵自動化選擇:兩行程式碼完成特徵工程

原創 機器學習初學者 機器學習初學者 5天前

本文介紹一個特徵選擇神器:特徵選擇器是用於減少機器學習資料集的維數的工具,可以傻瓜式地進行特徵選擇,兩行程式碼即可搞定!!

來源:Will Koehrsen

程式碼整理及註釋翻譯:黃海廣

程式碼和資料下載地址:

https://github.com/fengdu78/Data-Science-Notes/tree/master/9.feature-engineering/FeatureSelectorUsage

實現的功能

該選擇器基於Python編寫,有五種方法來標識要刪除的特徵:

  • 缺失值

  • 唯一值

  • 共線特徵

  • 零重要性特徵

  • 低重要性特徵

使用方法

 特徵選擇器(Feature Selector)的用法

在這個Jupyter檔案中, 我們將使用 FeatureSelector 類來選擇資料集中要刪除的特徵,這個類提供五種方法來查詢要刪除的功能:

  1. 查詢缺失分數大於指定閾值的列

  2. 查詢只有唯一值的特徵

  3. 查詢由相關係數大於指定值的共線特徵

  4. 使用梯度提升演算法查詢具有零重要性的特徵

  5. 使用梯度提升演算法查詢中查詢對指定的累積特徵重要性無貢獻的特徵

FeatureSelector 仍在進一步開發中! 歡迎大家在github提交PR.

from feature_selector import FeatureSelector

import pandas as pd

示例資料集

該資料集被用作Kaggle上房屋信用違約風險競賽的(https://www.kaggle.com/c/home-credit-default-risk)  一部分(文末提供下載)。它旨在用於有監督的機器學習分類任務,其目的是預測客戶是否會拖欠貸款。您可以在此處下載整個資料集,我們將處理10,000行的一小部分樣本。

特徵選擇器旨在用於機器學習任務,但可以應用於任何資料集。基於特徵重要性的方法需要使用機器學習的監督學習問題。

train = pd.read_csv('data/credit_example.csv')
train_labels = train['TARGET']
train.head()

5 rows × 122 columns

資料集中有幾個分類列。`FeatureSelector`處理這些特徵重要性的時候使用獨熱編碼。

train = train.drop(columns = ['TARGET'])

實施

FeatureSelector具有用於標識列,以除去五種特徵 :

  • identify_missing(查詢缺失值)

  • identify_single_unique(查詢唯一值)

  • identify_collinear(查詢共線特徵)

  • identify_zero_importance (查詢零重要特徵)

  • identify_low_importance(查詢低重要特徵)

這些方法找到要根據指定條件刪除的特徵。標識的特徵儲存在 FeatureSelector的 ops 屬性(Python詞典)中。我們可以手動刪除已識別的特徵,也可以使用 FeatureSelector中的刪除特徵函式真正刪除特徵。

建立例項

FeatureSelector 僅需要一個在行中具有觀察值而在列中具有特徵的資料集(標準結構化資料)。我們正在處理機器學習的分類問題,因此我們也需要訓練的標籤。

fs = FeatureSelector(data = train, labels = train_labels)

1. 缺失值

第一種特徵選擇方法很簡單:找到丟失分數大於指定閾值的任何列。在此示例中,我們將使用閾值0.6,這對應於查詢缺失值超過60%的特徵。(此方法不會首先對特徵進行一次獨熱編碼)。

fs.identify_missing(missing_threshold=0.6)
17 features with greater than 0.60 missing values.

可以通過 FeatureSelector 物件的ops詞典訪問已確定要刪除的特徵。

missing_features = fs.ops['missing']
missing_features[:10]
['OWN_CAR_AGE',
 'YEARS_BUILD_AVG',
 'COMMONAREA_AVG',
 'FLOORSMIN_AVG',
 'LIVINGAPARTMENTS_AVG',
 'NONLIVINGAPARTMENTS_AVG',
 'YEARS_BUILD_MODE',
 'COMMONAREA_MODE',
 'FLOORSMIN_MODE',
 'LIVINGAPARTMENTS_MODE']

我們還可以繪製資料集中所有列的缺失列分數的直方圖。

fs.plot_missing()

有關缺失分數的詳細資訊,我們可以訪問missing_stats屬性,這是所有特徵缺失分數的DataFrame。

fs.missing_stats.head(10)
 missing_fraction
COMMONAREA_AVG0.6953
COMMONAREA_MODE0.6953
COMMONAREA_MEDI0.6953
NONLIVINGAPARTMENTS_AVG0.6945
NONLIVINGAPARTMENTS_MODE0.6945
NONLIVINGAPARTMENTS_MEDI0.6945
LIVINGAPARTMENTS_MEDI0.6846
LIVINGAPARTMENTS_AVG0.6846
LIVINGAPARTMENTS_MODE0.6846
FONDKAPREMONT_MODE0.6820

2. 唯一值

下一個方法很簡單:找到只有一個唯一值的所有特徵。(這不會對特徵進行獨熱編碼)。

fs.identify_single_unique()
4 features with a single unique value.

 

single_unique = fs.ops['single_unique']
single_unique
['FLAG_MOBIL', 'FLAG_DOCUMENT_10', 'FLAG_DOCUMENT_12', 'FLAG_DOCUMENT_17']

我們可以繪製資料集中每個特徵中唯一值數量的直方圖。

fs.plot_unique()

最後,我們可以訪問一個DataFrame,其中包含每個特徵的唯一值數量。

fs.unique_stats.sample(5)
 nunique
DAYS_EMPLOYED4210
REGION_RATING_CLIENT3
FLAG_DOCUMENT_202
FLAG_DOCUMENT_152
NONLIVINGAREA_MEDI993

3. 共線(高相關性) 特徵

該方法基於皮爾森相關係數找到共線特徵對。對於高於指定閾值(就絕對值而言)的每一對,它標識要刪除的變數之一。我們需要傳遞一個 correlation_threshold

此方法基於在:https://chrisalbon.com/machine_learning/feature_selection/drop_highly_correlated_features/ 中找到的程式碼。

對於每一對,將要刪除的特徵是在DataFrame中列排序方面排在最後的特徵。(除非one_hot = True,否則此方法不會預先對資料進行一次獨熱編碼。因此,僅在數字列之間計算相關性)

fs.identify_collinear(correlation_threshold=0.975)
24 features with a correlation magnitude greater than 0.97.
correlated_features = fs.ops['collinear']
correlated_features[:5]
['AMT_GOODS_PRICE',
 'FLAG_EMP_PHONE',
 'YEARS_BUILD_MODE',
 'COMMONAREA_MODE',
 'ELEVATORS_MODE']

我們可以檢視閾值以上相關性的熱圖。將要刪除的特徵位於x軸上。

fs.plot_collinear()

要繪製資料中的所有相關性,我們可以將 plot_all = True 傳遞給 plot_collinear函式。

fs.plot_collinear(plot_all=True)

fs.identify_collinear(correlation_threshold=0.98)
fs.plot_collinear()
21 features with a correlation magnitude greater than 0.98.

要檢視閾值以上的相關細節,我們訪問record_collinear 屬性,它是一個DataFrame。 drop_feature 將被刪除,並且對於每個將被刪除的特徵,它與 corr_feature可能存在多個相關性,而這些相關性都高於correlation_threshold

fs.record_collinear.head()
 corr_featurecorr_valuedrop_feature
0AMT_CREDIT0.987232AMT_GOODS_PRICE
1DAYS_EMPLOYED-0.999533FLAG_EMP_PHONE
2YEARS_BUILD_AVG0.992120YEARS_BUILD_MODE
3COMMONAREA_AVG0.988074COMMONAREA_MODE
4FLOORSMAX_AVG0.984663FLOORSMAX_MODE

 

4. 零重要特徵 

此方法依賴於機器學習模型來識別要刪除的特徵。因此,它是有標籤的監督學習問題。該方法通過使用LightGBM庫中實現的梯度增強機找到特徵重要性。

為了減少所計算的特徵重要性的差異,預設情況下對模型進行了10次訓練。預設情況下,還使用驗證集(訓練資料的15%)通過提前停止訓練模型,以識別要訓練的最優估計量。可以將以下引數傳遞給identify_zero_importance 方法:

  • task: 可以是 classification 或 regression。指標和標籤必須與任務匹配。

  • eval_metric: 用於提前停止的度量(例如,用於分類的auc或用於迴歸的l2 )。要檢視可用指標的列表,請參閱LightGBM文件:(http://testlightgbm.readthedocs.io/en/latest/Parameters.html#metric-parameters)。

  • n_iterations: 訓練次數。特徵重要性是在訓練執行中平均得出的 (預設為10)。

  • early_stopping: 訓練模型時是否使用提前停止(預設= True)。當驗證集的效能對於指定數量的估計量(此實現中預設為100)不再降低時,提早停止將停止訓練估計量(決策樹)。早停是一種正則化形式,用於防止訓練資料過擬合。

首先對資料進行一次獨熱編碼,以供模型使用。這意味著某些零重要性特徵可以通過一鍵編碼來建立。要檢視單編碼的列,我們可以訪問 FeatureSelectorone_hot_features 。

注意:與其他方法相比,模型的特徵重要性是不確定的(具有少許隨機性)。每次執行此方法時,其結果都可能更改。

fs.identify_zero_importance(task = 'classification', eval_metric = 'auc',
                            n_iterations = 10, early_stopping = True)
Training Gradient Boosting Model

Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[57]	valid_0's auc: 0.760957	valid_0's binary_logloss: 0.250579
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[29]	valid_0's auc: 0.681283	valid_0's binary_logloss: 0.266277
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[50]	valid_0's auc: 0.73881	valid_0's binary_logloss: 0.257822
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[34]	valid_0's auc: 0.720575	valid_0's binary_logloss: 0.262094
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[48]	valid_0's auc: 0.769376	valid_0's binary_logloss: 0.247709
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[35]	valid_0's auc: 0.713877	valid_0's binary_logloss: 0.262254
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[76]	valid_0's auc: 0.753081	valid_0's binary_logloss: 0.251867
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[70]	valid_0's auc: 0.722385	valid_0's binary_logloss: 0.259535
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[45]	valid_0's auc: 0.752703	valid_0's binary_logloss: 0.252175
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[49]	valid_0's auc: 0.757385	valid_0's binary_logloss: 0.250356

81 features with zero importance after one-hot encoding.

執行梯度提升模型需要對特徵進行獨熱編碼。這些特徵儲存在 FeatureSelector的 one_hot_features 屬性中。原始特徵儲存在base_features中。

one_hot_features = fs.one_hot_features
base_features = fs.base_features
print('There are %d original features' % len(base_features))
print('There are %d one-hot features' % len(one_hot_features))
There are 121 original features
There are 134 one-hot features

FeatureSelector 的 data 屬性儲存原始DataFrame。獨熱編碼後, data_all屬性將保留原始資料以及獨熱編碼特徵。

fs.data_all.head(10)

10 rows × 255 columns

我們可以使用多種方法來檢查特徵重要性的結果。首先,我們可以訪問具有零重要性的特徵列表。

zero_importance_features = fs.ops['zero_importance']
zero_importance_features[10:15]
['ORGANIZATION_TYPE_Transport: type 1',
 'ORGANIZATION_TYPE_Security',
 'FLAG_DOCUMENT_15',
 'FLAG_DOCUMENT_17',
 'ORGANIZATION_TYPE_Religion']

畫出特徵重要性

使用 plot_feature_importances 的特徵重要性畫圖將向我們顯示 plot_n 最重要的特徵(按歸一化比例將特徵加總為1)。它還向我們顯示了累積特徵重要性與特徵數量之間的關係。

當我們繪製特徵重要性時,我們可以傳遞一個閾值,該閾值標識達到指定的累積特徵重要性所需的特徵數量。例如,threshold = 0.99將告訴我們佔總重要性的99%所需的特徵數量。

fs.plot_feature_importances(threshold = 0.99, plot_n = 12)

111 features required for 0.99 of cumulative importance

在 FeatureSelector中的 feature_importances 屬性中可以訪問所有的特徵重要性。

fs.feature_importances.head(10)
 featureimportancenormalized_importancecumulative_importance
0EXT_SOURCE_2145.20.0981740.098174
1EXT_SOURCE_3127.70.0863420.184517
2EXT_SOURCE_182.70.0559160.240433
3DAYS_BIRTH71.40.0482760.288709
4DAYS_REGISTRATION64.10.0433400.332049
5DAYS_ID_PUBLISH59.30.0400950.372143
6SK_ID_CURR57.70.0390130.411156
7DAYS_EMPLOYED55.50.0375250.448682
8DAYS_LAST_PHONE_CHANGE47.00.0317780.480460
9AMT_INCOME_TOTAL41.00.0277210.508181

我們可以使用這些結果來僅選擇“”個最重要的特徵。例如,如果我們希望排名前100位的重要性最高,則可以執行以下操作。

one_hundred_features = list(fs.feature_importances.loc[:99, 'feature'])
len(one_hundred_features)
100

5. 低重要性特徵

此方法使用梯度提升演算法(必須首先執行identify_zero_importance)通過查詢達到指定的累積總特徵重要性所需的最低特徵重要性的特徵,來構建特徵重要性。例如,如果我們輸入0.99,則將找到最不重要的特徵重要性,這些特徵總的不到總特徵重要性的99%。

使用此方法時,我們必須已經執行了identify_zero_importance ,並且需要傳遞一個cumulative_importance ,該值佔總特徵重要性的一部分。

**注意:**此方法建立在梯度提升模型的重要性基礎之上,並且還是不確定的。我建議使用不同的引數多次執行這兩種方法,並測試每個結果的特徵集,而不是隻選擇一個數字。

fs.identify_low_importance(cumulative_importance = 0.99)
110 features required for cumulative importance of 0.99 after one hot encoding.
129 features do not contribute to cumulative importance of 0.99.

要刪除的低重要性特徵是指那些對指定的累積重要性無貢獻的特徵。這些特徵也可以在 ops詞典中找到。

low_importance_features = fs.ops['low_importance']
low_importance_features[:5]
['NAME_FAMILY_STATUS_Widow',
 'WEEKDAY_APPR_PROCESS_START_SATURDAY',
 'ORGANIZATION_TYPE_Business Entity Type 2',
 'ORGANIZATION_TYPE_Business Entity Type 1',
 'NAME_INCOME_TYPE_State servant']

刪除特徵

一旦確定了要刪除的特徵,便可以通過多種方式刪除這些特徵。我們可以訪問removal_ops詞典中的任何功能列表,並手動刪除列。我們還可以使用 remove 方法,傳入標識我們要刪除的特徵的方法。

此方法返回結果資料,然後我們可以將其用於機器學習。仍然可以在特徵選擇器的 data 屬性中訪問原始資料。

請注意用於刪除特徵的方法!在使用刪除特徵之前,最好先檢查將要remove的特徵。

train_no_missing = fs.remove(methods = ['missing'])
Removed 17 features.
train_no_missing_zero = fs.remove(methods = ['missing', 'zero_importance'])
Removed 98 features.

要從所有方法中刪除特徵,請傳入 method='all'。在執行此操作之前,我們可以使用check_removal檢查將刪除了多少個特徵。這將返回已被識別為要刪除的所有特徵的列表。

all_to_remove = fs.check_removal()
all_to_remove[10:25]
Total of 156 features identified for removal

['FLAG_OWN_REALTY_Y',
 'FLAG_DOCUMENT_19',
 'ORGANIZATION_TYPE_Agriculture',
 'FLOORSMIN_MEDI',
 'ORGANIZATION_TYPE_Restaurant',
 'NAME_HOUSING_TYPE_With parents',
 'NONLIVINGAREA_MEDI',
 'NAME_INCOME_TYPE_Pensioner',
 'HOUSETYPE_MODE_specific housing',
 'ORGANIZATION_TYPE_Industry: type 5',
 'ORGANIZATION_TYPE_Realtor',
 'OCCUPATION_TYPE_Cleaning staff',
 'ORGANIZATION_TYPE_Industry: type 12',
 'OCCUPATION_TYPE_Realty agents',
 'ORGANIZATION_TYPE_Trade: type 6']

現在我們可以刪除所有已識別的特徵。

train_removed = fs.remove(methods = 'all')
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run

Removed 156 features.

處理獨熱特徵

如果我們檢視返回的DataFrame,可能會注意到原始資料中沒有的幾個新列。這些是在對資料進行獨熱編碼以進行機器學習時建立的。要刪除所有獨熱特徵,我們可以將 keep_one_hot = False 傳遞給 remove 方法。

train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run

Removed 190 features including one-hot features.
print('Original Number of Features', train.shape[1])
print('Final Number of Features: ', train_removed_all.shape[1])
Original Number of Features 121
Final Number of Features:  65

使用所有方法的替代選項

如果我們不想一次執行一個識別方法,則可以使用identify_all 在一次呼叫中執行所有方法。對於此功能,我們需要傳入引數字典以用於每種單獨的識別方法。

以下程式碼在一個呼叫中完成了上述步驟。

fs = FeatureSelector(data = train, labels = train_labels)

fs.identify_all(selection_params = {'missing_threshold': 0.6, 'correlation_threshold': 0.98,
                                    'task': 'classification', 'eval_metric': 'auc',
                                     'cumulative_importance': 0.99})
17 features with greater than 0.60 missing values.

4 features with a single unique value.

21 features with a correlation magnitude greater than 0.98.

Training Gradient Boosting Model

Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[46]	valid_0's auc: 0.743917	valid_0's binary_logloss: 0.254668
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[82]	valid_0's auc: 0.766619	valid_0's binary_logloss: 0.244264
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[55]	valid_0's auc: 0.72614	valid_0's binary_logloss: 0.26157
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[81]	valid_0's auc: 0.756286	valid_0's binary_logloss: 0.251242
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[39]	valid_0's auc: 0.686351	valid_0's binary_logloss: 0.269367
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[41]	valid_0's auc: 0.744124	valid_0's binary_logloss: 0.255549
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[90]	valid_0's auc: 0.761742	valid_0's binary_logloss: 0.249119
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[49]	valid_0's auc: 0.751569	valid_0's binary_logloss: 0.254504
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[76]	valid_0's auc: 0.726789	valid_0's binary_logloss: 0.257181
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[46]	valid_0's auc: 0.714889	valid_0's binary_logloss: 0.260482

80 features with zero importance after one-hot encoding.

115 features required for cumulative importance of 0.99 after one hot encoding.
124 features do not contribute to cumulative importance of 0.99.

150 total features out of 255 identified for removal after one-hot encoding.
train_removed_all_once = fs.remove(methods = 'all', keep_one_hot = True)
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run

Removed 150 features.
fs.feature_importances.head()
 featureimportancenormalized_importancecumulative_importance
0EXT_SOURCE_2165.30.0910740.091074
1EXT_SOURCE_3154.70.0852340.176309
2EXT_SOURCE_197.50.0537190.230028
3DAYS_BIRTH84.60.0466120.276639
4DAYS_REGISTRATION75.90.0418180.318457

由於特徵重要性已更改,因此刪除的特徵數略有差異。由缺失的(missing)、單一的(single_unique)和共線( collinear)確定要刪除的特徵數量將保持不變,因為它們是確定性的,但是由於多次訓練模型,零重要性( zero_importance )和低重要性(low_importance)的特徵數量可能會有所不同。

結論

本筆記本演示瞭如何使用FeatureSelector類從資料集中刪除特徵。此實現中有幾個重要注意事項:

  • 在機器學習模型的多次執行中,特徵重要性將發生變化。

  • 決定是否保留從一個獨熱編碼建立的額外特徵。

  • 為不同的引數嘗試幾個不同的值,以確定哪些引數最適合機器學習任務。

  • 對於相同的引數,缺失的(missing)、單一的(single_unique)和共線(collinear)的輸出將保持不變。

  • 特徵選擇是機器學習工作流中的一個關鍵步驟,它可能需要多次迭代來優化。

    我很感激你對這個專案的任何評論、反饋或幫助。

     

    程式碼和資料下載地址:

    https://github.com/fengdu78/Data-Science-Notes/tree/master/9.feature-engineering/FeatureSelectorUsage

參考

WillKoehrsen:https://github.com/WillKoehrsen/feature-selector

 

 

相關文章