特徵選擇詳解及與sklearn的結合應用

特徵選擇( Feature Selection )也稱特徵子集選擇( Feature Subset Selection , FSS ),或屬性選擇( Attribute Selection )。是指從已有的M個特徵(Feature)中選擇N個特徵使得系統的特定指標最優化,是從原始特徵中選擇出一些最有效特徵以降低數據集維度的過程,是提高學習算法性能的一個重要手段,也是模式識別中關鍵的數據預處理步驟。對於一個學習算法來說,好的學習樣本是訓練模型的關鍵。
此外,需要區分特徵選擇與特徵提取。特徵提取 ( Feature extraction )是指利用已有的特徵計算出一個抽象程度更高的特徵集,也指計算得到某個特徵的算法。
在這裏插入圖片描述

一、Filter(過濾法)

1、移除低方差的特徵 (Removing features with low variance)

       假設某特徵的特徵值只有0和1,並且在所有輸入樣本中,95%的實例的該特徵取值都是1,那就可以認爲這個特徵作用不大。如果100%都是1,那這個特徵就沒意義了。當特徵值都是離散型變量的時候這種方法才能用,如果是連續型變量,就需要將連續變量離散化之後才能用。可以把它作爲特徵選擇的預處理,先去掉那些取值變化小的特徵,然後再從接下來提到的的特徵選擇方法中選擇合適的進行進一步的特徵選擇。

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

2、單變量特徵選擇

       單變量特徵選擇的原理是分別單獨的計算每個變量的某個統計指標,根據該指標來判斷哪些指標重要,剔除那些不重要的指標。
對於分類問題(y離散),可採用:
 Chi2,f_classif, mutual_info_classif,Mutual_info_classif
對於迴歸問題(y連續),可採用:
 皮爾森相關係數,f_regression, mutual_info_regression,最大信息係數
(1)相關係數(Pearson Correlation)
  皮爾森相關係數是一種最簡單的,能幫助理解特徵和響應變量之間關係的方法,該方法衡量的是變量之間的線性相關性,結果的取值區間爲[-1,1],-1表示完全的負相關,+1表示完全的正相關,0表示沒有線性相關。
  Pearson Correlation速度快、易於計算,經常在拿到數據(經過清洗和特徵提取之後的)之後第一時間就執行。Scipy的 pearsonr 方法能夠同時計算 相關係數 和p-value.
計算方法:
第一種:

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

第二種:

import numpy as np
from scipy.stats import pearsonr
np.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
#  pearsonr(x, y)的輸入爲特徵矩陣和目標向量
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))

(2)假設檢驗(Hypothesis Test)
  Chi2:經典的卡方檢驗是檢驗定性自變量對定性因變量的相關性,對應於sklearn中的chi2
  F分佈的假設檢驗:對應於sklearn中的F_classif、F_regression
(3)互信息和最大信息係數 (Mutual information and maximal information coefficient (MIC))
  互信息爲隨機變量X與Y之間的互信息I(X;Y)爲單個事件之間互信息的數學期望,也是評價定性自變量對定性因變量的相關性,計算公式:
   I(X;Y)=E[I(xi;yj)]=xiXyjYp(xi,yj)logp(xi,yj)p(xi)p(yj)  I(X;Y) = E[I({x_i};{y_j})] = \sum\limits_{{x_i} \in X} {\sum\limits_{{y_j} \in Y} {p({x_i},{y_j})} } \log \frac{{p({x_i},{y_j})}}{{p({x_i})p({y_j})}} 
  互信息直接用於特徵選擇其實不是太方便:1、它不屬於度量方式,也沒有辦法歸一化,在不同數據及上的結果無法做比較;2、對於連續變量的計算不是很方便(X和Y都是集合,x,y都是離散的取值),通常變量需要先離散化,而互信息的結果對離散化的方式很敏感。
  最大信息係數克服了這兩個問題。它首先尋找一種最優的離散化方式,然後把互信息取值轉換成一種度量方式,取值區間在[0,1]。 minepy 提供了MIC功能。

from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由於MINE的設計不是函數式的,定義mic方法將其爲函數式的,返回一個二元組,二元組的第2項設置成固定的P0.5
def mic(x, y):
  m = MINE()
  m.compute_score(x, y)
  return (m.mic(), 0.5)
#選擇K個最好的特徵,返回特徵選擇後的數據
x_new=SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)

