天天看點

(資料科學學習手劄25)sklearn中的特征選擇相關功能

一、簡介

  在現實的機器學習任務中,自變量往往數量衆多,且類型可能由連續型(continuou)和離散型(discrete)混雜組成,是以出于節約計算成本、精簡模型、增強模型的泛化性能等角度考慮,我們常常需要對原始變量進行一系列的預處理及篩選,剔除掉冗雜無用的成分,得到較為滿意的訓練集,才會繼續我們的學習任務,這就是我們常說的特征選取(feature selection)。本篇就将對常見的特征選擇方法的思想及Python的實作進行介紹;

二、方法綜述

2.1 去除方差較小的變量

  這種方法針對離散型變量進行處理,例如,有變量X,其每個取值來自伯努利分布,即每一個樣本的觀測值為1或0,這種情況下,如果絕大多數觀測值都是1或0,那麼我們認為這種變量對我們模型的訓練,并不起什麼顯著地作用,這時就可以将這種變量剔除,下面我們來介紹sklearn中進行此項操作的方法:

  我們使用sklearn.feature中的VarianceThreshold()來對特征進行選擇,它主要的參數為threshold,傳入參數格式為 最小容忍比例*(1-最小容忍比例),這裡的容忍比例就是我們所說的當離散樣本中最多的那一類數量占全體數量的上限,比如設定為 0.8*(1-0.8),就是說對所有變量中最大比例樣本對應的比例大于等于80%的變量予以剔除,下面進行簡單的示範說明:

from sklearn.feature_selection import VarianceThreshold
import numpy as np

'''生成方差接近0的示範變量'''
X = np.array(np.random.binomial(1,0.1,30)).reshape((10,3))

'''生成方差明顯遠離0的示範變量'''
Y = np.array(np.random.binomial(1,0.5,10))

'''按列拼接矩陣'''
data = np.column_stack([X,Y])

'''初始化我們的低方差特征選擇模型'''
sel = VarianceThreshold(threshold=0.8*(1-0.8))

'''原始資料集'''
print('未經特征選擇:')
print(data)

'''利用設定好的模型對示範資料進行特征選擇并顯示結果'''
print('經過特征選擇:')
print(sel.fit_transform(data))      

 運作結果:

(資料科學學習手劄25)sklearn中的特征選擇相關功能

2.2 單變量的特征選擇

  單變量的特征選擇是指通過單變量的統計檢驗,為每一個待篩選變量進行檢驗并對其檢驗結果進行評分,最後根據自定的規則選擇留下哪些變量,有以下幾種自定規則方法:

  1.SelectKBest(score_func,k):其中score_func傳入用于計算評分的函數,預設是f_classif,它計算的是單變量與訓練target間的方差分析F值(Anova F-value);

k傳入使用者想要根據評分從高到低留下的變量的個數,預設是10;

  2.SelectPercentile(score_func,percentile):其中score_func同上;percentile傳入使用者想要根據得分從高到低留下的變量個數占總個數的比例,預設10,表示10%;

  3.SelectFpr(score_func,alpha):通過控制FPR檢驗中取僞錯誤發生的機率來選擇特征,其中score_func同上;alpha用來控制置信水準,即p值小于該值時拒絕原假設,即對應的變量被保留(原假設是該特征對分類結果無顯著貢獻);

  4.GenericUnivariateSelect(score_func,mode,param):這是一個整合上述幾種方法的廣義方法,其中score_func同上;mode用來指定特征選擇的方法,可選項有{‘percentile’, ‘k_best’, ‘fpr’, ‘fdr’, ‘fwe’},與上面幾種方法相對應;param的輸入取決于mode中指定的方式,即指定方式對應的傳入參數;

  下面我們以鸢尾花資料為例對SelectKBest進行示範,設定k=3,統計檢驗的方法設定為卡方獨立性檢驗:

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
print('篩選之前:')
'''特征篩選之前的自變量資料集形狀'''
print(X.shape)

'''進行SelectKBest,這裡設定檢驗函數為chi2,即卡方獨立性檢驗,設定保留的變量個數為3'''
X_new = SelectKBest(chi2, k=3).fit_transform(X, y)
print('篩選之後:')
print(X_new.shape)      

運作結果:

(資料科學學習手劄25)sklearn中的特征選擇相關功能

 2.3 遞歸特征消除法

  遞歸特征消除法(Recursive feature elimination)的基本思想是反複地建構多個模型(如回歸模型、支援向量機等),例如,在回歸任務中,對n個變量,第一輪構造n個模型,每個模型都對應着剔除掉一個變量,選擇出其中效果最佳的模型對應的變量,将其剔除,再進入第二輪,這樣通過遞歸構模組化型,最終将剩餘的變量控制在最佳的水準,這類似交叉驗證(cross validation)的過程,我們使用sklearn.feature_selection中的RFECV()來實施這個過程,其具體參數如下:

estimator:該參數傳入用于遞歸構模組化型的有監督型基學習器,要求該基學習器具有fit方法,且其輸出含有coef_或feature_importances_這種結果;

step:數值型,預設為1,控制每次疊代過程中删去的特征個數,有以下兩種情況:

  1.若傳入大于等于1的整數,則在每次疊代構模組化型的過程中删去對應數量的特征;

  2.若傳入介于0.0到1.0之間的浮點數,則在每次第疊代構造模型的過程中删去對應比例的特征。

