- Python機器學習(原書第3版)
- (美)塞巴斯蒂安·拉施卡 瓦希德·米爾賈利利
- 4197字
- 2021-06-11 16:13:47
4.5 選擇有意義的特征
如果發現模型在訓練數據集上的表現遠比在測試數據集要好,那么很有可能發生了過擬合現象。正如在第3章中所討論的那樣,過擬合意味著模型在擬合參數的過程中,對訓練數據集中某些特征的適應性過強,但卻不能很好地泛化新數據,因此模型的方差比較大。過擬合的原因是,與給定的訓練數據相比,我們的模型太過復雜。降低泛化誤差的常見解決方案如下:
- 收集更多的訓練數據。
- 通過正則化引入對復雜性的懲罰。
- 選擇參數較少的簡單模型。
- 降低數據的維數。
收集更多的訓練數據通常不太適用。在第6章中,我們將介紹一種實用技術,幫助判斷提供更多的訓練數據是否對我們有所幫助。在下面的章節中,我們將學習如何通過特征選擇來實現正則化和降維,從而采用需要較少參數的簡單模型來擬合數據,進而減少過擬合的機會。
4.5.1 L1和L2正則化對模型復雜度的懲罰
回顧第3章,L2正則化是通過懲罰權重大的個體來降低模型復雜度的一種方法。我們定義權重向量w的L2范數如下:
另外一種降低模型復雜度的方法是L1正則化:
這里,我們只是用權重絕對值之和替代了權重平方之和。與L2正則化相比,L1正則化通常會產生大部分特征權重為0的稀疏特征向量。如果高維數據集的樣本包含許多不相關的特征,特別是不相關特征數量大于樣本數量時,稀疏性很有實有價值。從這個意義上說,L1正則化可以理解為一種特征選擇技術。
4.5.2 L2正則化的幾何解釋
如上節所述,L2正則化為代價函數增加了懲罰項,與未正則化的代價函數所訓練的模型相比,L2還能有效地抑制極端權重值。
為了更好地理解L1正則化對數據進行稀疏化,我們首先來看一下正則化的幾何解釋。我們繪制權重系數為w1和w2的凸代價函數的等高線。
這里,我們用第2章中Adaline所采用的代價函數——誤差平方和(SSE)作為代價函數,因為它是球形的,比邏輯回歸的代價函數更容易繪制。在后續內容中,我們還將再次使用此代價函數。請記住,我們的目標是尋找一個權重系數的組合,能夠最小化訓練數據的代價函數,如圖4-4所示(橢圓中心點)。

圖 4-4
現在,我們可以把正則化看作是在代價函數中加入懲罰項來促進較小的權重,換句話說,懲罰較大的權重。因此,通過正則化參數λ增加正則化的強度,使得權重趨于零,從而降低模型對訓練數據的依賴性。圖4-5說明了L2懲罰項的概念。

圖 4-5
用陰影表示的球來表示二次的L2正則項。在這里,我們的權重系數不能超出正則化的區域——權重系數的組合不能落在陰影區域之外。另外,我們仍然希望最小化代價函數。在懲罰的約束下,盡最大的可能確定L2球與無懲罰項的代價函數等高線的交叉點。正則化參數λ越大,含懲罰項的代價函數增速就越快,導致L2球變窄。如果正則化參數λ趨于無窮大,那么權重系數將快速變為0,即成為L2球的圓心。總之,我們的目標是最小化無懲罰項的代價函數與懲罰項的總和,可以將其理解為增加偏置并采用更簡單的模型來降低在訓練數據不足的情況下擬合模型的方差。
4.5.3 L1正則化的稀疏解決方案
現在,我們來討論L1正則化和稀疏性。L1正則化的主要概念與我們前面討論的類似。然而,由于L1懲罰項是權重系數絕對值的和(記住L2是二次項),因此可以用菱形區域來表示,如圖4-6所示。

圖 4-6
從圖4-6中我們可以看到,代價函數等高線與L1菱形在w1=0處相交。由于L1正則化系統的邊界是尖銳的,因此這個交點更可能是最優的代價函數的橢圓與L1菱形邊界的交點位于坐標軸上,從而促進了稀疏性。
L1正則化與稀疏性
關于L1正則化可能導致稀疏性的數學細節超出了本書的范圍。如果你有興趣,可以在The Elements of Statistical Learning的3.4節中發現對L2和L1正則化的極好解釋,該書由Trevor Hastie、Robert Tibshirani和Jerome Friedman撰寫,由Springer于2009年出版。
對于scikit-learn中支持L1正則化的正則化模型,我們可以簡單地將參數penalty
設置為'l1'
來獲得稀疏解:

