机器学习如何计算特征的重要性_机器学习之特征工程
特征選擇是特征工程中的一個子集,從所有的特征中,選擇有意義的,對模型有幫助的特征,以避免將所有特征中對模型沒作用的特征導入模型去訓練,消耗不必要的計算資源。更正式地說,給定n個特征,我們搜索其中包括k(k
特征選擇之前一定要理解數據中特征的含義,可以先從業務上就能剔除一些不必要的特征,然后再進行技術上的特征選擇。
特征選擇方法有很多,接下來主要介紹以下幾種特征選擇方法:
一、Filter過濾法
1、方差過濾:
通過數據本身的方差來篩選特征。比如有一個特征本身的方差很小,就表示樣本在這個特征上基本沒有差異,可能特征中的大多數值都一樣,甚至整個特征的取值都相同,那這個特征對于樣本區分是沒有作用的。因此,首先需要去除樣本中方差為0的特征。
在sklearn.feature_selection模塊中的VarianceThreshold類是用來做方差特征選擇的。其中的threshold參數是控制過濾方差的閾值,默認是0。我們可以控制這個參數來選擇要去掉方差是多少的特征。
from sklearn.feature_selection import VarianceThresholdselector = VarianceThreshold()X_var = selector.fit_transform(X)threshold閾值設置對模型訓練的影響
| 模型表現 | 不會有太大影響 | 可能變更好,代表被過濾掉的特征大部分是噪音 也可能變糟糕,代表被過濾的特征中很多都是有效特征 |
| 運行時間 | 可能降低模型的運行時間,基于方差很小的特征有多少 當方差很小的特征不多時,對模型沒有太大影響 | 一定能降低模型的運行時間 算法在遍歷特征時的計算越復雜,運行時間下降得越多 |
案例:
# 選用集成算法隨機森林和鄰近算法KNN分別在方差過濾前和方差過濾后運行效果和運行時間的對比from sklearn.ensemble import RandomForestClassifier as RFCfrom sklearn.neighbors import KNeighborsClassifier as KNNfrom sklearn.model_selection import cross_val_scorefrom sklearn.feature_selection import VarianceThresholdimport numpy as npX = data.iloc[:, 1:]y = data.iloc[:,0]# 進行方差過濾時閾值設置為中位數X_var = VarianceThreshold(np.median(X.var().values)).fit_transform(X)# KNN方差過濾之前的訓練cross_val_score(KNN(),X,y,cv=5).mean() # 運行時間比較長# KNN方差過濾之后的訓練cross_val_score(KNN(),X_var,y,cv=5).mean() # 運行時間比較長"""對于KNN,過濾后的運行效果:準確率提升了一點點,訓練時間減少很多。"""# 隨機森林方差過濾之前的訓練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_var,y,cv=5).mean()"""對于隨機森林,過濾后的運行效果:準確率提升了一點點,訓練時間差不多。因為隨機森林訓練速度本身就非常快。"""案例中使用的方差閾值是特征方差的中位數,閾值設置的比較大,屬于過濾掉的特征比較多的情況。從運行結果來看,無論是KNN還是隨機森林,在過濾掉一半特征之后,模型的精確度都有所上升。這說明被過濾掉的特征在當前隨機模式(random_state = 0)下大部分是噪音。那么可以保留這個去掉了一半特征的數據,來為之后的特征選擇做準備。如果過濾之后模型的效果反而變差了,則可以認為被我們過濾掉的特征中有很多有效特征,因此需要放棄過濾,使用其他手段來進行特征選擇。
為什么隨機森林運行如此之快? 為什么方差過濾對隨機森林沒很大的有影響?
這是由于兩種算法的原理中涉及到的計算量不同。最近鄰算法KNN,單棵決策樹,支持向量機SVM,神經網絡,回歸算法,都需要遍歷特征或升維來進行運算,所以他們本身的運算量就很大,需要的時間就很長,因此方差過濾這樣的特征選擇對他們來說就尤為重要。但對于不需要遍歷特征的算法,比如隨機森林,它隨機選取特征進行分枝,本身運算就非常快速,因此特征選 擇對它來說效果平平。這其實很容易理解,無論過濾法如何降低特征的數量,隨機森林也只會選取固定數量的特征 來建模;而最近鄰算法就不同了,特征越少,距離計算的維度就越少,模型明顯會隨著特征的減少變得輕量。因此,過濾法的主要對象是:需要遍歷特征或升維的算法們,而過濾法的主要目的是:在維持算法表現的前提下,幫 助算法們降低計算成本。為什么過濾法對隨機森林無效,卻對樹模型有效?
從算法原理上來說,傳統決策樹需要遍歷所有特征,計算不純度后進行分枝,而隨機森林卻是隨機選擇特征進 行計算和分枝,因此隨機森林的運算更快,過濾法對隨機森林無用,對決策樹卻有用。
在sklearn中,決策樹和隨機森林都是隨機選擇特征進行分枝(不記得的小伙伴可以去復習第一章:決策樹, 參數random_state),但決策樹在建模過程中隨機抽取的特征數目卻遠遠超過隨機森林當中每棵樹隨機抽取 的特征數目(比如說對于這個780維的數據,隨機森林每棵樹只會抽取10~20個特征,而決策樹可能會抽取 300~400個特征),因此,過濾法對隨機森林無用,卻對決策樹有用。
在sklearn中,隨機森林中的每棵樹都比單獨的一棵決策樹簡單得多,高維數據下的隨機森林的計算 比決策樹快很多。
2、 相關性過濾
相關性主要是評判特征之間以及特征和標簽之間的相關性,去除特征之間的相關性主要是因為諸如線性回歸之類的模型訓練時特征之間相關產生共線性的問題而影響模型效果。去除與標簽不相關的特征主要是因為如果特征與標簽無關,那只會白白浪費我們的計算內存,可能還會給模型帶來噪聲。
在sklearn中,常用評判特征與標簽之間相關性的方法有:卡方、F檢驗、互信息。常用評判特征之間的相關性的方法有pearson相關系數。
卡方過濾卡方過濾是專門針對離散型標簽(即分類問題)的相關性過濾。在chi2計算每個非負特征和標簽之間的卡方統計量,并依照卡方統計量由高到低為特征排名。然后,再結合SelectBest這個可以輸入“評分標準”的類來選出前K個分數最高的特征,即去除最可能獨立于標簽,與分類目的無關的特征。當卡方檢驗檢測到某個特征中所有的值都相同,會提示我們使用方差先進行方差過濾。所以在做卡方相關性過濾之前要選使用方差過濾篩選一遍。
from sklearn.feature_selection import SelectKBestfrom sklearn.feature_selection import chi2from sklearn.model_selection import cross_val_score# X_var是方差過濾掉特征之后的特征矩陣X_chi = SelectKBest(chi2, k=300).fit_transform(X_var, y)cross_val_score(RFC(n_estimators=100, random_state=0), X_chi, y, cv=5).mean()結果顯示模型效果降低了,這說明我們在設定k=300的時候刪除了與模型相關且有效的特征,我們的K值設置得太小,要么我們需要調整K值,要么我們必須放棄相關性過濾。
當然,如果模型的表現提升,則說明我們的相關性過濾是有效的,是過濾掉了模型的噪音的,這時候我們就保留相關性過濾的結果。
參數k的設置可以使用學習曲線進行選擇:
import?matplotlib.pyplot as pltscore = []for?i?in?range(390, 200, -10):??X_chi =?SelectKBest(chi2,?k=i).fit_transform(X_var,?y)??once = cross_val_score(RFC(n_estimators=100,random_state=0), X_chi, y, cv=5).mean()??score.append(once)plt.plot(range(390, 200, -10), score)plt.show()?代碼運行結果:由圖可知,隨著k值的不斷增加,模型的表現不斷上升,這說明,k越大越好,數據中所有的特征都與標簽相關,但是這種選擇k值的代碼運行時間非常長。下面一種更好的設置k值的方法:根據p值來選擇k
卡方檢驗的本質是推測兩組數據之間的差異,其檢驗的原假設是”兩組數據是相互獨立的”。卡方檢驗返回卡方值和 P值兩個統計量,其中卡方值很難界定有效的范圍,而p值,我們一般使用0.01或0.05作為顯著性水平,即p值判斷 的邊界,具體我們可以這樣來看:
| 數據差異 | 差異不是自然形成的 | 這些差異是很自然的樣本誤差 |
| 相關性 | 兩組數據是相關的 | 兩組數據是相互獨立的 |
| 原假設 | 拒絕原假設,接受備擇假設 | 接受原假設 |
從特征工程的角度,我們希望選取卡方值很大,p值小于0.05的特征,即和標簽是相關聯的特征。而調用 SelectKBest之前,我們可以直接從chi2實例化后的模型中獲得各個特征所對應的卡方值和P值。
chi_val, p_val_chi = chi2(X_var,y)# k取多少?我們想要消除所有p值大于設定值,比如0.05或0.01的特征:k = chi_val.shape[0] - (p_val_chi > 0.05).sum()# X_chi = SelectKBest(chi2, k=填寫具體的k).fit_transform(X_var, y) # cross_val_score(RFC(n_estimators=10,random_state=0),X_chi,y,cv=5).mean()從結果看,所有特征的p值都是0,說明digit_recognizor這個數據集,方差驗證已經把所有和標簽無關的特征都剔除了,或者這個數據集本身就不含與標簽無關的特征。因此,舍棄任何一個特征,都會舍棄對模型有用的信息,而使模型表現下降,因此在我們對計算速度感到滿意時,我們不需要使用相關性過濾來過濾我 們的數據。如果我們認為運算速度太緩慢,那我們可以酌情刪除一些特征,但前提是,必須犧牲模型的表現。
F檢驗F檢驗,又稱方差齊性檢驗,是用來捕捉每個特征與標簽之間的線性關系的過濾方法。它即可以做回歸也可以做分類,因此sklearn.feature_selection中包含f_classif(F檢驗分類)和f_regression(F檢驗回歸)兩個類。其中F檢驗分類用于標簽是離散型變量的數據,而F檢驗回歸用于標簽是連續型變量的數據。
這兩個類也需要和類SelectKBest連用,并且我們也可以直接通過輸出的統計量來設置最佳K值。需要注意的是,F檢驗在數據服從正態分布時效果會非常穩定,因此如果使用F檢驗過濾,需要先將數據轉換成服從正態分布。
F檢驗的本質是尋找兩組數據之間的線性關系,其原假設是”數據不存在顯著的線性關系“。它返回F值和p值兩個統 計量。和卡方過濾一樣,我們希望選取p值小于0.05或0.01的特征,這些特征與標簽時顯著線性相關的,而p值大于 0.05或0.01的特征則被我們認為是和標簽沒有顯著線性關系的特征,應該被刪除。以F檢驗的分類為例做特征選擇:
from sklearn.feature_selection import f_classifF, p_val = f_classif(X_var, y)k = F.shape[0] - (p_val > 0.05).sum()# X_F = SelectKBest(f_classif, k=填寫具體的k值).fit_transform(X_var, y)# cross_val_score(RFC(n_estimators=10,random_state=0),X_F,y,cv=5).mean()結果和卡方過濾得到的結果一模一樣,沒有任何特征的p值大于0.01, 所有的特征都是和標簽相關的,因此不需要相關性過濾
互信息過濾
互信息是用來捕捉每個特征與標簽之間的任意關系(包括線性和非線性關系)的過濾方法。和F檢驗相似,它既可以做回歸也可以做分類,也包含mutual_info_classif(互信息分類)和 mutual_info_regression(互信息回歸)兩個類。用法和參數都與F檢驗一模一樣,不過互信息比F檢驗更加強大,F檢驗只能夠找出線性關系,而互信息可以找出任意關系。
互信息不返回p值或F值類似的統計量,它返回“每個特征與目標之間的互信息量的估計”,這個估計量在[0,1]之間,為0則表示兩個變量獨立,為1則表示兩個變量完全相關。以互信息分類為例的代碼如下:
from sklearn.feature_selection import mutual_info_classif as MICresult = MIC(X_var, y)k = result.shape[0] - sum(result <= 0)# X_mic = SelectKBest(MIC, k=填寫具體的k值).fit_transform(X_var, y)# cross_val_score(RFC(n_estimators=10, random_state=0), X_mic, y, cv=5).mean()所有特征的互信息量估計都大于0,說明所有特征都與標簽相關。
無論是F檢驗還是互信息法,大家也都可以使用學習曲線,只是使用統計量的方法會更加高效。當統計量判斷已經沒有特征可以刪除時,無論用學習曲線如何跑,刪除特征都只會降低模型的表現。而如果數據量太龐大,模型太復雜,還是可以犧牲模型表現來提升模型速度。
一般情況下先使用方差過濾,然后使用互信息來捕捉相關性,下面是各個類的總結:
| VarianceThreshold | 方差過濾,可輸入方差閾值控制特征選擇,返回方差大于閾值的新特征矩陣 | 看具體數據究竟是含更多噪聲還是更多有效特征,一般就使用0或1來篩選也可以畫學習曲線或取中位數跑模型來幫助確認 |
| SelectKBest | 用來選取K個統計量結果最佳的特征,生成符合統計量要求的新特征矩陣 | 看配合使用的統計量 |
| chi2 | 卡方檢驗,專用于分類算法,捕捉相關性 | 追求p值小于顯著水平的特征 |
| f_classif | F檢驗分類,只能捕捉線性相關性,要求數據服從正態分布 | 追求p值小于顯著水平的特征 |
| f_regression | F檢驗回歸,只能捕捉線性相關性,要求數據服從正態分布 | 追求p值小于顯著水平的特征 |
| mutual_info_classif | 互信息分類,可以捕捉任何相關性,不能用于稀疏矩陣 | 追求互信息估計大于0的特征 |
| mutual_info_regression | 互信息回歸,可以捕捉任何相關性,不能用于稀疏矩陣 | 追求互信息估計大于0的特征 |
二、Embedded嵌入法
嵌入法是一種讓算法自己決定使用那些特征的方法,即特征選擇和算法訓練同時進行。在使用嵌入法時,我們先使用某些機器學習的算法和模型進行訓練,得到各個特征的權值系數,根據權值系數從大到小選擇特征。這些權值系 數往往代表了特征對于模型的某種貢獻或某種重要性,比如決策樹和樹的集成模型中的feature_importances_屬 性,可以列出各個特征對樹的建立的貢獻,我們就可以基于這種貢獻的評估,找出對模型建立最有用的特征。因此 相比于過濾法,嵌入法的結果會更加精確到模型的效用本身,對于提高模型效力有更好的效果。并且,由于考慮特征對模型的貢獻,因此無關的特征(需要相關性過濾的特征)和無區分度的特征(需要方差過濾的特征)都會因為缺乏對模型的貢獻而被刪除掉,可謂是過濾法的進化版。
嵌入法整個流程為:過濾法中使用的統計量可以使用統計知識和常識來查找范圍(如p值應當低于顯著性水平0.05),而嵌入法中使用的權值系數卻沒有這樣的范圍可找——我們可以說,權值系數為0的特征對模型絲毫沒有作用,但當大量特征都對模型有貢獻且貢獻不一時,我們就很難去界定一個有效的臨界值。這種情況下,模型權值系數就是我們的超參數, 我們或許需要學習曲線,或者根據模型本身的某些性質去判斷這個超參數的最佳值究竟應該是多少。
另外,嵌入法引入了算法來挑選特征,因此其計算速度也會和應用的算法有很大的關系。如果采用計算量很大,計 算緩慢的算法,嵌入法本身也會非常耗時耗力。并且,在選擇完畢之后,我們還是需要自己來評估模型。
在sklearn.feature_selection模塊中SelectFromModel類嵌入法
class?sklearn.feature_selection.SelectFromModel(estimator, threshold=None, prefit=False, norm_order=1, max_features=None)類的參數說明具體如下表,并且一般重點關注前兩個參數的設置
| estimator | 使用的模型評估器,只要是帶feature_importances_或者coef_屬性,或帶有l1和l2懲罰項的模型都可以使用 |
| threshold | 特征重要性的閾值,重要性低于這個閾值的特征都將被刪除 |
| prefit | 默認False,判斷是否將實例化后的模型直接傳遞給構造函數,如果是True,則必須直接調用fit和transform, 不能使用fit_transform,并且SelectFromModel不能與cross_val_score,GridSearchCV和克隆估計器的類似實用程序一起使用 |
| norm_order | k可輸入非零整數,正無窮,負無窮,默認值為1,在評估器的coef_屬性高于一維的情況下, 用于過濾低于閾值的系數的向量的范數的階數 |
| max_features | 在閾值設定下,要選擇的最大特征數。要禁用閾值并僅根據max_features選擇,請設置threshold=-np.inf |
SelectFromModel是一個元變換器,可以與任何在擬合后具有coef_,feature_importances_屬性或參數中可選懲 罰項的評估器一起使用(比如隨機森林和樹模型就具有屬性feature_importances_,邏輯回歸就帶有l1和l2懲罰 項,線性支持向量機也支持l2懲罰項)。
對于有feature_importances_的模型來說,若重要性低于提供的閾值參數,則認為這些特征不重要并被移除。feature_importances_的取值范圍是[0,1],如果設置閾值很小,比如0.001,就可以刪除那些對標簽預測完全沒貢 獻的特征。如果設置得很接近1,可能只有一兩個特征能夠被留下。
使用懲罰項的模型的嵌入法
對于使用懲罰項的模型來說,正則化懲罰項越大,特征在模型中對應的系數就會越小。當正則化懲罰項大到 一定的程度的時候,部分特征系數會變成0,當正則化懲罰項繼續增大到一定程度時,所有的特征系數都會趨 于0。但是我們會發現一部分特征系數會更容易先變成0,這部分系數就是可以篩掉的。也就是說,我們選擇 特征系數較大的特征。另外,支持向量機和邏輯回歸使用參數C來控制返回的特征矩陣的稀疏性,參數C越小,返回的特征越少。Lasso回歸,用alpha參數來控制返回的特征矩陣,alpha的值越大,返回的特征越少。
在嵌入法下,我們很容易就能夠實現特征選擇的目標:減少計算量,提升模型表現。因此,比起要思考很多統計量的過濾法來說,嵌入法可能是更有效的一種方法。然而,在算法本身很復雜的時候,過濾法的計算遠遠比嵌入法要 快,所以大型數據中,我們還是會優先考慮過濾法。
三、Wrapper包裝法
包裝法也是一個特征選擇和算法訓練同時進行的方法,與嵌入法十分相似,它也是依賴于算法自身的選擇,比如 coef_屬性或feature_importances_屬性來完成特征選擇。但不同的是,我們往往使用一個目標函數作為黑盒來幫 助我們選取特征,而不是自己輸入某個評估指標或統計量的閾值。包裝法在初始特征集上訓練評估器,并且通過 coef_屬性或通過feature_importances_屬性獲得每個特征的重要性。然后,從當前的一組特征中修剪最不重要的 特征。在修剪的集合上遞歸地重復該過程,直到最終到達所需數量的要選擇的特征。區別于過濾法和嵌入法的一次 訓練解決所有問題,包裝法要使用特征子集進行多次訓練,因此它所需要的計算成本是最高的。注意:在這個圖中的“算法”,指的不是我們最終用來導入數據的分類或回歸算法(即不是隨機森林),而是專業的數據挖掘算法,即我們的目標函數。這些數據挖掘算法的核心功能就是選取最佳特征子集。
最典型的目標函數是遞歸特征消除法(Recursive feature elimination, 簡寫為RFE)。它是一種貪婪的優化算法, 旨在找到性能最佳的特征子集。它反復創建模型,并在每次迭代時保留最佳特征或剔除最差特征,下一次迭代時, 它會使用上一次建模中沒有被選中的特征來構建下一個模型,直到所有特征都耗盡為止。然后,它根據自己保留或剔除特征的順序來對特征進行排名,最終選出一個最佳子集。包裝法的效果是所有特征選擇方法中最利于提升模型表現的,它可以使用很少的特征達到很優秀的效果。除此之外,在特征數目相同時,包裝法和嵌入法的效果能夠匹敵,不過它比嵌入法算得更見緩慢,所以也不適用于太大型的數據。相比之下,包裝法是最能保證模型效果的特征選擇方法。
在sklearn.feature_selection模塊中有RFE的實現
參數:
| estimator | 使用的模型評估器 |
| n_features_to_select | 想要選擇的特征個數 |
| step | 每次迭代中希望移除的特征個數 |
| verbose | 控制輸入冗長 |
重要屬性:
| support_ | 返回所有的特征的是否最后被選中的布爾矩陣 |
| ranking_ | 返回特征的按數次迭代中綜合重要性的排名 |
四、總結
以上只是介紹特征選擇方法一部分,每種方法的原理都不同,并且都涉及到不同調整方法的超參數。一般來說,過濾法更快速,但更粗糙。包裝法和嵌入法更精確,比較適合具體到算法去調整,但計算量比較大,運行時間長。當數據量很大的時候,優先使用方差過濾和互信息法調整,再上其他特征選擇方法。使用邏輯回歸時,優先使用嵌入法。使用支持向量機時,優先使用包裝法。迷茫的時候,從過濾法走起,看具體數據具體分析。
特征選擇只是特征工程中的一小步。更高級的方法往往是使用特征創造或特征提取來尋找高級特征。在Kaggle之 類的算法競賽中,很多高分團隊都是在高級特征上做文章,而這是比調參和特征選擇更難的。特征工程非常深奧,需要在工作學習中不斷積累。
總結
以上是生活随笔為你收集整理的机器学习如何计算特征的重要性_机器学习之特征工程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python入门级教学之(Python中
- 下一篇: Linux的实际操作:任务调度基本说明