特征選取是機器學習領域非常重要的一個方向。
主要有兩個功能:
(1)減少特征數量、降維,使模型泛化能力更強,減少過擬合
(2)增強度特征和特征值之間的理解
幾種常用的特征選取方法
一、去掉取值變化小的特征
考察某個特征下,樣本的方差值,可以人為給定一個閾值,拋開那些小於這個閾值的特征。
二、單變量特征選擇
單變量特征選擇的出發點是計算某一特征和分類變量之間的關系,以此計算每一特征的得分,拋開那些排名靠后的特征。比較經典的方法是卡方檢驗。
(1)peason相關系數,缺點:只對線性相關系數敏感
(2)距離相關系數
比較: 第一、Pearson相關系數計算速度快,這在處理大規模數據的時候很重要。第二、Pearson相關系數的取值區間是[-1,1],距離相關系數都是[0,1]。這個特點使得Pearson相關系數能夠表征更豐富的關系,符號表示關系的正負,絕對值能夠表示強度。當然,Pearson相關性有效的前提是兩個變量的變化關系是單調的。
(3)基於學習模型的特征排序
這種方法的思路是直接使用你要用的機器學習算法,針對每個單獨的特征和響應變量建立預測模型
Pearson相關系數等價於線性回歸里的標准化回歸系數
三、線性模型和正則化
單變量特征選擇方法獨立的衡量每個特征與響應變量之間的關系,另一種主流的特征選擇方法是基於機器學習模型的方法。可以對特征打分叫做wrapper類型,不能打分的稱為filter類型。
多重共線性:多個互相關聯的特征,這時候模型就會變得不穩定,數據中細微的變化就可能導致模型的巨大變化(模型的變化本質上是系數,或者叫參數,可以理解成W),這會讓模型的預測變得困難。???
(1)正則化模型
正則化就是把額外的約束或者懲罰項加到已有模型(損失函數)上,以防止過擬合並提高泛化能力
L1正則化:
L2正則化:
L2正則化將系數向量的L2范數添加到了損失函數中。由於L2懲罰項中系數是二次方的,這使得L2和L1有着諸多差異,最明顯的一點就是,L2正則化會讓系數的取值變得平均。對於關聯特征,這意味着他們能夠獲得更相近的對應系數。還是以Y=X1+X2為例,假設X1和X2具有很強的關聯,如果用L1正則化,不論學到的模型是Y=X1+X2還是Y=2X1,懲罰都是一樣的,都是2alpha。但是對於L2來說,第一個模型的懲罰項是2alpha,但第二個模型的是4*alpha。可以看出,系數之和為常數時,各系數相等時懲罰是最小的,所以才有了L2會讓各個系數趨於相同的特點。
可以看出,L2正則化對於特征選擇來說一種穩定的模型,不像L1正則化那樣,系數會因為細微的數據變化而波動。所以L2正則化和L1正則化提供的價值是不同的,L2正則化對於特征理解來說更加有用:表示能力強的特征對應的系數是非零。
from sklearn.linear_model import Ridge from sklearn.metrics import r2_score size = 100 #We run the method 10 times with different random seeds for i in range(10): print "Random seed %s" % i np.random.seed(seed=i) X_seed = np.random.normal(0, 1, size) X1 = X_seed + np.random.normal(0, .1, size) X2 = X_seed + np.random.normal(0, .1, size) X3 = X_seed + np.random.normal(0, .1, size) Y = X1 + X2 + X3 + np.random.normal(0, 1, size) X = np.array([X1, X2, X3]).T lr = LinearRegression() lr.fit(X,Y) print "Linear model:", pretty_print_linear(lr.coef_)
四、隨機森林
隨機森林具有准確率高、魯棒性好、易於使用等優點,這使得它成為了目前最流行的機器學習算法之一。隨機森林提供了兩種特征選擇的方法:mean decrease impurity和mean decrease accuracy。
(1)平均不純度減少
這里特征得分實際上采用的是Gini Importance。使用基於不純度的方法的時候,要記住:1、這種方法存在偏向,對具有更多類別的變量會更有利;2、對於存在關聯的多個特征,其中任意一個都可以作為指示器(優秀的特征),並且一旦某個特征被選擇之后,其他特征的重要度就會急劇下降,因為不純度已經被選中的那個特征降下來了,其他的特征就很難再降低那么多不純度了,這樣一來,只有先被選中的那個特征重要度很高,其他的關聯特征重要度往往較低。在理解數據時,這就會造成誤解,導致錯誤的認為先被選中的特征是很重要的,而其余的特征是不重要的,但實際上這些特征對響應變量的作用確實非常接近的(這跟Lasso是很像的)。
需要注意的一點是,關聯特征的打分存在不穩定的現象,這不僅僅是隨機森林特有的,大多數基於模型的特征選擇方法都存在這個問題。
(2)平均精確率減少
另一種常用的特征選擇方法就是直接度量每個特征對模型精確率的影響。主要思路是打亂每個特征的特征值順序,並且度量順序變動對模型的精確率的影響。很明顯,對於不重要的變量來說,打亂順序對模型的精確率影響不會太大,但是對於重要的變量來說,打亂順序就會降低模型的精確率。
from sklearn.cross_validation import ShuffleSplit from sklearn.metrics import r2_score from collections import defaultdict X = boston["data"] Y = boston["target"] rf = RandomForestRegressor() scores = defaultdict(list) #crossvalidate the scores on a number of different random splits of the data for train_idx, test_idx in ShuffleSplit(len(X), 100, .3): X_train, X_test = X[train_idx], X[test_idx] Y_train, Y_test = Y[train_idx], Y[test_idx] r = rf.fit(X_train, Y_train) acc = r2_score(Y_test, rf.predict(X_test)) for i in range(X.shape[1]): X_t = X_test.copy() np.random.shuffle(X_t[:, i]) shuff_acc = r2_score(Y_test, rf.predict(X_t)) scores[names[i]].append((acc-shuff_acc)/acc) print "Features sorted by their score:" print sorted([(round(np.mean(score), 4), feat) for feat, score in scores.items()], reverse=True)
五、兩種頂層特征算法特征選擇
(1)穩定性選擇
穩定性選擇是一種基於二次抽樣和選擇算法相結合較新的方法,選擇算法可以是回歸、SVM或其他類似的方法。它的主要思想是在不同的數據子集和特征子集上運行特征選擇算法,不斷的重復,最終匯總特征選擇結果,比如可以統計某個特征被認為是重要特征的頻率(被選為重要特征的次數除以它所在的子集被測試的次數)
from sklearn.linear_model import RandomizedLasso from sklearn.datasets import load_boston boston = load_boston() #using the Boston housing data. #Data gets scaled automatically by sklearn's implementation X = boston["data"] Y = boston["target"] names = boston["feature_names"] rlasso = RandomizedLasso(alpha=0.025) rlasso.fit(X, Y) print "Features sorted by their score:" print sorted(zip(map(lambda x: round(x, 4), rlasso.scores_), names), reverse=True)
(2)遞歸特征消除
遞歸特征消除的主要思想是反復的構建模型(如SVM或者回歸模型)然后選出最好的(或者最差的)的特征(可以根據系數來選),把選出來的特征放到一遍,然后在剩余的特征上重復這個過程,直到所有特征都遍歷了。這個過程中特征被消除的次序就是特征的排序。因此,這是一種尋找最優特征子集的貪心算法。
from sklearn.feature_selection import RFE from sklearn.linear_model import LinearRegression boston = load_boston() X = boston["data"] Y = boston["target"] names = boston["feature_names"] #use linear regression as the model lr = LinearRegression() #rank all features, i.e continue the elimination until the last one rfe = RFE(lr, n_features_to_select=1) rfe.fit(X,Y) print "Features sorted by their rank:" print sorted(zip(map(lambda x: round(x, 4), rfe.ranking_), names))
總結:
(1)對於理解數據、數據的結構、特點來說,單變量特征選擇是個非常好的選擇。盡管可以用它對特征進行排序來優化模型,但由於它不能發現冗余(例如假如一個特征子集,其中的特征之間具有很強的關聯,那么從中選擇最優的特征時就很難考慮到冗余的問題)。
(2)正則化的線性模型對於特征理解和特征選擇來說是非常強大的工具。L1正則化能夠生成稀疏的模型,對於選擇特征子集來說非常有用;相比起L1正則化,L2正則化的表現更加穩定,由於有用的特征往往對應系數非零,因此L2正則化對於數據的理解來說很合適。由於響應變量和特征之間往往是非線性關系,可以采用basis expansion的方式將特征轉換到一個更加合適的空間當中,在此基礎上再考慮運用簡單的線性模型。
(3)隨機森林是一種非常流行的特征選擇方法,它易於使用,一般不需要feature engineering、調參等繁瑣的步驟,並且很多工具包都提供了平均不純度下降方法。它的兩個主要問題,1是重要的特征有可能得分很低(關聯特征問題),2是這種方法對特征變量類別多的特征越有利(偏向問題)。盡管如此,這種方法仍然非常值得在你的應用中試一試。
(4)特征選擇在很多機器學習和數據挖掘場景中都是非常有用的。在使用的時候要弄清楚自己的目標是什么,然后找到哪種方法適用於自己的任務。當選擇最優特征以提升模型性能的時候,可以采用交叉驗證的方法來驗證某種方法是否比其他方法要好。當用特征選擇的方法來理解數據的時候要留心,特征選擇模型的穩定性非常重要,穩定性差的模型很容易就會導致錯誤的結論。對數據進行二次采樣然后在子集上運行特征選擇算法能夠有所幫助,如果在各個子集上的結果是一致的,那就可以說在這個數據集上得出來的結論是可信的,可以用這種特征選擇模型的結果來理解數據。