請注意,我們還需要選擇其他不同的優化算法(例如solver='liblinear'
),因為'lbfgs'
目前還不支持L1正則化的損失優化。將L1正則化邏輯回歸應用于標準的Wine數據,將得出以下稀疏解:

訓練和測試準確率(100%)表明模型在這兩個數據集上的表現都很好。當我們通過lr.intercept_
屬性訪問截距項時,可以看到數組返回三個值:

由于通過一對其余(OvR)方法在多元分類數據集上擬合LogisticRegression
對象,第一個截距值屬于擬合類1而不是類2和3的模型,第二個截距值屬于擬合類2而不是類1和3的模型,第三個截距值屬于擬合類3而不是類1和2的模型:

通過訪問lr.coef_
屬性,我們獲得包含三行權重系數的權重數組,每一權重向量對應一個分類。每行由13個權重組成,我們用每個權重乘以13維葡萄酒數據集中的特征值來計算凈輸入:

訪問scikit-learn估計器的偏差和權重參數
在scikit-learn中,w0對應intercept_
,當j>0時,wj值對應coef_
。
由于L1正則化是一種特征選擇方法,我們只訓練了一個對數據集中潛在不相關特征處理能力強的模型。嚴格地說,前面例子中的權重向量不一定稀疏,因為它們所包含的非零項更多。然而,可以通過進一步增加正則化強度來增強稀疏性(更多零項),即選擇較小的C
參數值。
在本章的最后一個正則化示例中,我們將改變正則化強度并繪制正則化的路徑,即不同特征在不同正則化強度下的權重系數:

執行上述代碼產生圖4-7所示的路徑圖,這為解釋L1正則化行為提供了更進一步的認識。正如我們所看到的,在一個強大的正則化參數(C<0.01)作用下,懲罰項使得所有的特征權重都為零,C是正則化參數λ的逆。

圖 4-7
4.5.4 序列特征選擇算法
另外一種降低模型復雜度并避免過擬合的方法是通過特征選擇進行降維,這對未正則化的模型特別有用。主要有兩類降維技術:特征選擇和特征提取。通過特征選擇可以從原始特征中選擇子集,而特征提取則是從特征集中提取信息以構造新的特征子空間。
在本節,我們將看到一些經典的特征選擇算法。第5章將討論不同的特征提取技術以把數據集壓縮到低維特征子空間。
序列特征選擇算法屬于貪婪搜索算法,用于把初始的d維特征空間降低到k維特征子空間(k<d)。特征選擇算法的動機是自動選擇與問題最相關的特征子集,提高模型的計算效率,或者通過去除不相關的特征或噪聲降低模型的泛化誤差,這對不支持正則化的算法很有效。
經典的序列特征選擇算法是序列后向選擇(seguehtial baekward selection,SBS),其目的是在分類器性能衰減最小的約束下,降低初始特征子空間的維數,以提高計算效率。在某些情況下,SBS甚至可以在模型面臨過擬合問題時提高模型的預測能力。
貪婪搜索算法
貪婪算法在組合搜索問題的每個階段都做出局部最優選擇,通常會得到待解決問題的次優解,而窮舉搜索算法則評估所有可能的組合,并保證找到最優解。然而,在實踐中,窮舉搜索往往在計算上不可行,而貪婪算法則可以找到不太復雜且計算效率更高的解決方案。
SBS算法背后的理念非常簡單:它順序地從完整的特征子集中移除特征,直到新特征子空間包含需要的特征數量。為了確定每個階段要刪除哪個特征,需要定義期待最小化的標準衡量函數(criterion function)J。
可以簡單地把標準衡量函數計算的標準值定義為在去除特定特征前后分類器的性能差異。每個階段要去除的特征可以定義為該標準值最大的特征;或者更直觀地說,每個階段去除性能損失最小的那個特征。基于前面SBS的定義,我們可以總結出四個簡單的步驟來描述該算法:
1)用k=d初始化算法,d為特征空間Xd的維數。
2)確定最大化標準x-=argmax J(Xk-x)的特征x-,其中x∈Xk。
3)從特征集中去除特征x-:Xk-1=Xk-x-;k=k-1。
4)如果k等于期望的特征數,則停止;否則,跳轉到步驟2。
序數列特征算法資源
讀者可以在文獻(Comparative Study of Techniques for Large-Scale Feature Selection, F. Ferri, P. Pudil, M. Hatef, and J. Kittler, pages 403-413, 1994)中發現對幾種序列特征算法的詳細評價。
不幸的是,scikit-learn尚未實現SBS算法。但是它很簡單,我們可以用Python實現:


