特征選擇 (feature_selection)


特征選擇 (feature_selection)

本文主要參考sklearn(0.18版為主,部分0.17)的1.13節的官方文檔,以及一些工程實踐整理而成。

  當數據預處理完成后,我們需要選擇有意義的特征輸入機器學習的算法和模型進行訓練。通常來說,從兩個方面考慮來選擇特征:

  • 特征是否發散:如果一個特征不發散,例如方差接近於0,也就是說樣本在這個特征上基本上沒有差異,這個特征對於樣本的區分並沒有什么用。
  • 特征與目標的相關性:這點比較顯見,與目標相關性高的特征,應當優選選擇。除移除低方差法外,本文介紹的其他方法均從相關性考慮。

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

  • Filter:過濾法,按照發散性或者相關性對各個特征進行評分,設定閾值或者待選擇閾值的個數,選擇特征。
  • Wrapper:包裝法,根據目標函數(通常是預測效果評分),每次選擇若干特征,或者排除若干特征。
  • Embedded:嵌入法,先使用某些機器學習的算法和模型進行訓練,得到各個特征的權值系數,根據系數從大到小選擇特征。類似於Filter方法,但是是通過訓練來確定特征的優劣。

特征選擇主要有兩個目的:

  • 減少特征數量、降維,使模型泛化能力更強,減少過擬合;
  • 增強對特征和特征值之間的理解。

  拿到數據集,一個特征選擇方法,往往很難同時完成這兩個目的。通常情況下,選擇一種自己最熟悉或者最方便的特征選擇方法(往往目的是降維,而忽略了對特征和數據理解的目的)。本文將結合 Scikit-learn提供的例子 介紹幾種常用的特征選擇方法,它們各自的優缺點和問題。

Filter

1. 移除低方差的特征 (Removing features with low variance)

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

>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])

果然, VarianceThreshold 移除了第一列特征,第一列中特征值為0的概率達到了5/6.

2. 單變量特征選擇 (Univariate feature selection)

  單變量特征選擇的原理是分別單獨的計算每個變量的某個統計指標,根據該指標來判斷哪些指標重要,剔除那些不重要的指標。

  對於分類問題(y離散),可采用:
    _卡方檢驗_,f_classif, mutual_info_classif互信息
  對於回歸問題(y連續),可采用:
    _皮爾森相關系數_,f_regression, mutual_info_regression最大信息系數

  這種方法比較簡單,易於運行,易於理解,通常對於理解數據有較好的效果(但對特征優化、提高泛化能力來說不一定有效)。這種方法有許多改進的版本、變種。

  單變量特征選擇基於單變量的統計測試來選擇最佳特征。它可以看作預測模型的一項預處理。Scikit-learn將特征選擇程序用包含 transform 函數的對象來展現

  • SelectKBest 移除得分前 k 名以外的所有特征(取top k)
  • SelectPercentile 移除得分在用戶指定百分比以后的特征(取top k%)
  • 對每個特征使用通用的單變量統計檢驗: 假正率(false positive rate) SelectFpr, 偽發現率(false discovery rate) SelectFdr, 或族系誤差率 SelectFwe.
  • GenericUnivariateSelect 可以設置不同的策略來進行單變量特征選擇。同時不同的選擇策略也能夠使用超參數尋優,從而讓我們找到最佳的單變量特征選擇策略。

  將特征輸入到評分函數,返回一個單變量的f_score(F檢驗的值)或p-values(P值,假設檢驗中的一個標准,P-value用來和顯著性水平作比較),注意SelectKBest 和 SelectPercentile只有得分,沒有p-value。

  • For classification: chi2, f_classif, mutual_info_classif
  • For regression: f_regression, mutual_info_regression

Notice:
  The methods based on F-test estimate the degree of linear dependency between two random variables. (F檢驗用於評估兩個隨機變量的線性相關性)On the other hand, mutual information methods can capture any kind of statistical dependency, but being nonparametric, they require more samples for accurate estimation.(另一方面,互信息的方法可以捕獲任何類型的統計依賴關系,但是作為一個非參數方法,估計准確需要更多的樣本)

Feature selection with sparse data:
  If you use sparse data (i.e. data represented as sparse matrices), chi2, mutual_info_regression, mutual_info_classif will deal with the data without making it dense.(如果你使用稀疏數據(比如,使用稀疏矩陣表示的數據), 卡方檢驗(chi2)、互信息回歸(mutual_info_regression)、互信息分類(mutual_info_classif)在處理數據時可保持其稀疏性.)

