3.2 Embedded嵌入法
嵌入法是一種讓算法自己決定使用哪些特征的方法,即特征選擇和算法訓練同時進行。在使用嵌入法時,我們先使
用某些機器學習的算法和模型進行訓練,得到各個特征的權值系數,根據權值系數從大到小選擇特征。這些權值系
數往往代表了特征對於模型的某種貢獻或某種重要性,比如決策樹和樹的集成模型中的feature_importances_屬
性,可以列出各個特征對樹的建立的貢獻,我們就可以基於這種貢獻的評估,找出對模型建立最有用的特征。因此
相比於過濾法,嵌入法的結果會更加精確到模型的效用本身,對於提高模型效力有更好的效果。並且,由於考慮特
征對模型的貢獻,因此無關的特征(需要相關性過濾的特征)和無區分度的特征(需要方差過濾的特征)都會因為
缺乏對模型的貢獻而被刪除掉,可謂是過濾法的進化版。
過濾法中使用的統計量可以使用統計知識和常識來查找范圍(如p值應當低於顯著性水平0.05),而嵌入法中使用
的權值系數卻沒有這樣的范圍可找——我們可以說,權值系數為0的特征對模型絲毫沒有作用,但當大量特征都對
模型有貢獻且貢獻不一時,我們就很難去界定一個有效的臨界值。這種情況下,模型權值系數就是我們的超參數,
我們或許需要學習曲線,或者根據模型本身的某些性質去判斷這個超參數的最佳值究竟應該是多少。在我們之后的
學習當中,每次講解新的算法,我都會為大家提到這個算法中的特征工程是如何處理,包括具體到每個算法的嵌入
法如何使用。在這堂課中,我們會為大家講解隨機森林和決策樹模型的嵌入法
另外,嵌入法引入了算法來挑選特征,因此其計算速度也會和應用的算法有很大的關系。如果采用計算量很大,計
算緩慢的算法,嵌入法本身也會非常耗時耗力。並且,在選擇完畢之后,我們還是需要自己來評估模型
feature_selection.SelectFromModel class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1, max_features=None)
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的值越大,返回的特征越少。
參數
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
我們重點要考慮的是前兩個參數。在這里,我們使用隨機森林為例,則需要學習曲線來幫助我們尋找最佳特征值
from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import RandomForestClassifier as RFC RFC_ = RFC(n_estimators =10,random_state=0) X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y) #在這里我只想取出來有限的特征。0.005這個閾值對於有780個特征的數據來說,是非常高的閾值,因為平均每個特征 只能夠分到大約0.001的feature_importances_ X_embedded.shape #模型的維度明顯被降低了 #同樣的,我們也可以畫學習曲線來找最佳閾值 #======【TIME WARNING:10 mins】======# import numpy as np import matplotlib.pyplot as plt RFC_.fit(X,y).feature_importances_ threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20) 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.00134之前,模型的效果都可以維持在0.93以上,因此我們可以從中挑選一個數值來驗證一下模型的效果
X_embedded = SelectFromModel(RFC_,threshold=0.00067).fit_transform(X,y) X_embedded.shape cross_val_score(RFC_,X_embedded,y,cv=5).mean()
可以看出,特征個數瞬間縮小到324多,這比我們在方差過濾的時候選擇中位數過濾出來的結果392列要小,並且
交叉驗證分數0.9399高於方差過濾后的結果0.9388,這是由於嵌入法比方差過濾更具體到模型的表現的緣故,換一
個算法,使用同樣的閾值,效果可能就沒有這么好了。
和其他調參一樣,我們可以在第一條學習曲線后選定一個范圍,使用細化的學習曲線來找到最佳值:
#======【TIME WARNING:10 mins】======# score2 = [] for i in np.linspace(0,0.00134,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.00134,20),score2) plt.xticks(np.linspace(0,0.00134,20)) plt.show()
查看結果,果然0.00067並不是最高點,真正的最高點0.000564已經將模型效果提升到了94%以上。我們使用
0.000564來跑一跑我們的SelectFromModel
X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(X,y) X_embedded.shape cross_val_score(RFC_,X_embedded,y,cv=5).mean() #=====【TIME WARNING:2 min】=====# #我們可能已經找到了現有模型下的最佳結果,如果我們調整一下隨機森林的參數呢? cross_val_score(RFC(n_estimators=100,random_state=0),X_embedded,y,cv=5).mean()
得出的特征數目依然小於方差篩選,並且模型的表現也比沒有篩選之前更高,已經完全可以和計算一次半小時的
KNN相匹敵(KNN的准確率是96.58%),接下來再對隨機森林進行調參,准確率應該還可以再升高不少。可見,
在嵌入法下,我們很容易就能夠實現特征選擇的目標:減少計算量,提升模型表現。因此,比起要思考很多統計量
的過濾法來說,嵌入法可能是更有效的一種方法。然而,在算法本身很復雜的時候,過濾法的計算遠遠比嵌入法要
快,所以大型數據中,我們還是會優先考慮過濾法。