前面的實現定義了參數k_features
,指定了想要返回的理想特征數目。在默認情況下,我們調用scikit-learn的accuracy_score
對模型在特征子空間的性能(分類估計器)進行評估。
在fit
方法的while
循環中,我們對由itertools.combination
函數創建的特征子集循環地進行評估刪減,直至特征子集達到預期維度。在每次迭代中,我們根據內部創建的測試數據集X_test
收集每個最優子集的準確率得分,并將其存儲在列表self.scores_
中。稍后我們將用這些分數來評估。最終特征子集的列號被賦給self.indices_
,我們可以用它調用transform
方法,返回包括選定特征列在內的新數據數組。注意,fit
方法并未具體計算判斷標準,而是簡單地去除了沒有包含在最優特征子集中的特征。
現在,讓我們看看實現的SBS應用于scikit-learn的KNN分類器的效果:

雖然SBS實現已經在fit
函數內將數據集劃分成測試數據集和訓練數據集,但是仍然將訓練數據集X_train
輸入到算法中。SBS的fit
方法將為測試(驗證)和訓練創建新子集,這就是為什么該測試數據集也被稱為驗證數據集。這也是一種避免原始測試數據集成為訓練數據的必要方法。
請記住,SBS算法收集每個階段最優特征子集的得分,下面進入代碼實現中更為精彩的部分,繪制出在驗證數據集上計算的KNN分類器的分類準確率。示例代碼如下:

從圖4-8可以看到,可能是由于維數降低(維數詛咒,在第3章中,我們在介紹KNN算法時曾經討論過),KNN分類器通過減少特征數提高了在驗證數據集上的準確率。此外,還可以看到當k={3,7,8,9,10,11,12}時,分類器的準確率達到100%。

圖 4-8
為了滿足好奇心,讓我們來看看在驗證數據集上產生如此良好性能的最小特征子集(k=3)究竟是個什么樣子:

用前面的代碼可以得到存儲在sbs.subsets_
屬性第11位的三個特征子集的列號,以及從pandas Wine DataFrame
的列索引返回的相應特征名。
我們接著評估該KNN分類器在原始測試數據集上的性能:

前面的代碼用完整的特征集在訓練數據集上取得了大約97%的準確率,在測試數據集上獲得大約96%的準確率,這表明模型已經可以很好地泛化到新數據集。現在用選定的三個特征子集來看一下KNN的性能:

如果采用葡萄酒數據集中少于四分之一的原始特征,測試數據集的預測準確率就會略有下降。這可能表明三個特征所提供的差異信息并不比原始數據集少。然而,我們必須記住葡萄酒數據集是一個小數據集,非常容易受隨機性的影響,即如何將數據集劃分成訓練數據集和測試數據集,以及如何進一步將訓練數據集劃分為訓練數據集和驗證數據集。
雖然減少特征數量并沒有提高KNN模型的性能,但是縮小了數據集的規模,在實際應用中可能會涉及昂貴的數據收集。此外,通過大量地減少特征的數量,我們可以得到更簡單的模型,這些模型也更加容易解釋。
用scikit-learn實現特征選擇算法
scikit-learn有許多其他的特征選擇算法,包括基于特征權重的遞歸后向消除法(recursive backward elimination)、基于樹的根據重要性選擇特征的方法以及單變量統計檢驗方法。對不同特征選擇方法的全面討論超出了本書的范圍,但是可以從網站http://scikit-learn.org/stable/modules/feature_selection.html找到優秀的總結與例證。
此外,我實現了幾種不同的序列特征選擇方法,這與前面實現的簡單SBS相關。可以從網站http://rasbt.github.io/mlxtend/user_guide/feature_selection/SequentialFeatureSelector/找到這些Python實現的mlxtend
軟件包。