特徵選擇 (feature_selection)

轉載:https://www.cnblogs.com/stevenlk/p/6543628.html

特徵選擇 (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_classifmutual_info_classif互信息
  對於迴歸問題(y連續),可採用:
    皮爾森相關係數f_regressionmutual_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)檢驗

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

>>> 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)爲單個事件之間互信息的數學期望)也是評價定性自變量對定性因變量的相關性的,互信息計算公式如下:

 

I(X;Y)=E[I(xi;yj)]=∑xiϵX∑yjϵYp(xi,yj)logp(xi,yj)p(xi)p(yj)I(X;Y)=E[I(xi;yj)]=∑xiϵX∑yjϵYp(xi,yj)logp(xi,yj)p(xi)p(yj)

  互信息直接用於特徵選擇其實不是太方便:1、它不屬於度量方式,也沒有辦法歸一化,在不同數據及上的結果無法做比較;2、對於連續變量的計算不是很方便(X和Y都是集合,x,y都是離散的取值),通常變量需要先離散化,而互信息的結果對離散化的方式很敏感。

  最大信息係數克服了這兩個問題。它首先尋找一種最優的離散化方式,然後把互信息取值轉換成一種度量方式,取值區間在[0,1]。 minepy 提供了MIC功能。

反過頭來看y=x2y=x2這個例子,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相關係數的弱點而生的。在xx和x2x2這個例子中,即便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 從文件系統中加載數據至內存
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章