cv:控制交叉驗證的分割政策,預設是3折交叉驗證,有以下幾種情況:

  1.None,等價于不傳入參數,即使用預設設定的3折交叉驗證;

  2.正整數,這時即指定了交叉驗證中分裂的子集個數,即k折中的k;

n_jobs:控制并行運算中利用到的CPU核心數,預設為1,即單核工作,若設定為-1,則啟用所有核心進行運算;

 函數的傳回值:

n_features_:通過交叉驗證過程最終剩下的特征個數;

support_:被選擇的特征的被選擇情況(True表示被選擇,False表示被淘汰)

ranking_:所有特征的評分排名

estimator_:利用剩下的特征訓練出的模型

下面以威斯康辛州乳腺癌資料作為示範資料,決策樹分類為基學習器,具體過程如下:

from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn.feature_selection import RFECV
from sklearn.metrics import confusion_matrix as cm
from sklearn.model_selection import train_test_split


'''載入紅酒三分類資料'''
X,y = datasets.load_wine(return_X_y=True)

'''分格訓練集與測試集'''
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)

'''定義基學習器'''
estimator =DecisionTreeClassifier()

'''利用基學習器直接來訓練(不删除變量)'''
pre_ = estimator.fit(X_train,y_train).predict(X_test)

'''列印混淆矩陣'''
print('遞歸特征删減前:')
print(cm(y_test,pre_))

'''進行遞歸特征消除,這裡設定每一輪疊代中每次删去一個變量,并進行5折交叉驗證來用于評估性能'''
selector = RFECV(estimator,step=1,cv=5)

'''儲存最後訓練出的最優學習器'''
selector = selector.fit(X,y)

'''列印特征的剔除情況'''
print(selector.support_)

'''利用得到的最優學習器來對驗證集進行預測'''
pre = selector.estimator_.predict(X_test[:,selector.support_])


'''列印混淆矩陣'''
print('遞歸特征删減後:')
print(cm(y_test,pre))      

運作結果如下:

(資料科學學習手劄25)sklearn中的特征選擇相關功能

2.4 SelectFromModel

  這是一種受算法限制比較大的特征篩選方法,使用這種算法的前提是你所選擇的算法的傳回項中含有coef_或feature_importances_項,即可用來衡量變量優劣的系數,通過這種系數對不同變量進行評分,然後按照設定的數目或比例剔除對應數目的最差變量,在sklearn.feature_selection中我們使用SelectFromModel()來實作上述過程,其主要參數如下:

estimator:基學習器,必須是含有coef_或feature_importances_輸出項的有監督學習算法;

threshold:指定留下的特征數量,預設值為"mean",有幾種不同的設定政策:

  1.字元型時,指定一個特殊的名額,當特征的評分系數小于這個名額時,保留,否則剔除;可選項有"median","mean",也可更加自由地指定為alpha*關鍵名額,這裡的alpha是一個連續實數,例如'1.5*median';

  2.數值型,且隻能設定為1e-5,适用于含有懲罰項的算法(如邏輯回歸,lasso回歸等);

prefit:是否進行預訓練,即制定的學習器在SelectFromModel之前就已經進行了fit操作,預設為False;

輸出項:

estimator_:傳回由最終保留的特征訓練成的學習器;

threshold_:之前參數設定的變量剔除名額量

注意,這裡若想檢視所有特征被篩選的情況,需要對儲存SelectFromModel fit之後的對象使用.get_support()方法才可以;

  這裡若使用其傳回的訓練好的學習器,則predict時不需要根據變量删減情況儲存的數組對測試樣本進行索引;

下面我們依舊使用威斯康辛州乳腺癌資料作為示範資料,決策樹作為基學習器,具體過程如下:

from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn.feature_selection import SelectFromModel
from sklearn.metrics import confusion_matrix as cm
from sklearn.model_selection import train_test_split


'''載入紅酒三分類資料'''
X,y = datasets.load_wine(return_X_y=True)

'''分格訓練集與測試集'''
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)

'''定義基學習器'''
estimator =DecisionTreeClassifier()

'''利用基學習器直接來訓練(不删除變量)'''
pre_ = estimator.fit(X_train,y_train).predict(X_test)

'''列印混淆矩陣'''
print('遞歸特征删減前:')
print(cm(y_test,pre_))

'''進行遞歸特征消除,這裡設定每一輪疊代中每次删去一個變量,并進行5折交叉驗證來用于評估性能'''
selector =SelectFromModel(estimator,threshold='median')

'''儲存最後訓練出的最優學習器'''
selector = selector.fit(X,y)

'''列印特征的剔除情況'''
print('列印特征的剔除情況')
print(selector.get_support())

'''利用得到的最優學習器來對驗證集進行預測'''
pre = selector.estimator_.predict(X_test)

'''列印混淆矩陣'''
print('遞歸特征删減後:')
print(cm(y_test,pre))      
(資料科學學習手劄25)sklearn中的特征選擇相關功能

 2.5 篩選特征和訓練模型基于不同的學習器(基于SelectFromModel)

  我們可以把特征選擇與真正使用的訓練學習器相獨立開來,例如我們可以使用支援向量機來作為特征選擇中使用到的算法,而将産出的資料用随機森林模型來訓練,通過sklearn.pipeline中的Pipeline就可以非常巧妙地将這些過程組合在一起,但這種方法不是很主流,在這裡就不展開說,欲了解詳情可以檢視sklearn的官網相關内容介紹頁:http://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline

  以上就是關于機器學習中特征選擇的基本内容,如有筆誤,望指出。

繼續閱讀