Examples:
Univariate Feature Selection
Comparison of F-test and mutual information

2.1 卡方(Chi2)檢驗

  經典的卡方檢驗是檢驗定性自變量對定性因變量的相關性。比如,我們可以對樣本進行一次\(chi^2\) 測試來選擇最佳的兩項特征:

>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)

2.2 Pearson相關系數 (Pearson Correlation)

  皮爾森相關系數是一種最簡單的,能幫助理解特征和響應變量之間關系的方法,該方法衡量的是變量之間的線性相關性,結果的取值區間為[-1,1],-1表示完全的負相關,+1表示完全的正相關,0表示沒有線性相關。

  Pearson Correlation速度快、易於計算,經常在拿到數據(經過清洗和特征提取之后的)之后第一時間就執行。Scipy的 pearsonr 方法能夠同時計算 相關系數 和p-value.

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)))
>>>
# 輸出為二元組(sorce, p-value)的數組
Lower noise (0.71824836862138386, 7.3240173129992273e-49)
Higher noise (0.057964292079338148, 0.31700993885324746)

這個例子中,我們比較了變量在加入噪音之前和之后的差異。當噪音比較小的時候,相關性很強,p-value很低。

  Scikit-learn提供的 f_regrssion 方法能夠批量計算特征的f_score和p-value,非常方便,參考sklearn的 pipeline

  Pearson相關系數的一個明顯缺陷是,作為特征排序機制,他只對線性關系敏感。如果關系是非線性的,即便兩個變量具有一一對應的關系,Pearson相關性也可能會接近0。例如:

x = np.random.uniform(-1, 1, 100000)
print pearsonr(x, x**2)[0]
-0.00230804707612

  更多類似的例子參考 sample plots 。另外,如果僅僅根據相關系數這個值來判斷的話,有時候會具有很強的誤導性,如 Anscombe’s quartet ,最好把數據可視化出來,以免得出錯誤的結論。

2.3 互信息和最大信息系數 (Mutual information and maximal information coefficient (MIC)

  經典的互信息(互信息為隨機變量X與Y之間的互信息\(I(X;Y)\)為單個事件之間互信息的數學期望)也是評價定性自變量對定性因變量的相關性的,互信息計算公式如下:

\[I(X;Y)=E[I(x_i;y_j)]=\sum_{ x_i\epsilon X }\sum_{ y_j\epsilon 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功能。

反過頭來看\(y=x^2\)這個例子,MIC算出來的互信息值為1(最大的取值)。

from minepy import MINE
m = MINE()
x = np.random.uniform(-1, 1, 10000)
m.compute_score(x, x**2)
print(m.mic())
>>>1.0

  MIC的統計能力遭到了 一些質疑 ,當零假設不成立時,MIC的統計就會受到影響。在有的數據集上不存在這個問題,但有的數據集上就存在這個問題。

2.4 距離相關系數 (Distance Correlation)

  距離相關系數是為了克服Pearson相關系數的弱點而生的。在\(x\)\(x^2\)這個例子中,即便Pearson相關系數是0,我們也不能斷定這兩個變量是獨立的(有可能是非線性相關);但如果距離相關系數是0,那么我們就可以說這兩個變量是獨立的。

  R的 energy 包里提供了距離相關系數的實現,另外這是 Python gist 的實現。

> x = runif (1000, -1, 1)
> dcor(x, x**2)
[1] 0.4943864

  盡管有 MIC 和 距離相關系數 在了,但當變量之間的關系接近線性相關的時候,Pearson相關系數仍然是不可替代的。
  第一,Pearson相關系數計算速度快,這在處理大規模數據的時候很重要。
  第二,Pearson相關系數的取值區間是[-1,1],而MIC和距離相關系數都是[0,1]。這個特點使得Pearson相關系數能夠表征更豐富的關系,符號表示關系的正負,絕對值能夠表示強度。當然,Pearson相關性有效的前提是兩個變量的變化關系是單調的。

2.5 基於模型的特征排序 (Model based ranking)

  這種方法的思路是直接使用你要用的機器學習算法,針對 每個單獨的特征 和 響應變量建立預測模型。假如 特征 和 響應變量 之間的關系是非線性的,可以用基於樹的方法(決策樹、隨機森林)、或者 擴展的線性模型 等。基於樹的方法比較易於使用,因為他們對非線性關系的建模比較好,並且不需要太多的調試。但要注意過擬合問題,因此樹的深度最好不要太大,再就是運用交叉驗證

  在 波士頓房價數據集 上使用sklearn的 隨機森林回歸 給出一個_單變量選擇_的例子(這里使用了交叉驗證):

from sklearn.cross_validation import cross_val_score, ShuffleSplit
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
import numpy as np

# Load boston housing dataset as an example
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]

rf = RandomForestRegressor(n_estimators=20, max_depth=4)
scores = []
# 單獨采用每個特征進行建模,並進行交叉驗證
for i in range(X.shape[1]):
    score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2",  # 注意X[:, i]和X[:, i:i+1]的區別
                            cv=ShuffleSplit(len(X), 3, .3))
    scores.append((format(np.mean(score), '.3f'), names[i]))
print(sorted(scores, reverse=True))

[('0.620', 'LSTAT'), ('0.591', 'RM'), ('0.467', 'NOX'), ('0.342', 'INDUS'), ('0.305', 'TAX'), ('0.240', 'PTRATIO'), ('0.206', 'CRIM'), ('0.187', 'RAD'), ('0.184', 'ZN'), ('0.135', 'B'), ('0.082', 'DIS'), ('0.020', 'CHAS'), ('0.002', 'AGE')]

Wrapper

3. 遞歸特征消除 (Recursive Feature Elimination)

  遞歸消除特征法使用一個基模型來進行多輪訓練,每輪訓練后,移除若干權值系數的特征,再基於新的特征集進行下一輪訓練

  sklearn官方解釋:對特征含有權重的預測模型(例如,線性模型對應參數coefficients),RFE通過遞歸減少考察的特征集規模來選擇特征。首先,預測模型在原始特征上訓練,每個特征指定一個權重。之后,那些擁有最小絕對值權重的特征被踢出特征集。如此往復遞歸,直至剩余的特征數量達到所需的特征數量。

  RFECV 通過交叉驗證的方式執行RFE,以此來選擇最佳數量的特征:對於一個數量為d的feature的集合,他的所有的子集的個數是2的d次方減1(包含空集)。指定一個外部的學習算法,比如SVM之類的。通過該算法計算所有子集的validation error。選擇error最小的那個子集作為所挑選的特征。

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)

