特征选择过滤法-方差过滤、F检验、互信息法
過濾法
過濾法通常用作預處理步驟,特征選擇完全獨立于任何機器學習算法。它是根據各種統計檢驗分數和相關性指標來選擇特征。
? ? ? ? 全部特征--->最佳特征子集--->算法--->模型評估
1.方差過濾 ---VarianceThreshold
這是一個通過特征本身的方差來篩選特征的類。比如一個特征的方差很小,就表示樣本在這個特征上基本沒有差異,可能特征中的大多數值都一樣,甚至整個特征的取值都相同,那么這個特征對于樣本區分沒有什么作用。所以無論接下來的特征工程要做什么,都要先消除方差為0的特征。VarianceThreshold有重要參數threshold,表示方差的閾值,表示舍棄所有方差小于threshold的特征,不填默認為0,即刪除所有記錄都相同的特征。方差過濾示例代碼如下:
import pandas as pd data=pd.read_csv(r"F:\sklearn預處理數據集\digit recognizor.csv") x=data.iloc[:,1:] y=data.iloc[:,0] x.shape #(42000, 784) 此數據集有42000行,784個特征from sklearn.feature_selection import VarianceThreshold selector=VarianceThreshold() #實例化,不填參數默認方差為0 x_var0=selector.fit_transform(x) #獲取刪除不合格特征之后的新特征矩陣 #也可以直接寫成x=VarianceThreshold().fit_transform(x) x_var0.shape #(42000, 708)?可以看出,在刪除了方差為0的特征之后,依然剩下708個特征,明顯還需要做進一步的特征選擇,假如這里只想保留一半的特征,那么可以設定一個讓特征總數減半的閾值,只要找到特征方差的中位數并設為參數threshold的值。
import numpy as np x_fsvar=VarianceThreshold(np.median(x.var().values)).fit_transform(x) x_fsvar.shape-------------------------------代碼分割線---------------------------- (42000, 392)PS:當特征是二分類時,特征的取值就是伯努利隨機變量,這些變量的方差可以計算為:?Var[X]=p(1-p)。其中X是特征矩陣,p是二分類特征中的一類在這個特征中所占的概率(注:伯努利分布指的是對于隨機變量X有, 參數為p(0<p<1),如果它分別以概率p和1-p取1和0為值)
假設p=0.8,即二分類特征中某種分類占到80%以上的時候刪除特征。
x_bvar=VarianceThreshold(0.8*(1-0.8)).fit_transform(x) x_bvar.shape--------------------代碼分割線---------------------------(42000, 685)1.1方差過濾后對模型的影響?
為了檢驗方差過濾后對模型的影響,這里分別用KNN和隨機森林兩種方法分別在方差過濾前和方差過濾后運行的效果和運行時間的對比。(KNN是K近鄰算法中的分類算法,其原理是利用每個樣本到其它樣本點的距離來判斷每個樣本點的相似度,然后進行樣本分類。KNN必出遍歷每個特征和每個樣本,因而特征越多,KNN的計算越緩慢)完整代碼如下:
#KNN 和 隨機森林在不同方差過濾效果下的對比 from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.neighbors import KNeighborsClassifier as KNN from sklearn.model_selection import cross_val_score import numpy as np x=data.iloc[:,1:] y=data.iloc[:,0] x_fsvar=VarianceThreshold(np.median(x.var().values)).fit_transform(x)#KNN-方差過濾前效果 cross_val_score(KNN(),x,y,cv=5).mean() %%timeit #計算代碼平均運行時間 cross_val_score(KNN(),x,y,cv=5).mean() #KNN-方差過濾后效果 cross_val_score(KNN(),x_fsvar,y,cv=5).mean() %%timeit #計算代碼平均運行時間 cross_val_score(KNN(),x_fsvar,y,cv=5).mean()#隨機森林-方差過濾前效果 cross_val_score(RFC(n_estimators=10,random_state=0),x,y,cv=5).mean() %%timeit #計算代碼平均運行時間 cross_val_score(RFC(n_estimators=10,random_state=0),x,y,cv=5).mean() #隨機森林-方差過濾后效果 cross_val_score(RFC(n_estimators=10,random_state=0),x_fsvar,y,cv=5).mean() %%timeit #計算代碼平均運行時間 cross_val_score(RFC(n_estimators=10,random_state=0),x_fsvar,y,cv=5).mean() -----------------------------------代碼分割線--------------------------------------- KNN-方差過濾前效果:0.965857142857143 KNN-方差過濾前時間:34.1 s ± 365 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)KNN-方差過濾后效果:0.966 KNN-方差過濾后時間:27.6 s ± 173 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)隨機森林-方差過濾前效果:0.9373571428571429 隨機森林-方差過濾前時間:11.5 s ± 305 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)隨機森林-方差過濾后效果:0.9390476190476191 隨機森林-方差過濾后時間:11.1 s ± 72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)根據以上結果,可以觀察到隨機森林的準確率略遜于KNN,但運行時間比KNN短。方差過濾后,隨機森林和KNN的準確率都微弱上升?,隨機森林運行時間基本無明顯變化,而KNN運行時間明顯減少。
Q:為什么隨機森林運行如此之快?為什么方差過濾對隨機森林沒有很大的影響?
A:這是由于兩種算法的原理中涉及到的計算量不同。最近鄰算法KNN,單棵決策樹,支持向量機SVM,神經網絡,回歸算法,都需要遍歷特征或升維來進行運算,所以他們本身的運算量就很大,需要的時間就很長,因此方差過濾這樣的特征選擇對他們來說尤為重要。但對于不需要遍歷特征的算法,比如隨機森林,它隨機選取特征進行分枝,本身運算就非常快速,因此特征選擇對它來說效果并不明顯。這其實很容易理解,無論過濾法如何降低特征的數量,隨機森林也只會選取固定數量的特征來建模;而最近鄰算法就不同了,特征越少,距離計算的維度就越少,模型明顯會隨著特征的減少而變得輕量。因此,
過濾法的主要對象是:需要遍歷特征或升維的算法
過濾法的主要目的是:在維持算法表現的前提下,幫助算法降低計算成本
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?--------------菜菜機器學習
Q:過濾法對隨機森林無效,卻對樹模型有效?
A: 從算法原理上來說,傳統決策樹需要遍歷所有特征,計算不純度后進行分枝,而隨機森林卻是隨機抽取進行計算和分枝。因此隨機森林的運算更快,過濾法對隨機森林無用,對決策樹卻有用。
在sklearn中,決策樹和隨機森林都是隨機選擇特征進行分枝,但決策樹在建模過程中隨 機抽取的特征數目卻遠遠超過隨機森林當中每棵樹隨機抽取的特征數目(比如對于這個780維的數據,隨機森林每棵樹只會抽取10-20個特征,而決策樹可能會抽取200~400個特征),因此,過濾法對隨機森林無用,卻對決策樹有用。也因此,在sklearn中,隨機森林中的每棵樹都比單獨的一棵決策樹簡單得多,高維數據下的隨機森林的計算比決策樹快很多。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?--------------菜菜機器學習
| 閾值很小? 被過濾掉的特征比較少? | 閾值較大 被過濾掉的特征比較少多 | |
| 模型表現 | 不會有太大影響 | 可能變得更好,代表被濾掉的特征大部分是噪音;也可能變糟糕,代表被濾掉的特征中很多都是有效特征 |
| 運行時間 | 可能降低模型的運行時間基于方差很小的特征有多少 當方差很小的特征不多時,對模型沒有太大影響 | 一定能夠降低模型的運行時間,算法在遍歷特征時的計算越復雜,運行時間下降得越多 |
在我們的對比中,我們使用的方差閾值是特征方差中的中位數,因此屬于閾值比較大,過濾掉的特征比較多的情況。無論是KNN還是隨機森林,在過濾掉一般特征之后,模型的精確度都上升了。這說明被我們過濾掉的特征在當前模式下大部分都是噪音,那我們就可以保留這個去掉了一半特征的數據,來為之后的特征選擇做準備。當然,如果過濾之后模型的效果變差了,我們就可以認為,被我們過濾掉的特征中有很多都是有效特征,那就應當采取另一種方法進行特征選擇。
2.相關性過濾
方差調訓完畢后,接下來就考慮相關性了,常用的來評判特征與標簽之間的相關性方法有:卡方檢驗,F檢驗,互信息法。
2.1卡方過濾
?????????卡方過濾是專門針對離散型標簽(即分類問題)的相關性過濾。卡方檢驗類feature_selection.chi2計算每個非負特征和標簽之間的卡方統計量,并依照卡方統計量由高到低為特征排名。再結合feature_selection.SelectKBest?這個可以輸入“評分標準”來選出前K個分數最高的特征的類,我們可以借此除去最可能獨立于標簽,與我們分類目的無關的特征。
? ? ? ? 另外,如果卡方檢驗檢測到某個特征中所有的值都相同,會提示我們適用方差先進性方差過濾。并且,剛才我們已經驗證過,當我們適用方差過濾篩掉一般特征之后,模型的表現是提升的,這里我們使用threshold=中位數時完成的方差過濾來做卡方檢驗。
from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.model_selection import cross_val_score #卡方檢驗 from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 #假設這里需要300個特征 x_fschi=SelectKBest(chi2,k=300).fit_transform(x_fsvar,y) x_fschi.shape #(42000, 300) #驗證模型效果 cross_val_score(RFC(n_estimators=10,random_state=0),x_fschi,y,cv=5).mean()---------------------------------------------------------------------------- 0.9344761904761905此時模型的效果降低了,說明在設定k=300的時候刪除了與模型相關且有效的特征,我們的k值設置得太小,需要重新調整k值,為了能夠選擇一個最優的超參數k,在這里可畫出學習曲線:
%matplotlib inline import matplotlib.pyplot as plt score=[] for i in range(390,200,-10):x_fschi=SelectKBest(chi2,k=i).fit_transform(x_fsvar,y)once=cross_val_score(RFC(n_estimators=10,random_state=0),x_fschi,y,cv=5).mean()score.append(once) plt.plot(range(390,200,-10),score) plt.show()得到的學習曲線如圖:
? ? ? ? ? ? ? ? ? ? ?
通過這條曲線,可以觀察到,隨著k值的不斷增加,模型的表現不斷上升,這說明,k越大越好,數據中所有的特征都是與特征相關的。但是運行這條曲線的時間同樣的也是非常長,接下來介紹一種更好的選擇k的方法:看p值選擇k。
卡方檢驗的本質是推測兩組數據間的差異,期檢驗的原假設是“兩組數據是相互獨立的”。卡方檢驗返回卡方值和p值兩個統計量,其中卡方值很難界定有效的范圍,而p值,一般使用0.05或0.01作為顯著性特征水平,即p值判斷的邊界
| p值 | <=0.05或0.01 | >0.05或0.01 |
| 數據差異 | 差異不是自然形成的 | 這些差異是很自然的樣本誤差 |
| 相關性 | 兩組數據是相關的 | 兩組數據是相互獨立的 |
| 原假設 | 拒絕原假設,接受備擇假設 | 接受原假設 |
?k=0,說明所有p值都小于0.05,也就是方差過濾已經把所有和標簽無關的特征都剔除了,或者中國數據集本身就不含與標簽無關的特征。在這種情況下,舍棄任何一個特征,都會舍棄對模型有用的信息,而使模型表現下降。接下來,繼續試用其它相關性過濾的方法來驗證。
2.2 F檢驗
????????F檢驗,又稱ANOVA,方差齊性檢驗,是用來捕捉每個特征與標簽之間的線性關系的過濾方法。F檢驗既可以做回歸,也可以做分類,因此包含faeture_selection.f_classif(F檢驗分類)和feature_selection.f_regression(F檢驗回歸)兩個類。其中F檢驗分類用于標簽是離散型變量的數據,而F檢驗回歸用于標簽是連續型變量的數據。
? ? ? ? 和卡方檢驗一樣,這兩個類需要和類SelectKBest連用,并且也可以直接通過輸出的統計量來判斷設置一個什么樣的k合適。F檢驗在數據服從正態分布時效果會非常穩定,所以在使用F檢驗過濾時通常會先將數據轉化為服從正態分布的方式。
????????F檢驗的本質是尋找兩組數據之間的線性關系,其原假設是“數據不存在顯著的線性關系”。它返回F值和p值兩個統計量。和卡方過濾一樣,我們希望選取p值小于0.01或0.05的特征,這些特征與標簽是顯著線性相關的。以F檢驗為例,繼續在數據集上進行特征選擇:
#F檢驗 from sklearn.feature_selection import f_classif F,pvalues_f=f_classif(x_fsvar,y) #print("F值",F) #print("p值",pvalues_f) k=F.shape[0]-(pvalues_f>0.05).sum() print(k) -------------------------------------------- k=0得到的結論和卡方過濾得到的結果一樣,沒有任何特征的p值大于0.05,所以有特征都與標簽相關,因此不需要相關性過濾。
2.3 互信息法?
????????互信息法是用來捕捉每個特征與標簽之間的任意關系(包括線性和非線性)的過濾方法。和F檢驗相似,它既可以做回歸,也可以做分類,并且包含兩個類feature_selection.mutual_info_classif(互信息分類) feature_selection.mutual_info_regression(互信息回歸)。這兩個類的用法和參數都和F檢驗一樣,但F檢驗只能找出線性關系,而互信息法可以找出任意關系。
? ? ? ? 互信息法不返回F值和p值類似的統計量,它返回“每個特征與目標之間互信息量的估計”,這個估計量在[0,1]之間取值,0表示兩個變量相互獨立,1則表示兩個變量完全相關,以互信息分類為例的代碼如下:
#互信息法 from sklearn.feature_selection import mutual_info_classif as MIC result=MIC(x_fsvar,y) #得到互信息量的估計 #print(result) (result>0).sum() ------------------------------------------------------------------- 392所有特征的互信息量估計都大于0,因此所有特征都與標簽有關。
3.過濾法總結
通常先使用方差過濾,再使用互信息法來捕捉相關性。
| 類 | 說明 | 超參數的選擇 |
| VarianceThreshold | 方差過濾,可輸入方差閾值,返回方差大于閾值的新特征矩陣 | (學習曲線) |
| SelectKBest | 用來選取K個統計量結果最佳的特征,生成符合統計量要求的新特征矩陣 | |
| chi2 | 卡方檢驗,專用于分類算法,捕捉相關性 | 追求p小于顯著性水平的特征 |
| f_classif | F檢驗分類,只能捕捉線性相關性 要求數據服從正態分布 | 追求p小于顯著性水平的特征 |
| f_regression | F檢驗回歸,只能捕捉線性相關性 要求數據服從正態分布 | 追求p小于顯著性水平的特征 |
| mutual_info_classif | 互信息分類,可以捕捉任何相關性 不能用于稀疏矩陣 | 追求互信息大于0的特征 |
| mutual_info_regression | 互信息回歸,可以捕捉任何相關性 不能用于稀疏矩陣 | 追求互信息大于0的特征 |
總結
以上是生活随笔為你收集整理的特征选择过滤法-方差过滤、F检验、互信息法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超级电容锂电池混合储能Simulink仿
- 下一篇: shell用法大全