特徵選擇技術總結

deephub發表於2022-11-24

在本文中,我們將回顧特性選擇技術並回答為什麼它很重要以及如何使用python實現它。

本文還可以幫助你解答以下的面試問題:

  • 什麼是特徵選擇?
  • 說出特性選擇的一些好處
  • 你知道哪些特徵選擇技巧?
  • 區分單變數、雙變數和多變數分析。
  • 我們能用PCA來進行特徵選擇嗎?
  • 前向特徵選擇和後向特徵選擇的區別是什麼?

什麼是特徵選擇,為什麼它很重要?

特性選擇是選擇與ML模型更加一致、非冗餘和更相關的基本特性的過程。在ML專案中使用特性選擇是必要的,因為:

  • 它有助於減少資料集的大小和複雜性,並且可以使用更少的時間來訓練模型及進行推理;
  • 具有較少特徵的簡單機器學習模型更容易理解和解釋;
  • 它可以避免過度擬合。更多特徵使模型變得更加複雜,並帶來維度災難(誤差隨著特徵數量的增加而增加)。

特徵選擇方法有哪些?

有兩種常見的方法可以處理特徵選擇:

1、前向特徵選擇。使用一個特徵(或一小部分)擬合模型並不斷新增特徵,直到新加的模型對ML 模型指標沒有影響。可以使用相關分析等方法(例如,基於 Pearson 係數),或者您可以從單個特徵或特徵子集開始擬合模型。

2、向後特徵選擇。這是 與1的相反方法。使用這種方法,可以從完整的特徵集開始,然後迭代地逐個減少功能,減少特徵的同時只要 ML 模型指標保持不變即可。

我們可以將一些流行的方法總結成以下幾種分類:

  • Filtered-based基於過濾的方法:這種方法是最直接的,這種特徵的選擇獨立於任何機器學習演算法。使用統計資料(例如 Pearson 相關係數、LDA 等),根據每個特徵如何影響目標結果來選擇重要特徵。這是計算密集度最低且速度最快的方法。
  • Wrapper 基於包裝器方法:這種方法根據 ML 訓練指標結果選擇特徵。每個子集在訓練後得到一個分數,然後新增或刪除特徵,並在最終在達到所需的 ML 指標閾值時停止,這種方法可以是前向、後向或遞迴的。這是計算最密集的方法,因為需要訓練許多 ML 模型,並且逐一進行判斷選擇。
  • Embedded 基於嵌入的方法:這種方法更加複雜,它將上面兩種方法組合在一起。這種方法最流行的例子是 LASSO 和樹型演算法。

使用Python進行特徵選擇

本文將使用一個金融科技資料集,該資料集包含過去貸款申請人的資料,如信用等級、申請人收入、DTI和其他特徵。最後的目標是使用ML預測貸款申請人是否可能違約(無法支付貸款)。這有助於企業做出決策,例如拒絕貸款申請、減少貸款金額或以更高的利率向風險較高的申請人放貸。我用來執行程式碼的環境是Kaggle。

讓我們開始並載入資料集:

 %matplotlib inline 
 from matplotlib import pyplot as plt
 pd.set_option('display.float_format', lambda x: '%.0f' % x) 
 loan = pd.read_csv('../input/lending-club/accepted_2007_to_2018Q4.csv.gz', compression='gzip', low_memory=True)
 loan.info

資料集包含超過200萬行(我們稱之為樣本)和超過150個特徵。這是相當大的資料量,這些資料通常包含了很多“噪聲”它對我們的ML工作沒有任何的幫助,因此我們需要在ML訓練發生之前驗證資料的質量和適用性。

第一步:獲得專業的領域知識

對如此詳盡的特徵列表進行分析可能需要大量的計算資源和時間。所以我們需要詳細瞭解每個資料集的屬性。

諮詢並詢問行業的專家哪些特徵是必要的;例如,在金融科技資料集的例子中可能需要諮詢每天執行貸款評估的信貸員。信貸員將確切地知道是什麼驅動了他們的決策過程(我們其實是希望將這部分過程透過ML實現自動化)。

