一、簡介
在現實的機器學習任務中,自變量往往數量眾多,且類型可能由連續型(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))
運行結果:
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)
運行結果:
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))
運行結果如下:
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))
運行結果:
2.5 篩選特征和訓練模型基於不同的學習器(基於SelectFromModel)
我們可以把特征選擇與真正使用的訓練學習器相獨立開來,例如我們可以使用支持向量機來作為特征選擇中使用到的算法,而將產出的數據用隨機森林模型來訓練,通過sklearn.pipeline中的Pipeline就可以非常巧妙地將這些過程組合在一起,但這種方法不是很主流,在這里就不展開說,欲了解詳情可以查看sklearn的官網相關內容介紹頁:http://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline
以上就是關於機器學習中特征選擇的基本內容,如有筆誤,望指出。