(4)距離相關(Distance Correlation)
       距離相關是爲了克服Pearson相關係數的弱點而生的。有時即便Pearson相關係數是0,我們也不能斷定這兩個變量是獨立的(有可能是非線性相關);但如果距離相關是0,那麼我們就可以說這兩個變量是獨立的。R語言中有方法dcor用於計算距離相關(點擊鏈接有維基百科的相關介紹)
注:上面沒有給出代碼的方法都可以通過調用sklearn來實現,只有sklearn不能直接實現的我纔給出了代碼

使用selectKBest方法進行單變量特徵選擇
score_func : callable
    Function taking two arrays X and y, and returning a pair of arrays
    (scores, pvalues) or a single array with scores.
    Default is f_classif (see below "See also"). The default function only
    works with classification tasks.

k : int or "all", optional, default=10
    Number of top features to select.
    The "all" option bypasses selection, for use in a parameter search.

F_classif(分類):分類任務的標籤/特徵之間的方差分析f值。

Mutual_info_classif(相互信息分類):離散目標的相互信息。

chi2(卡方檢驗):分類任務的非負特徵的chi平方統計。

F_regression(迴歸):迴歸任務的標籤/特徵之間的F值。

Mutual_info_regression(相互信息迴歸):連續目標的相互信息。

SelectPercentile(選擇百分位數):根據最高分數的百分位數選擇特徵。

selectFpr:根據假陽性率測試選擇特徵。

selectFdr:根據估計的誤報率選擇特徵。

selectFwe:根據家庭錯誤率選擇功能。

GenericUnivariateSelect(通用單變量選擇):具有可配置模式的單變量特徵選擇器。

Get_support():用於得到特徵篩選的布爾值結果
indices : boolean (default False)
    If True, the return value will be an array of integers, rather than a boolean mask.

       以上是sklearn對單變量特徵選擇的支持,首先我們先要導入想要用來進行特徵選擇的方法,例如from sklearn.feature_selection import chi2。然後使用SelectKBest(score_func,K)根據我們選擇的方法計算的得分,移除K名以外的所有特徵。最後,我們可以使用Get_support(X,Y)方法得到特徵篩選後的布爾值(整型)數組,依據用戶給出的特徵的排列順序,如果該特徵被移除,數組中相應位置返回false;我們也可以使用fit_transform(X,Y)方法直接得到特徵選擇後的整個新的同特徵向量數組x_new.當然,除了SelectKBest,也可以用SelectPercentile等方法。

二、Wrapper(封裝器):

       遞歸消除特徵法使用一個基模型來進行多輪訓練,每輪訓練後,移除若干權值係數的特徵,再基於新的特徵集進行下一輪訓練。
       對特徵含有權重的預測模型(例如,線性模型對應參數coefficients),RFE通過遞歸減少考察的特徵集規模來選擇特徵。首先,預測模型在原始特徵上訓練,每個特徵指定一個權重。之後,那些擁有最小絕對值權重的特徵被踢出特徵集。如此往復遞歸,直至剩餘的特徵數量達到所需的特徵數量。
Sklearn中有兩種方法:RFE和RFECV
(1)REF(estimator,n_features_to_select,step)
  給定一個爲特徵分配權重的外部估計量(例如線性模型的係數),遞歸特徵消除(rfe)的目標是通過遞歸地考慮更小的特徵集來選擇特徵。首先,對估計量進行初始特徵集的訓練,通過“coef”屬性或“feature”importances屬性獲得每個特徵的重要性,然後從當前特徵集中刪去最不重要的特徵。該過程在修剪集上遞歸地重複,直到最終達到所需的要選擇的特性數量。
  其中estimator是帶有特徵權重的分類器(所有的迴歸模型都有feature_importances),而n_features_to_select就是我們要保留的特徵,step是每次遞歸要出去的特徵的數目。

from sklearn.datasets import make_friedman1
from sklearn.feature_selection import RFE
from sklearn.svm import SVR
X, y = make_friedman1(n_samples=50, n_features=10, random_state=0)
estimator = SVR(kernel="linear")
selector = RFE(estimator, 5, step=1)
selector = selector.fit(X, y)
print(selector.support_ )# doctest: +NORMALIZE_WHITESPACE
輸出:array([ True,  True,  True,  True,  True,
        False, False, False, False, False], dtype=bool)
