特征選擇
概念:就是從所有的特征中,選擇出有意義,對(duì)模型有幫助的特征屯碴,以避免必須將所有特征都導(dǎo)入模型去訓(xùn)練的情況巧涧。
特征選擇常用的方法有:過濾法,嵌入法判哥,包裝法献雅,和降維算法。
導(dǎo)入數(shù)據(jù)
import pandas as pd
data = pd.read_csv(r"C:\Users\18700\Desktop\03數(shù)據(jù)預(yù)處理和特征工程\digit recognizor.csv")
data.head()
X = data.iloc[:,1:] #特征矩陣
y = data.iloc[:,0] #標(biāo)簽
X.shape #維度指的是特征的數(shù)量塌计,這個(gè)數(shù)據(jù)維度太高
#(42000, 784)
"""
這個(gè)數(shù)據(jù)量相對(duì)夸張挺身,如果使用支持向量機(jī)和神經(jīng)網(wǎng)絡(luò),很可能會(huì)直接跑不出來锌仅。使用KNN跑一次大概需要半個(gè)小時(shí)章钾。
用這個(gè)數(shù)據(jù)舉例,能更夠體現(xiàn)特征工程的重要性热芹。
"""
1. Filter過濾法
過濾方法通常用作預(yù)處理步驟贱傀,特征選擇完全獨(dú)立于任何機(jī)器學(xué)習(xí)算法。
全部特征——最佳特征子集——算法——評(píng)估
1.1 方差過濾 (一般來說伊脓,只用來過濾到0/1的方差小的特征)
1.1.1 VarianceThreshold
通過特征本身的方差來篩選特征的類府寒。優(yōu)先消除方差為0的特征。VarianceThreshold有重要參數(shù)threshold,表示方差的閾值株搔,表示舍棄所有方差小于threshold的特征剖淀,不填默認(rèn)為0,即刪除所有的記錄都相同的特征纤房。
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold() #實(shí)例化纵隔,不填參數(shù)默認(rèn)方差為0
X_var0 = selector.fit_transform(X) #獲取刪除不合格特征之后的新特征矩陣
#也可以直接寫成 X = VairanceThreshold().fit_transform(X)
X_var0.shape #是一個(gè)ndarray
#(42000, 708) #可將特征變少了,刪除了方差為0的特征
#X_var0.head() #會(huì)報(bào)錯(cuò)
pd.DataFrame(X_var0).head() #所以需要轉(zhuǎn)換為dataframe
根據(jù)方差的中位數(shù)進(jìn)行過濾
#通過var的中位數(shù)進(jìn)行過濾
import numpy as np
X_fsvar = VarianceThreshold(np.median(X.var().values)).fit_transform(X) #就是舍棄方差小于中位數(shù)方差的特征
#X.var()是一個(gè)series帆卓,.values提取對(duì)應(yīng)的值
X.var().values
np.median(X.var().values)
X_fsvar.shape
#(42000, 392)
特征是伯努利隨機(jī)變量(二分類)
#若特征是伯努利隨機(jī)變量巨朦,假設(shè)p=0.8,即二分類特征中某種分類占到80%以上的時(shí)候刪除特征
X_bvar = VarianceThreshold(.8 * (1 - .8)).fit_transform(X)
X_bvar.shape
#(42000, 685)
1.1.2 方差過濾對(duì)模型的影響
- 最近鄰算法KNN剑令,單棵決策樹糊啡,支持向量機(jī)SVM,神經(jīng)網(wǎng)絡(luò)吁津,回歸算法棚蓄,都需要遍歷特征或升維來進(jìn)行運(yùn)算,所以他們本身的運(yùn)算量就很大碍脏,需要的時(shí)間就很長(zhǎng)梭依,因此方差過濾這樣的特征選擇對(duì)他們來說就尤為重要。
- 但對(duì)于不需要遍歷特征的算法典尾,比如隨機(jī)森林役拴,它隨機(jī)選取特征進(jìn)行分枝,本身運(yùn)算就非臣毓。快速河闰,因此特征選擇對(duì)它來說效果平平。
過濾法的主要對(duì)象是:需要遍歷特征或升維的算法們;
過濾法的主要目的是:在維持算法表現(xiàn)的前提下褥紫,幫助算法們降低計(jì)算成本姜性。
如果過濾之后模型的效果反而變差了,那么被過濾掉的特征中有很多是有效特征髓考,就需要放棄過濾部念。
1.2 相關(guān)性過濾
1.2.1 卡方過濾
卡方過濾是專門針對(duì)離散型標(biāo)簽(即分類問題)的相關(guān)性過濾。卡方檢驗(yàn)類feature_selection.chi2計(jì)算每個(gè)非負(fù)特征和標(biāo)簽之間的卡方統(tǒng)計(jì)量氨菇,并依照卡方統(tǒng)計(jì)量由高到低為特征排名儡炼。再結(jié)合feature_selection.SelectKBest這個(gè)可以輸入”評(píng)分標(biāo)準(zhǔn)“來選出前K個(gè)分?jǐn)?shù)最高的特征的類,我們可以借此除去最可能獨(dú)立于標(biāo)簽门驾,與我們分類目的無關(guān)的特征射赛。
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest #選擇k個(gè)分?jǐn)?shù)最高的特征
from sklearn.feature_selection import chi2 #卡方檢驗(yàn)
#假設(shè)在這里我需要300個(gè)特征
X_fschi = SelectKBest(chi2, k=300).fit_transform(X_fsvar, y) #選擇前300個(gè)卡方值的特征
X_fschi.shape
#(42000, 300)
驗(yàn)證模型的效果如何
cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
輸出結(jié)果
0.9344761904761905
'''
如果模型的效果降低了,這說明我們?cè)谠O(shè)定k=300的時(shí)候刪除了與模型相關(guān)且有效的特征奶是,
我們的K值設(shè)置得太小楣责,要么我們需要調(diào)整K值竣灌,要么我們必須放棄相關(guān)性過濾。
'''
1.2.2 選擇超參數(shù)K
卡方檢驗(yàn)的本質(zhì)是推測(cè)兩組數(shù)據(jù)之間的差異秆麸,其檢驗(yàn)的原假設(shè)是”兩組數(shù)據(jù)是相互獨(dú)立的”初嘹。卡方檢驗(yàn)返回卡方值和P值兩個(gè)統(tǒng)計(jì)量沮趣,我們可以根據(jù)P值進(jìn)行篩選屯烦,p<=0.05或0.01,說明兩組數(shù)據(jù)是相關(guān)的。
從特征工程的角度房铭,我們希望選取卡方值很大驻龟,p值小于0.05的特征,即和標(biāo)簽是相關(guān)聯(lián)的特征缸匪。
#選擇超參數(shù)K
chivalue, pvalues_chi = chi2(X_fsvar,y) #返回卡方值和P值
chivalue
pvalues_chi
#k取多少翁狐?我們想要消除所有p值大于設(shè)定值,比如0.05或0.01的特征:
#chivalue.shape[0]就是取出特征總個(gè)數(shù)凌蔬,pvalues_chi > 0.05返回TRUE Flase,False=0,TRUE=1,所以就是總特征數(shù)減去所以p>0.05的特征露懒,就是想保留的特征的數(shù)量
k = chivalue.shape[0] - (pvalues_chi > 0.05).sum()
#X_fschi = SelectKBest(chi2, k=填寫具體的k).fit_transform(X_fsvar, y) #就可以把上述的K值帶進(jìn)去
#cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
1.2.3 F檢驗(yàn)
F檢驗(yàn),又稱ANOVA砂心,方差齊性檢驗(yàn)懈词,是用來捕捉每個(gè)特征與標(biāo)簽之間的線性關(guān)系的過濾方法。它即可以做回歸也可以做分類辩诞,因此包含feature_selection.f_classif(F檢驗(yàn)分類)和feature_selection.f_regression(F檢驗(yàn)回歸)兩個(gè)類坎弯。它返回F值和p值兩個(gè)統(tǒng)計(jì)量。和卡方過濾一樣译暂,選取p值小于0.05或0.01的特征荞怒,這些特征與標(biāo)簽時(shí)顯著線性相關(guān)的。
#F檢驗(yàn)
from sklearn.feature_selection import f_classif
F, pvalues_f = f_classif(X_fsvar,y)
F
pvalues_f
k = F.shape[0] - (pvalues_f > 0.05).sum()
#X_fsF = SelectKBest(f_classif, k=填寫具體的k).fit_transform(X_fsvar, y)
#cross_val_score(RFC(n_estimators=10,random_state=0),X_fsF,y,cv=5).mean()
1.2.4 互信息法
互信息法是用來捕捉每個(gè)特征與標(biāo)簽之間的任意關(guān)系(包括線性和非線性關(guān)系)的過濾方法秧秉。和F檢驗(yàn)相似,它既可以做回歸也可以做分類衰抑,并且包含兩個(gè)類feature_selection.mutual_info_classif(互信息分類)和feature_selection.mutual_info_regression(互信息回歸)象迎。
它返回“每個(gè)特征與目標(biāo)之間的互信息量的估計(jì)”,這個(gè)估計(jì)量在[0,1]之間取值呛踊,為0則表示兩個(gè)變量獨(dú)立砾淌,為1則表示兩個(gè)變量完全相關(guān)。
from sklearn.feature_selection import mutual_info_classif as MIC
result = MIC(X_fsvar,y)
k = result.shape[0] - sum(result <= 0)
#X_fsmic = SelectKBest(MIC, k=填寫具體的k).fit_transform(X_fsvar, y)
#cross_val_score(RFC(n_estimators=10,random_state=0),X_fsmic,y,cv=5).mean()
1.3 過濾法總結(jié)
先使用方差過濾谭网,然后使用互信息法來捕捉相關(guān)性
2. Embedded嵌入法
嵌入法是一種讓算法自己決定使用哪些特征的方法汪厨,即特征選擇和算法訓(xùn)練同時(shí)進(jìn)行。
feature_selection.SelectFromModel
class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1,max_features=None)
參數(shù):
estimator:使用的模型評(píng)估器愉择,只要是帶feature_importances_或者coef_屬性劫乱,或帶有l(wèi)1和l2懲罰項(xiàng)的模型都可以使用织中。
threshold:特征重要性的閾值,重要性低于這個(gè)閾值的特征都將被刪除衷戈。
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier as RFC
RFC_ = RFC(n_estimators =10,random_state=0) #需要先實(shí)例化隨機(jī)森林狭吼,再帶入SelectFromModel。
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y) #這個(gè)是嵌入法的實(shí)例化
#在這里我只想取出來有限的特征殖妇。0.005這個(gè)閾值對(duì)于有780個(gè)特征的數(shù)據(jù)來說刁笙,是非常高的閾值,因?yàn)槠骄總€(gè)特征只能夠分到大約0.001的feature_importances_
X_embedded.shape
#(42000, 47) 模型的維度明顯被降低了
繪制threshold的學(xué)習(xí)曲線
import numpy as np
import matplotlib.pyplot as plt
RFC_.fit(X,y).feature_importances_ #看特征重要性
#linspace(小值谦趣,大值疲吸,個(gè)數(shù)) 在最大值和最小值之間取20個(gè)數(shù)
threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20) #讓閾值的取值在0到最大值之間取出20個(gè)數(shù)
score = []
for i in threshold:
X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
score.append(once)
plt.plot(threshold,score)
plt.show()
可見,隨著閾值越來越高前鹅,模型的效果逐漸變差摘悴,被刪除的特征越來越多,信息損失也逐漸變大嫡纠。但是在0.003之前烦租,模型的效果都可以維持在0.93以上,因此我們可以從中挑選一個(gè)數(shù)值來驗(yàn)證一下模型的效果除盏。
驗(yàn)證模型
X_embedded = SelectFromModel(RFC_,threshold=0.00067).fit_transform(X,y)
X_embedded.shape
#(42000, 324)
cross_val_score(RFC_,X_embedded,y,cv=5).mean()
#0.9391190476190475
接著叉橱,可以使用細(xì)化的學(xué)習(xí)曲線來找到最佳值
score2 = []
for i in np.linspace(0,0.002,20):
X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
score2.append(once)
plt.figure(figsize=[20,5])
plt.plot(np.linspace(0,0.002,20),score2)
plt.xticks(np.linspace(0,0.002,20))
plt.show()
模型驗(yàn)證
X_embedded = SelectFromModel(RFC_,threshold=0.000632).fit_transform(X,y)
X_embedded.shape
#(42000, 332) 可以看到特征其實(shí)增加了,因?yàn)殚撝翟O(shè)置的更小了
#驗(yàn)證模型效果如何
cross_val_score(RFC_,X_embedded,y,cv=5).mean()
#0.9407857142857143
我們可能已經(jīng)找到了現(xiàn)有模型下的最佳結(jié)果踱侣,如果我們調(diào)整一下隨機(jī)森林的參數(shù)呢粪小?
cross_val_score(RFC(n_estimators=100,random_state=0),X_embedded,y,cv=5).mean()
# 0.9630714285714287
可見,在嵌入法下抡句,我們很容易就能夠?qū)崿F(xiàn)特征選擇的目標(biāo):減少計(jì)算量探膊,提升模型表現(xiàn)。
3 Wrapper包裝法
包裝法也是一個(gè)特征選擇和算法訓(xùn)練同時(shí)進(jìn)行的方法待榔,但我們往往使用一個(gè)目標(biāo)函數(shù)作為黑盒來幫助我們選取特征逞壁,而不是自己輸入某個(gè)評(píng)估指標(biāo)或統(tǒng)計(jì)量的閾值。锐锣。區(qū)別于過濾法和嵌入法的一次訓(xùn)練解決所有問題腌闯,包裝法要使用特征子集進(jìn)行多次訓(xùn)練,計(jì)算成本位于嵌入法和過濾法之間雕憔。
最典型的目標(biāo)函數(shù)是遞歸特征消除法(Recursive feature elimination, 簡(jiǎn)寫為RFE)姿骏。它是一種貪婪的優(yōu)化算法,旨在找到性能最佳的特征子集斤彼。 它反復(fù)創(chuàng)建模型分瘦,并在每次迭代時(shí)保留最佳特征或剔除最差特征蘸泻,下一次迭代時(shí),它會(huì)使用上一次建模中沒有被選中的特征來構(gòu)建下一個(gè)模型擅腰,直到所有特征都耗盡為止蟋恬。
feature_selection.RFE
class sklearn.feature_selection.RFE (estimator, n_features_to_select=None, step=1, verbose=0)
參數(shù)estimator是需要填寫的實(shí)例化后的評(píng)估器,n_features_to_select是想要選擇的特征個(gè)數(shù)趁冈,step表示每次迭代中希望移除的特征個(gè)數(shù)歼争。
除此之外,RFE類有兩個(gè)很重要的屬性渗勘,.support_:返回所有的特征的是否最后被選中的布爾矩陣沐绒,以及.ranking_返回特征的按數(shù)次迭代中綜合重要性的排名。
from sklearn.feature_selection import RFE
RFC_ = RFC(n_estimators =10,random_state=0) #實(shí)例化RFC
#n_features_to_select是模型選擇的個(gè)數(shù)旺坠,step每迭代一次刪除50個(gè)特征
selector = RFE(RFC_, n_features_to_select=332, step=50).fit(X, y) #RFE的實(shí)例化和訓(xùn)練 332是上述模型效果最好時(shí)的特征數(shù)
selector.support_.sum() #support_返回特征是否被選中的布爾矩陣乔遮,求和其實(shí)就是n_features_to_select
selector.ranking_ #返回特征的重要性排名
X_wrapper = selector.transform(X)
#交叉驗(yàn)證驗(yàn)證模型
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
#0.9398809523809524
對(duì)包裝法畫學(xué)習(xí)曲線
score = []
for i in range(1,751,50): #每50個(gè)取一個(gè)值,和linspace不同取刃。
X_wrapper = RFE(RFC_,n_features_to_select=i, step=50).fit_transform(X,y)
once = cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
score.append(once)
plt.figure(figsize=[20,5])
plt.plot(range(1,751,50),score)
plt.xticks(range(1,751,50))
plt.show()
4 特征選擇總結(jié)
- 當(dāng)數(shù)據(jù)量很大的時(shí)候,優(yōu)先使用方差過濾和互信息法調(diào)整崩侠,再上其他特征選擇方法漆魔。
- 使用邏輯回歸時(shí),優(yōu)先使用嵌入法却音。
- 使用支持向量機(jī)時(shí)改抡,優(yōu)先使用包裝法。
- 迷茫的時(shí)候系瓢,從過濾法走起阿纤,看具體數(shù)據(jù)具體分析。