假設我們已得到了以下建議(請參閱下面的程式碼片段)。雖然我們應該對這些建議保持謹慎,但它為我們開始初步工作提供了一個很好的基礎,我們可以進一步改進。

 loans = loan[['id', 'loan_amnt', 'term','int_rate', 'sub_grade', 'emp_length','grade', 'annual_inc', 'loan_status', 'dti', 'mths_since_recent_inq', 'revol_util', 'bc_open_to_buy', 'bc_util', 'num_op_rev_tl']] 
 
 #remove missing values 
 loans = loans.dropna()

花合理的時間來理解資料集中每個特徵的含義:

  • loan_amnt -借款人申請貸款的清單金額。
  • term -償還貸款的次數,其中的值以月為單位,可以是36或60。
  • int_rate -貸款的利率
  • sub_grade -根據借款人的信用記錄分配貸款等級分數
  • emp_length -借款者的就業年限。
  • home_ownership-借款人提供的房屋所有權狀況(例如,租金、所有權、抵押貸款等)
  • annual_inc -借款人提供的自我報告的年收入
  • addr_state-借款人在貸款申請中提供的狀態
  • dti -用借款人每月償還的債務總額(不包括按揭)除以借款人每月收入計算的比率。
  • mths_since_recent_inq-最近一次查詢的月份
  • revol_util - 迴圈額度利用率,或借款人使用的信貸金額相對於所有可用的迴圈信貸。
  • bc_open_to_buy - 銀行卡的總開放購買量
  • bc_util - 所有銀行卡賬戶的總流動餘額與高信用/信用限額的比率
  • num_op_rev_tl - 開戶數
  • loan_status - 當前貸款狀態(例如,完全支付或登出)。這就是我們要用模型預測的標籤。

在進行下一步工作之前,需要先執行資料處理步驟。步驟包括缺失值、異常值和分類特徵處理。

 loans = loans.dropna() 
 
 q_low = loans["annual_inc"].quantile(0.08) 
 q_hi = loans["annual_inc"].quantile(0.92) loans = loans[(loans["annual_inc"] < q_hi) & (loans["annual_inc"] > q_low)] 
 loans = loans[(loans['dti'] <=45)] 
 q_hi = loans['bc_open_to_buy'].quantile(0.95) 
 loans = loans[(loans['bc_open_to_buy'] < q_hi)] 
 loans = loans[(loans['bc_util'] <=160)] 
 loans = loans[(loans['revol_util'] <=150)] 
 loans = loans[(loans['num_op_rev_tl'] <=35)] 
 
 cleaner_app_type = {"term": {" 36 months": 1.0, " 60 months": 2.0},
      "sub_grade": {"A1": 1.0, "A2": 2.0, "A3": 3.0, "A4": 4.0,
           "A5": 5.0, "B1": 11.0, "B2": 12.0, "B3": 13.0, "B4": 14.0,
           "B5": 15.0, "C1": 21.0, "C2": 22.0, "C3": 23.0, "C4":
           24.0, "C5": 25.0, "D1": 31.0, "D2": 32.0, "D3": 33.0,
           "D4": 34.0, "D5": 35.0, "E1": 41.0, "E2": 42.0, "E3":
           43.0, "E4": 44.0, "E5": 45.0, "F1": 51.0, "F2": 52.0,
           "F3": 53.0, "F4": 54.0, "F5": 55.0, "G1": 61.0, "G2":
           62.0, "G3": 63.0, "G4": 64.0, "G5": 65.0, }, 
       "emp_length": {"< 1 year": 0.0, '1 year': 1.0, '2 years': 2.0,
           '3 years': 3.0, '4 years': 4.0, '5 years': 5.0, '6 years':
            6.0, '7 years': 7.0, '8 years': 8.0, '9 years': 9.0, '10+
            years': 10.0 } 
        } 
 loans = loans.replace(cleaner_app_type)

在預選特徵之後,下一步是進行單變數分析。分析單個特徵時可以使用的最常見的兩種技術:1)刪除低方差(超過90%)的特徵;2)刪除有大量缺失值的特徵。

低方差:假設有兩個特徵,1)性別只包含一個性別值(例如,女性),2)年齡包含30到50歲之間的不同值。在這種情況下,性別特徵的方差很小,因為這個屬性中的值都是相同的,在模型訓練時,它不會幫助模型找到任何模式;因此我們可以直接刪除這個特徵。

這種方式得實現非常簡單,可以使用sklearn得VarianceThreshold函式。下面的程式碼將識別那些在至少90%的例項中相同的特性。

 from sklearn.feature_selection import VarianceThreshold
 variance = VarianceThreshold(threshold = (.9 * (1 - .9)))
 variance.fit(loans)
 variance.get_support()

可以看到在我們的案例中沒有低方差的特徵,所以不需要刪除。

缺失值:在這組特徵中沒有任何包含大量缺失值的特徵;因此,我們將跳過這一步。以前我們也發過處理缺失值的文章,如果你對這部分感興趣,可以搜尋檢視。

第二步:識別高度相關的特徵

第二步是識別特徵的多重共線性。我們使用雙變數分析來找出兩組變數之間是否有關係(相關)。

利用這些相關性,你可以得到以下的結論:

  • 一個或多個變數依賴於另一個變數,可能導致多重共線性;
  • 相關性可以幫助預測一個變數與另一個變數的關係,表明存在因果關係;
  • 在業務層面上可以瞭解標籤結果的因素,在我們的例子中瞭解每個特性如何影響貸款支付結果

當資料集的特徵之間具有高度的正相關或負相關時,ML模型可能會受到多重共線性的影響。高度相關的特徵可能提供相同的資訊。在這種情況下可能會導致扭曲或誤導的結果,為了解決這個問題,我們可以只保留一個特徵,刪除多餘的特徵,這樣是不丟失任何資訊的。

比如月薪和年薪;雖然它們可能不一樣,但它們可能有相同的模式。像邏輯迴歸和線性迴歸這樣的模型對這個問題很敏感,如果用這樣的冗餘特徵訓練模型,可能會產生誤導的結果。因此我們應該以消除其中一個為目標。

注意:決策樹和增強樹等演算法不受多重共線性的影響。

如何處理多重共線性?

有很多方法可以處理它。檢測高度相關特徵的最簡單方法是使用 Pearson 相關係數並刪除十分(~90%)相關特徵。主成分分析(PCA)也可以用作降維演算法。它通常用於降維,它將每個資料點僅投影到前幾個主成分上獲得低維資料的同時儘可能多地保留資料的變化。

這裡我們使用pandas_profiling來進行分析

 from pandas_profiling import ProfileReport 
 profile = ProfileReport (loans, title = 'Loans Defaults Prediction', html = {'style': {'full_width': True }}) 
 profile

你會發現Pearson和Phik之間不同型別的相關性。當資料中包含未處理的分類特性時,Phik是非常好用的。例如,下面的“grade”分類特徵,它在相關矩陣上繪製得很好:

如何理解相關矩陣:相關性範圍從+1到-1,其中:

  • 零相關表示變數之間沒有關係;
  • 相關性為-1表示完全負相關,這意味著當一個變數上升時,另一個變數下降;
  • 相關性為+1表示完全正相關,這意味著兩個變數一起朝同一個方向移動。

上圖可以觀察到以下高度相關的特徵:

  • 客戶資訊相關的特徵:bc_open_to_buy / num_op_rev_tl。這兩個特徵都與迴圈賬戶和銀行卡有關,因此它們高度相關。為了避免多協同問題,去掉初始模型中的bc_open_to_buy特性。revol_util / bc_util。也是一個類似的情況,可以刪除bc_util特性。
  • 貸款資訊特性:Int_rate和grade是基於借貸專有模型的sub_grade的衍生品;因此它們是高度相關的;我們把這些刪除。這裡的sub_grade和loan_amount也是相關的,但關聯度較低,可以保留它們。
 loans.drop(["bc_util", "bc_open_to_buy","int_rate", "grade"], axis = 1, inplace = True)

第三步:找出特徵與目標變數之間的相關性

我們希望能夠找到與目標變數(在本例中為loan_status)高度相關的特性。這裡將回顧上面介紹的兩種流行的方法:

基於過濾的方法

相關矩陣可以幫助我們識別高度相關的特徵。pandas_profiling生成分析報告可能需要時間,因此瞭解繪製相關矩陣的其他技術是必要的。下面是兩種可選方法:

使用pandas自帶的corr函式

 loans_cor=loan.corr() 
 loans_cor

使用seaborn熱點圖

 import seaborn as sns 
 import matplotlib.pyplot as plt 
 %matplotlib inline 
 plt.figure(figsize=(10,6)) 
 sns.heatmap(loans_cor, annot=True)

我們可以觀察到以下高度相關的特徵:sub_grade, term, loan_amnt, dti, emp_length, annual_inc與loan_status。這可以讓我們知道哪些特性是重要的。

包裝器方法

包裝器的方法是一種選擇特徵的更自動化的方式,我們將使用內建函式 SequentialFeatureSelector()實現前向選擇,該函式是 mlxtend 庫的一部分。此函式具有不同的特徵選擇技術。

SequentialFeatureSelector() 有 11 個引數,您可以調整這些引數以獲得最佳結果。我們這裡將調整以下引數:

  • Estimator——核心使用的演算法;在這個們的例子中將使用 LogisticRegression() 演算法;
  • k_features — 希望演算法選擇為最佳特徵的特徵數(預設為 1)。它應該小於資料集的所有特徵數總和。mlxtend 包還提供了“best”引數,其中選擇器返回最佳交叉驗證效能。因此,與其猜測需要返回多少特徵,不如應用“best”;
  • Forward 和 floating 引數來標識包裝器方法:例如,對於我們的前向選擇,它將是forward = True,而floating = False;
  • Scoring :指定了評估標準:使用 sklearn 評分指標“precision”。對於分類器,因為資料集是不平衡的。我們還可以使用 f1、precision、recall、roc_auc 等用於分類任務的指標和 r2 、mean_absolute_error、mean_squared_error/neg_mean_squared_error、median_absolute_error 用於迴歸任務的指標;
  • cv——交叉驗證,預設為5。

現在讓我們將上面定義的特徵選擇器應用到的資料集中。

對於給定的資料將嘗試一個非常常見的演算法-邏輯迴歸序列特徵選擇器。Loan_status將被用作預測的標籤以查詢預測的依賴項:

 from sklearn.model_selection import train_test_split, RandomizedSearchCV 
 from sklearn.linear_model import LogisticRegression 
 from sklearn import metrics 
 from sklearn.preprocessing import MinMaxScaler
 X = loans.drop('loan_status', axis=1) 
 y = loans[['loan_status']] 
 y = y.values.ravel() X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)
 scaler = MinMaxScaler() 
 X_train = scaler.fit_transform(X_train) 
 X_test = scaler.transform(X_test)

下一步是我們將使用SequentialFeatureSelector來尋找“最佳”特徵:

 from mlxtend.feature_selection import SequentialFeatureSelector as SFS
 
 sfs = SFS(LogisticRegression(),
           k_features='best', 
           forward=True, 
           floating=False, 
           scoring = 'precision', 
           cv = 0)

將上面的特徵選擇器應用到我們的資料:

 sfs.fit(X, y) 
 sfs.k_feature_names_

返回並檢視ML任務應該使用的最佳特性:

透過比較每個訓練步驟中的效能和特徵數量來了解選擇過程。還可以看到所選擇的模型度量在迭代步驟中不會發生很大的變化。

 from mlxtend.plotting import plot_sequential_feature_selection as plot_sfs 
 import matplotlib.pyplot as plt 
 fig1 = plot_sfs(sfs.get_metric_dict(), kind='std_dev') plt.title('Sequential Forward Selection') 
 plt.grid() 
 plt.show()

可以看到不同特徵的指標表現

總結

在本文中,我們介紹了特徵選擇技術的基本原理,這對理解重要特徵和結果變數之間的相關性是非常關鍵的。本篇文章的程式碼:https://avoid.overfit.cn/post/6f2a58732ffa42ba8dffa6db78c5ebc0

作者:Maria Gusarova

相關文章