print(selector.ranking_)
輸出:array([1, 1, 1, 1, 1, 6, 4, 3, 2, 5])

(2)RFECV(estimator,step,cv)
  RFECV即通過交叉驗證的方式執行RFE,以此來選擇最佳數量的特徵。我們注意到這個函數中沒有n_features_to_select,所以他會遞歸所有的特徵子集,然後通過交叉驗證選擇最佳數量的特徵。

from sklearn.datasets import make_friedman1
from sklearn.feature_selection import RFECV
from sklearn.svm import SVR
X, y = make_friedman1(n_samples=50, n_features=10, random_state=0)
estimator = SVR(kernel="linear")
selector = RFECV(estimator, step=1, cv=5)
selector = selector.fit(X, y)
print(selector.support_) # doctest: +NORMALIZE_WHITESPACE
輸出:array([ True,  True,  True,  True,  True,
        False, False, False, False, False], dtype=bool)
print(selector.ranking_)
輸出:array([1, 1, 1, 1, 1, 6, 4, 3, 2, 5])

support_屬性可以得到特徵篩選結果的布爾值數組,ranking_屬性可以得到對應位置特徵得分的排序,被選中的特徵都會標誌爲1。

三、Embedded(嵌入法)

       單變量特徵選擇方法獨立的衡量每個特徵與響應變量之間的關係,另一種主流的特徵選擇方法是基於機器學習模型的方法。有些機器學習方法本身就具有對特徵進行打分的機制,或者很容易將其運用到特徵選擇任務中,例如迴歸模型,SVM,決策樹,隨機森林等等。其實Pearson相關係數等價於線性迴歸裏的標準化迴歸係數。
  SelectFromModel作爲meta-transformer,能夠用於擬合後任何擁coef_或feature_importances_屬性的預測模型。如果特徵對應的coef_或feature_importances_值低於設定的閾值threshold,那麼這些特徵將被移除。除了手動設置閾值,也可通過字符串參數調用內置的啓發式算法(heuristics)來設置閾值,包括:平均值(“mean”), 中位數(“median”)以及他們與浮點數的乘積,如“0.1*mean”。
1、 基於懲罰項的特徵選擇法
  最常用的是通過L1和L2正則化來選取特徵。L1是通過稀疏參數(減少參數的數量)來降低複雜度,使用L1範數作爲懲罰項的線性模型(Linear models)會得到稀疏解,大部分特徵對應的係數爲0,我們可以選擇係數不爲0的特徵用於分類器。L2是通過減小參數值的大小來降低複雜度,相比於L1,L2正則化會讓係數的取值變得平均,不像L1那樣係數會因爲細微的數據變化而波動,所以L2正則化對於特徵選擇來說是一種穩定的模型。。特別指出,常用於此目的的稀疏預測模型有 linear_model.Lasso(迴歸), linear_model.LogisticRegression 和 svm.LinearSVC(分類)。

from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
iris = load_iris()
X, y = iris.data, iris.target
Print(X.shape)
輸出:(150, 4)
lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
model = SelectFromModel(lsvc, prefit=True)
X_new = model.transform(X)
Print(X_new.shape)
輸出:(150, 3)

以上代碼中我們也可以調用get_support()方法來獲取特徵選擇的結果,也可以通過feature_importances_或者coef_來查看各特徵的比重。
  當然,上面的程序中我們也可以替換機器學習模型,更改殘參數中的懲罰項來選擇L1還是L2正則化。
2、 基於樹模型的特徵選擇
  基於樹的預測模型(見 sklearn.tree 模塊,森林見 sklearn.ensemble 模塊)能夠用來計算特徵的重要程度,因此能用來去除不相關的特徵。

from sklearn.ensemble import ExtraTreesClassifier
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
iris = load_iris()
X, y = iris.data, iris.target
Print(X.shape)
輸出:(150, 4)
clf = ExtraTreesClassifier()
clf = clf.fit(X, y)
clf.feature_importances_  
array([ 0.04...,  0.05...,  0.4...,  0.4...])
model = SelectFromModel(clf, prefit=True)
X_new = model.transform(X)
Print(X_new.shape)               
輸出:(150, 2)

       熟悉決策樹的同學都知道,決策樹的實現過程就是通過計算基尼指數或者信息熵來選擇最佳特徵進行分類的,我們便是利用這個過程進行特徵選擇。當然在決策樹或者隨機森林中,我們還可以設置樹的深度來控制得到的特徵數量,樹的深度不能太低也不能太高,太低會導致分類精度不夠,太高容易過擬合,具體的大家可以自己去網上查查,我這裏就不多講了。