示例:
Recursive feature elimination: 一個遞歸特征消除的示例,展示了在數字分類任務中,像素之間的相關性。
Recursive feature elimination with cross-validation: 一個遞歸特征消除示例,通過交叉驗證的方式自動調整所選特征的數量。

Embedded

4. 使用SelectFromModel選擇特征 (Feature selection using SelectFromModel)

  單變量特征選擇方法獨立的衡量每個特征與響應變量之間的關系,另一種主流的特征選擇方法是基於機器學習模型的方法。有些機器學習方法本身就具有對特征進行打分的機制,或者很容易將其運用到特征選擇任務中,例如回歸模型,SVM,決策樹,隨機森林等等。其實Pearson相關系數等價於線性回歸里的標准化回歸系數。

  SelectFromModel 作為meta-transformer,能夠用於擬合后任何擁有coef_feature_importances_ 屬性的預測模型。 如果特征對應的coef_feature_importances_ 值低於設定的閾值threshold,那么這些特征將被移除。除了手動設置閾值,也可通過字符串參數調用內置的啟發式算法(heuristics)來設置閾值,包括:平均值(“mean”), 中位數(“median”)以及他們與浮點數的乘積,如”0.1*mean”。

Examples
Feature selection using SelectFromModel and LassoCV: 在閾值未知的前提下,選擇了Boston dataset中兩項最重要的特征。

4.1 基於L1的特征選擇 (L1-based feature selection)

  使用L1范數作為懲罰項的線性模型(Linear models)會得到稀疏解:大部分特征對應的系數為0。當你希望減少特征的維度以用於其它分類器時,可以通過 feature_selection.SelectFromModel 來選擇不為0的系數。特別指出,常用於此目的的稀疏預測模型有 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
>>> 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)
>>> X_new.shape
(150, 3)

  使用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)

  _對於SVM和邏輯回歸,參數C控制稀疏性:C越小,被選中的特征越少。對於Lasso,參數alpha越大,被選中的特征越少。_

示例:
Classification of text documents using sparse features: 不同算法使用基於L1的特征選擇進行文檔分類的對比。

Note:

L1恢復和壓縮感知 (L1-recovery and compressive sensing)
  對於一個好的alpha值,在滿足特定條件下, Lasso 僅使用少量觀測值就能夠完全恢復出非零的系數。特別地,樣本的數量需要“足夠大”,否則L1模型的表現會充滿隨機性,所謂“足夠大”取決於非零系數的數量,特征數量的對數,噪聲的數量,非零系數的最小絕對值以及設計矩陣X的結構。此外,設計矩陣必須擁有特定的屬性,比如不能太過相關(correlated)。 對於非零系數的恢復,還沒有一個選擇alpha值的通用規則 。alpha值可以通過交叉驗證來設置(LassoCV or LassoLarsCV),盡管這也許會導致模型欠懲罰(under-penalized):引入少量非相關變量不會影響分數預測。相反BIC (LassoLarsIC) 更傾向於設置較大的alpha值。
Reference Richard G. Baraniuk “Compressive Sensing”, IEEE Signal Processing Magazine [120] July 2007

4.2 隨機稀疏模型 (Randomized sparse models)

  基於L1的稀疏模型的局限在於,當面對一組互相關的特征時,它們只會選擇其中一項特征。為了減輕該問題的影響可以使用隨機化技術,通過_多次重新估計稀疏模型來擾亂設計矩陣_,或通過_多次下采樣數據來統計一個給定的回歸量被選中的次數_。——穩定性選擇 (Stability Selection)

  RandomizedLasso 實現了使用這項策略的Lasso,RandomizedLogisticRegression 使用邏輯回歸,適用於分類任務。要得到整個迭代過程的穩定分數,你可以使用 lasso_stability_path

  注意到對於非零特征的檢測,要使隨機稀疏模型比標准F統計量更有效, 那么模型的參考標准需要是稀疏的,換句話說,非零特征應當只占一小部分。

示例:
Sparse recovery: feature selection for sparse linear models: 比較了不同的特征選擇方法,並討論了它們各自適用的場合。

參考文獻:
N. Meinshausen, P. Buhlmann, “Stability selection”, Journal of the Royal Statistical Society, 72 (2010)
F. Bach, “Model-Consistent Sparse Estimation through the Bootstrap”

4.3 基於樹的特征選擇 (Tree-based feature selection)

  基於樹的預測模型(見 sklearn.tree 模塊,森林見 sklearn.ensemble 模塊)能夠用來計算特征的重要程度,因此能用來去除不相關的特征(結合 sklearn.feature_selection.SelectFromModel):

>>> 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
>>> 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)
>>> X_new.shape               
(150, 2)

示例:
Feature importances with forests of trees: 從模擬數據中恢復有意義的特征。
Pixel importances with a parallel forest of trees: 用於人臉識別數據的示例。

5. 將特征選擇過程融入pipeline (Feature selection as part of a pipeline)

  特征選擇常常被當作學習之前的一項預處理。在scikit-learn中推薦使用
sklearn.pipeline.Pipeline:

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

  在此代碼片段中,將 sklearn.svm.LinearSVC 和 sklearn.feature_selection.SelectFromModel 結合來評估特征的重要性,並選擇最相關的特征。之后 sklearn.ensemble.RandomForestClassifier 模型使用轉換后的輸出訓練,即只使用被選出的相關特征。你可以選擇其它特征選擇方法,或是其它提供特征重要性評估的分類器。更多詳情見 sklearn.pipeline.Pipeline 相關示例。
  
關於更多,參見另一個文檔:
《基於模型的特征選擇詳解 (Embedded & Wrapper)》


小結:

所屬方式 說明
VarianceThreshold Filter 方差選擇法(移除低方差的特征)
SelectKBest Filter 可選關聯系數、卡方校驗、最大信息系數作為得分計算的方法
RFE Wrapper 遞歸地訓練基模型,將權值系數較小的特征從特征集合中消除
SelectFromModel Embedded 訓練基模型,選擇權值系數較高的特征

參考:
[1] 1.13. Feature selection
[2] 1.13 特征選擇
[3] 干貨:結合Scikit-learn介紹幾種常用的特征選擇方法
[4] 使用sklearn做單機特征工程
[5] 使用sklearn優雅地進行數據挖掘
[6] 誰動了我的特征?——sklearn特征轉換行為全記錄

注:
  文檔[4]實際上是用sklearn實現整個數據挖掘流程,特別是在提高效率上sklearn的並行處理,流水線處理,自動化調參,持久化是使用sklearn優雅地進行數據挖掘的核心。這里是一個簡單的總結,具體可查看該文檔:

類或方法 說明
sklearn.pipeline Pipeline 流水線處理
sklearn.pipeline FeatureUnion 並行處理
sklearn.grid_search GridSearchCV 網格搜索自動化調參
externals.joblib dump 數據持久化
externals.joblib load 從文件系統中加載數據至內存


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM