機器學習中特徵選擇的方法綜述

本文摘自知乎用戶文章的第三章節,源出處地址:

作者:城東
鏈接:https://www.zhihu.com/question/28641663/answer/110165221
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


當數據預處理完成後,我們需要從所有特徵中選擇有意義的特徵,並將其輸入機器學習算法和模型進行訓練。

通常來說,從以下兩個方面考慮來選擇特徵:

(1)特徵是否發散:如果一個特徵不發散(方差接近於0),也就是說樣本在這個特徵上基本上沒有差異,對於樣本的區分作用不大,此類特徵可以過濾掉;
(2)特徵與目標的相關性:這點比較顯見,與目標相關性高的特徵,應當優選選擇。


根據特徵選擇的形式又可以將特徵選擇方法分爲3種:

(1)Filter(過濾法):按照發散性或者相關性對各個特徵進行評分,設定閾值或者待選擇閾值的個數,選擇特徵。
(2)Wrapper(包裝法):根據目標函數(通常是預測效果評分,或cost function),每次選擇(或排除)若干特徵。

(3)Embedded(嵌入法):先使用某些機器學習的算法和模型訓練,得到各個特徵的權值係數,根據係數從大到小選擇特徵。類似於Filter方法,只是通過訓練來確定特徵的優劣。

我們通常使用sklearn中的feature_selection庫來進行特徵選擇。

(一)Filter 過濾法

1.1,方差選擇法

  使用方差選擇法,先要計算各個特徵的方差,然後根據閾值,選擇方差大於閾值的特徵。工程上使用feature_selection庫的VarianceThreshold類來選擇特徵的代碼如下:

from sklearn.feature_selection import VarianceThreshold

#方差選擇法,返回值爲特徵選擇後的數據
#參數threshold爲方差的閾值
VarianceThreshold(threshold=3).fit_transform(iris.data)

1.2,相關係數法

  使用相關係數法,先要計算各個特徵對目標值的相關係數(Pearson相關係數)以及相關係數的P值。用feature_selection庫的SelectKBest類結合相關係數來選擇特徵的代碼如下:

from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr

#選擇K個最好的特徵,返回選擇特徵後的數據
#第一個參數爲計算評估特徵是否好的函數,該函數輸入特徵矩陣和目標向量,輸出二元組(評分,P值)的數組,數組第i項爲第i個特徵的評分和P值。
#在此定義爲計算相關係數
#參數k爲選擇的特徵個數
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)

1.3,卡方檢驗

  經典的卡方檢驗是檢驗定性自變量對定性因變量的相關性。假設自變量有N種取值,因變量有M種取值,考慮自變量等於i且因變量等於j的樣本頻數的觀察值與期望的差距,構建X2統計量:
  這個統計量的含義是自變量對因變量的相關性,feature_selection庫的SelectKBest類結合卡方檢驗選擇特徵的代碼如下:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

#選擇K個最好的特徵,返回選擇特徵後的數據
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)

1.4,互信息法

  經典的互信息也是評價定性自變量對定性因變量的相關性的,互信息計算公式如下:
  爲了處理定量數據,最大信息係數法被提出,使用feature_selection庫的SelectKBest類結合最大信息係數法來選擇特徵的代碼如下:
from sklearn.feature_selection import SelectKBest
from minepy import MINE
 
 #由於MINE的設計不是函數式的,定義mic方法將其爲函數式;
 #返回一個二元組,二元組的第2項設置成固定的P值0.5
 def mic(x, y):
     m = MINE()
     m.compute_score(x, y)
     return (m.mic(), 0.5)

#選擇K個最好的特徵,返回特徵選擇後的數據
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)

(二)Wrapper 包裝法

Wrapper最代表性的方法就是遞歸消除特徵法,過程:使用一個基模型來進行多輪訓練,每輪訓練後,消除若干權值係數的特徵,再基於新的特徵集進行下一輪訓練。使用feature_selection庫的RFE類來選擇特徵的代碼如下:

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

#遞歸特徵消除法,返回特徵選擇後的數據
#參數estimator爲基模型
#參數n_features_to_select爲選擇的特徵個數
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)

(三)Embedded 嵌入法

3.1,基於懲罰項的特徵選擇法

使用帶懲罰項的基模型,除了篩選出特徵外,同時也進行了降維。使用feature_selection庫的SelectFromModel類結合帶L1懲罰項的邏輯迴歸模型,來選擇特徵的代碼如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression

#帶L1懲罰項的邏輯迴歸作爲基模型的特徵選擇
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)

實際上,L1懲罰項降維的原理在於保留多個對目標值具有同等相關性的特徵中的一個,所以沒選到的特徵不代表不重要。故,可結合L2懲罰項來優化。具體操作爲:若一個特徵在L1中的權值爲1,選擇在L2中權值差別不大且在L1中權值爲0的特徵構成同類集合,將這一集合中的特徵平分L1中的權值,故需要構建一個新的邏輯迴歸模型:

from sklearn.linear_model import LogisticRegression

class LR(LogisticRegression):
    def __init__(self, threshold=0.01, dual=False, tol=1e-4, C=1.0,
                 fit_intercept=True, intercept_scaling=1, class_weight=None,
                 random_state=None, solver='liblinear', max_iter=100,
                 multi_class='ovr', verbose=0, warm_start=False, n_jobs=1):

        #權值相近的閾值
        self.threshold = threshold
        LogisticRegression.__init__(self, penalty='l1', dual=dual, tol=tol, C=C,
                 fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight=class_weight,
                 random_state=random_state, solver=solver, max_iter=max_iter,
                 multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
        #使用同樣的參數創建L2邏輯迴歸
        self.l2 = LogisticRegression(penalty='l2', dual=dual, tol=tol, C=C, fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight = class_weight, random_state=random_state, solver=solver, max_iter=max_iter, multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)

    def fit(self, X, y, sample_weight=None):
        #訓練L1邏輯迴歸
        super(LR, self).fit(X, y, sample_weight=sample_weight)
        self.coef_old_ = self.coef_.copy()
        #訓練L2邏輯迴歸
        self.l2.fit(X, y, sample_weight=sample_weight)

        cntOfRow, cntOfCol = self.coef_.shape
        #權值係數矩陣的行數對應目標值的種類數目
        for i in range(cntOfRow):
            for j in range(cntOfCol):
                coef = self.coef_[i][j]
                #L1邏輯迴歸的權值係數不爲0
                if coef != 0:
                    idx = [j]
                    #對應在L2邏輯迴歸中的權值係數
                    coef1 = self.l2.coef_[i][j]
                    for k in range(cntOfCol):
                        coef2 = self.l2.coef_[i][k]
                        #在L2邏輯迴歸中,權值係數之差小於設定的閾值,且在L1中對應的權值爲0
                        if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:
                            idx.append(k)
                    #計算這一類特徵的權值係數均值
                    mean = coef / len(idx)
                    self.coef_[i][idx] = mean
        return self

使用feature_selection庫的SelectFromModel類結合帶L1以及L2懲罰項的邏輯迴歸模型,來選擇特徵的代碼如下:

from sklearn.feature_selection import SelectFromModel
 
#帶L1和L2懲罰項的邏輯迴歸作爲基模型的特徵選擇
#參數threshold爲權值係數之差的閾值
SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(iris.data, iris.target)

3.2,基於樹模型的特徵選擇法

樹模型中GBDT也可用來作爲基模型進行特徵選擇,使用feature_selection庫的SelectFromModel類結合GBDT模型,來選擇特徵的代碼如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier

#GBDT作爲基模型的特徵選擇
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)

發佈了38 篇原創文章 · 獲贊 61 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章