3、隨機稀疏模型(Randomized sparse models)
  基於L1的稀疏模型的侷限在於,當面對一組互相關的特徵時,它們只會選擇其中一項特徵。爲了減輕該問題的影響可以使用隨機化技術,通過多次重新估計稀疏模型來擾亂設計矩陣,或通過多次下采樣數據來統計一個給定的迴歸量被選中的次數。
  穩定性選擇是一種基於二次抽樣和選擇算法相結合較新的方法,選擇算法可以是迴歸、SVM或其他類似的方法。它的主要思想是在不同的數據子集和特徵子集上運行特徵選擇算法,不斷的重複,最終彙總特徵選擇結果,比如可以統計某個特徵被認爲是重要特徵的頻率(被選爲重要特徵的次數除以它所在的子集被測試的次數)。理想情況下,重要特徵的得分會接近100%。稍微弱一點的特徵得分會是非0的數,而最無用的特徵得分將會接近於0。
sklearn在隨機lasso(RandomizedLasso)和隨機邏輯迴歸(RandomizedLogisticRegression)中有對穩定性選擇的實現。

from sklearn.linear_model import RandomizedLasso
from sklearn.datasets import load_boston
boston = load_boston()

#using the Boston housing data. 
#Data gets scaled automatically by sklearn's implementation
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
rlasso = RandomizedLasso(alpha=0.025)
rlasso.fit(X, Y)
print("Features sorted by their score:")
print(sorted(zip(map(lambda x: format(x, '.4f'), rlasso.scores_), names), reverse=True))
Features sorted by their score:
輸出:[('1.0000', 'RM'), ('1.0000', 'PTRATIO'), ('1.0000', 'LSTAT'), ('0.6450', 'CHAS'), ('0.6100', 'B'), ('0.3950', 'CRIM'), ('0.3800', 'TAX'), ('0.2250', 'DIS'), ('0.2000', 'NOX'), ('0.1150', 'INDUS'), ('0.0750', 'ZN'), ('0.0200', 'RAD'), ('0.0100', 'AGE')]

       在上邊這個例子當中,最高的3個特徵得分是1.0,這表示他們總會被選作有用的特徵(當然,得分會收到正則化參數alpha的影響,但是sklearn的隨機lasso能夠自動選擇最優的alpha)。接下來的幾個特徵得分就開始下降,但是下降的不是特別急劇,這跟純lasso的方法和隨機森林的結果不一樣。能夠看出穩定性選擇對於克服過擬合和對數據理解來說都是有幫助的:總的來說,好的特徵不會因爲有相似的特徵、關聯特徵而得分爲0,這跟Lasso是不同的。對於特徵選擇任務,在許多數據集和環境下,穩定性選擇往往是性能最好的方法之一。
四、 sklearn.pipeline.Pipeline
  我們可以使用Pipeline實現特徵選擇和模型訓練的串行計算,使得代碼看起來更加的簡潔,具體的用法可以去看看sklearn的官方API。

import sklearn.pipeline.Pipeline:
clf = Pipeline([
('feature_selection', SelectFromModel(LinearSVC(penalty="l1"))),
('classification', RandomForestClassifier())
])
clf.fit(X, y)

總結:以上的這些都是本人看了幾篇博客後做出的整理,其實一開始看的時候還是很迷糊的,就各種亂用,所以這裏要提一下:大家一定要清楚自己的特徵變量是離散的還是連續的,相對應的用到的學習模型是離散的分類模型還是迴歸模型,這個很重要,這之間的區別不用我多說,不能一上來就直接用各種方法嘗試一遍,就算有好的效果也是立不住腳的,而且說實話,也不會有好的效果。
參考博客:

1、https://www.cnblogs.com/stevenlk/p/6543646.html
2、https://www.cnblogs.com/bonelee/p/8632866.html
3、https://ynuwm.github.io/2017/12/09/sklearn-特徵提取/
4、https://www.cnblogs.com/stevenlk/p/6543628.html
5、https://baike.baidu.com/item/特徵選擇/4950639?fr=aladdin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章