如何进行特征选择?
? ?特征選擇(排序)對(duì)于數(shù)據(jù)科學(xué)家、機(jī)器學(xué)習(xí)從業(yè)者來(lái)說(shuō)非常重要。好的特征選擇能夠提升模型的性能,更能幫助我們理解數(shù)據(jù)的特點(diǎn)、底層結(jié)構(gòu),這對(duì)進(jìn)一步改善模型、算法都有著重要作用。
特征選擇主要有兩個(gè)功能:
? ?拿到數(shù)據(jù)集,一個(gè)特征選擇方法,往往很難同時(shí)完成這兩個(gè)目的。通常情況下,我們經(jīng)常不管三七二十一,選擇一種自己最熟悉或者最方便的特征選擇方法(往往目的是降維,而忽略了對(duì)特征和數(shù)據(jù)理解的目的)。
? ?在許多機(jī)器學(xué)習(xí)相關(guān)的書里,很難找到關(guān)于特征選擇的內(nèi)容,因?yàn)樘卣鬟x擇要解決的問題往往被視為機(jī)器學(xué)習(xí)的一種副作用,一般不會(huì)單獨(dú)拿出來(lái)討論。
本文將結(jié)合Scikit-learn提供的例子介紹幾種常用的特征選擇方法,它們各自的優(yōu)缺點(diǎn)和問題。
1、去掉取值變化小的特征 Removing features with low variance
? ?這應(yīng)該是最簡(jiǎn)單的特征選擇方法了:假設(shè)某特征的特征值只有0和1,并且在所有輸入樣本中,95%的實(shí)例的該特征取值都是1,那就可以認(rèn)為這個(gè)特征作用不大。如果100%都是1,那這個(gè)特征就沒意義了。當(dāng)特征值都是離散型變量的時(shí)候這種方法才能用,如果是連續(xù)型變量,就需要將連續(xù)變量離散化之后才能用,而且實(shí)際當(dāng)中,一般不太會(huì)有95%以上都取某個(gè)值的特征存在,所以這種方法雖然簡(jiǎn)單但是不太好用。可以把它作為特征選擇的預(yù)處理,先去掉那些取值變化小的特征,然后再?gòu)慕酉聛?lái)提到的的特征選擇方法中選擇合適的進(jìn)行進(jìn)一步的特征選擇。
2、單變量特征選擇 Univariate feature selection
? ?單變量特征選擇能夠?qū)γ恳粋€(gè)特征進(jìn)行測(cè)試,衡量該特征和響應(yīng)變量之間的關(guān)系,根據(jù)得分扔掉不好的特征。對(duì)于回歸和分類問題可以采用卡方檢驗(yàn)等方式對(duì)特征進(jìn)行測(cè)試。
? ?這種方法比較簡(jiǎn)單,易于運(yùn)行,易于理解,通常對(duì)于理解數(shù)據(jù)有較好的效果(但對(duì)特征優(yōu)化、提高泛化能力來(lái)說(shuō)不一定有效);這種方法有許多改進(jìn)的版本、變種。
2.1 Pearson相關(guān)系數(shù) Pearson Correlation
? ?皮爾森相關(guān)系數(shù)是一種最簡(jiǎn)單的,能幫助理解特征和響應(yīng)變量之間關(guān)系的方法,該方法衡量的是變量之間的線性相關(guān)性,結(jié)果的取值區(qū)間為[-1,1],-1表示完全的負(fù)相關(guān)(這個(gè)變量下降,那個(gè)就會(huì)上升),+1表示完全的正相關(guān),0表示沒有線性相關(guān)。
? ?Pearson Correlation速度快、易于計(jì)算,經(jīng)常在拿到數(shù)據(jù)(經(jīng)過(guò)清洗和特征提取之后的)之后第一時(shí)間就執(zhí)行。Scipy的pearsonr方法能夠同時(shí)計(jì)算相關(guān)系數(shù)和p-value,
import numpy as np from scipy.stats import pearsonr np.random.seed(0) size = 300 x = np.random.normal(0, 1, size) print "Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)) print "Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)) Lower noise (0.71824836862138386, 7.3240173129992273e-49)
Higher noise (0.057964292079338148, 0.31700993885324746)
? ?這個(gè)例子中,我們比較了變量在加入噪音之前和之后的差異。當(dāng)噪音比較小的時(shí)候,相關(guān)性很強(qiáng),p-value很低。
? ?Scikit-learn提供的f_regrssion方法能夠批量計(jì)算特征的p-value,非常方便,參考sklearn的pipeline
? ?Pearson相關(guān)系數(shù)的一個(gè)明顯缺陷是,作為特征排序機(jī)制,他只對(duì)線性關(guān)系敏感。如果關(guān)系是非線性的,即便兩個(gè)變量具有一一對(duì)應(yīng)的關(guān)系,Pearson相關(guān)性也可能會(huì)接近0。
x = np.random.uniform(-1, 1, 100000) print pearsonr(x, x**2)[0]-0.00230804707612
? ?更多類似的例子參考sample plots。另外,如果僅僅根據(jù)相關(guān)系數(shù)這個(gè)值來(lái)判斷的話,有時(shí)候會(huì)具有很強(qiáng)的誤導(dǎo)性,如Anscombe’s quartet,最好把數(shù)據(jù)可視化出來(lái),以免得出錯(cuò)誤的結(jié)論。
2.2 互信息和最大信息系數(shù) Mutual information and maximal information coefficient (MIC)
? ? ? ? 以上就是經(jīng)典的互信息公式了。想把互信息直接用于特征選擇其實(shí)不是太方便:1、它不屬于度量方式,也沒有辦法歸一化,在不同數(shù)據(jù)及上的結(jié)果無(wú)法做比較;2、對(duì)于連續(xù)變量的計(jì)算不是很方便(X和Y都是集合,x,y都是離散的取值),通常變量需要先離散化,而互信息的結(jié)果對(duì)離散化的方式很敏感。
? ?最大信息系數(shù)克服了這兩個(gè)問題。它首先尋找一種最優(yōu)的離散化方式,然后把互信息取值轉(zhuǎn)換成一種度量方式,取值區(qū)間在[0,1]。minepy提供了MIC功能。
反過(guò)頭來(lái)看y=x^2這個(gè)例子,MIC算出來(lái)的互信息值為1(最大的取值)。
from minepy import MINE m = MINE() x = np.random.uniform(-1, 1, 10000) m.compute_score(x, x**2) print m.mic()1.0
? ?MIC的統(tǒng)計(jì)能力遭到了一些質(zhì)疑,當(dāng)零假設(shè)不成立時(shí),MIC的統(tǒng)計(jì)就會(huì)受到影響。在有的數(shù)據(jù)集上不存在這個(gè)問題,但有的數(shù)據(jù)集上就存在這個(gè)問題。
2.3 距離相關(guān)系數(shù) (Distance correlation)
? ?距離相關(guān)系數(shù)是為了克服Pearson相關(guān)系數(shù)的弱點(diǎn)而生的。在x和x^2這個(gè)例子中,即便Pearson相關(guān)系數(shù)是0,我們也不能斷定這兩個(gè)變量是獨(dú)立的(有可能是非線性相關(guān));但如果距離相關(guān)系數(shù)是0,那么我們就可以說(shuō)這兩個(gè)變量是獨(dú)立的。
? ?R的energy包里提供了距離相關(guān)系數(shù)的實(shí)現(xiàn),另外這是Python gist的實(shí)現(xiàn)。
#R-code > x = runif (1000, -1, 1) > dcor(x, x**2) [1] 0.4943864? ?盡管有MIC和距離相關(guān)系數(shù)在了,但當(dāng)變量之間的關(guān)系接近線性相關(guān)的時(shí)候,Pearson相關(guān)系數(shù)仍然是不可替代的。第一、Pearson相關(guān)系數(shù)計(jì)算速度快,這在處理大規(guī)模數(shù)據(jù)的時(shí)候很重要。第二、Pearson相關(guān)系數(shù)的取值區(qū)間是[-1,1],而MIC和距離相關(guān)系數(shù)都是[0,1]。這個(gè)特點(diǎn)使得Pearson相關(guān)系數(shù)能夠表征更豐富的關(guān)系,符號(hào)表示關(guān)系的正負(fù),絕對(duì)值能夠表示強(qiáng)度。當(dāng)然,Pearson相關(guān)性有效的前提是兩個(gè)變量的變化關(guān)系是單調(diào)的。
2.4 基于學(xué)習(xí)模型的特征排序 (Model based ranking)
? ?這種方法的思路是直接使用你要用的機(jī)器學(xué)習(xí)算法,針對(duì)每個(gè)單獨(dú)的特征和響應(yīng)變量建立預(yù)測(cè)模型。其實(shí)Pearson相關(guān)系數(shù)等價(jià)于線性回歸里的標(biāo)準(zhǔn)化回歸系數(shù)。假如某個(gè)特征和響應(yīng)變量之間的關(guān)系是非線性的,可以用基于樹的方法(決策樹、隨機(jī)森林)、或者擴(kuò)展的線性模型等。基于樹的方法比較易于使用,因?yàn)樗麄儗?duì)非線性關(guān)系的建模比較好,并且不需要太多的調(diào)試。但要注意過(guò)擬合問題,因此樹的深度最好不要太大,再就是運(yùn)用交叉驗(yàn)證。
? ?在波士頓房?jī)r(jià)數(shù)據(jù)集上使用sklearn的隨機(jī)森林回歸給出一個(gè)單變量選擇的例子:
from sklearn.cross_validation import cross_val_score, ShuffleSplit from sklearn.datasets import load_boston from sklearn.ensemble import RandomForestRegressor#Load boston housing dataset as an example boston = load_boston() X = boston["data"] Y = boston["target"] names = boston["feature_names"]rf = RandomForestRegressor(n_estimators=20, max_depth=4) scores = [] for i in range(X.shape[1]):score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2",cv=ShuffleSplit(len(X), 3, .3))scores.append((round(np.mean(score), 3), names[i])) print sorted(scores, reverse=True)[(0.636, 'LSTAT'), (0.59, 'RM'), (0.472, 'NOX'), (0.369, 'INDUS'), (0.311, 'PTRATIO'), (0.24, 'TAX'), (0.24, 'CRIM'), (0.185, 'RAD'), (0.16, 'ZN'), (0.087, 'B'), (0.062, 'DIS'), (0.036, 'CHAS'), (0.027, 'AGE')]
3 線性模型和正則化
? ?單變量特征選擇方法獨(dú)立的衡量每個(gè)特征與響應(yīng)變量之間的關(guān)系,另一種主流的特征選擇方法是基于機(jī)器學(xué)習(xí)模型的方法。有些機(jī)器學(xué)習(xí)方法本身就具有對(duì)特征進(jìn)行打分的機(jī)制,或者很容易將其運(yùn)用到特征選擇任務(wù)中,例如回歸模型,SVM,決策樹,隨機(jī)森林等等。說(shuō)句題外話,這種方法好像在一些地方叫做wrapper類型,大概意思是說(shuō),特征排序模型和機(jī)器學(xué)習(xí)模型是耦盒在一起的,對(duì)應(yīng)的非wrapper類型的特征選擇方法叫做filter類型。
? ?下面將介紹如何用回歸模型的系數(shù)來(lái)選擇特征。越是重要的特征在模型中對(duì)應(yīng)的系數(shù)就會(huì)越大,而跟輸出變量越是無(wú)關(guān)的特征對(duì)應(yīng)的系數(shù)就會(huì)越接近于0。在噪音不多的數(shù)據(jù)上,或者是數(shù)據(jù)量遠(yuǎn)遠(yuǎn)大于特征數(shù)的數(shù)據(jù)上,如果特征之間相對(duì)來(lái)說(shuō)是比較獨(dú)立的,那么即便是運(yùn)用最簡(jiǎn)單的線性回歸模型也一樣能取得非常好的效果。
from sklearn.linear_model import LinearRegression import numpy as npnp.random.seed(0) size = 5000#A dataset with 3 features X = np.random.normal(0, 1, (size, 3)) #Y = X0 + 2*X1 + noise Y = X[:,0] + 2*X[:,1] + np.random.normal(0, 2, size) lr = LinearRegression() lr.fit(X, Y)#A helper method for pretty-printing linear models def pretty_print_linear(coefs, names = None, sort = False):if names == None:names = ["X%s" % x for x in range(len(coefs))]lst = zip(coefs, names)if sort:lst = sorted(lst, key = lambda x:-np.abs(x[0]))return " + ".join("%s * %s" % (round(coef, 3), name)for coef, name in lst)print "Linear model:", pretty_print_linear(lr.coef_)Linear model: 0.984 * X0 + 1.995 * X1 + -0.041 * X2
? ?在這個(gè)例子當(dāng)中,盡管數(shù)據(jù)中存在一些噪音,但這種特征選擇模型仍然能夠很好的體現(xiàn)出數(shù)據(jù)的底層結(jié)構(gòu)。當(dāng)然這也是因?yàn)槔又械倪@個(gè)問題非常適合用線性模型來(lái)解:特征和響應(yīng)變量之間全都是線性關(guān)系,并且特征之間均是獨(dú)立的。
? ?在很多實(shí)際的數(shù)據(jù)當(dāng)中,往往存在多個(gè)互相關(guān)聯(lián)的特征,這時(shí)候模型就會(huì)變得不穩(wěn)定,數(shù)據(jù)中細(xì)微的變化就可能導(dǎo)致模型的巨大變化(模型的變化本質(zhì)上是系數(shù),或者叫參數(shù),可以理解成W),這會(huì)讓模型的預(yù)測(cè)變得困難,這種現(xiàn)象也稱為多重共線性。例如,假設(shè)我們有個(gè)數(shù)據(jù)集,它的真實(shí)模型應(yīng)該是Y=X1+X2,當(dāng)我們觀察的時(shí)候,發(fā)現(xiàn)Y'=X1+X2+e,e是噪音。如果X1和X2之間存在線性關(guān)系,例如X1約等于X2,這個(gè)時(shí)候由于噪音e的存在,我們學(xué)到的模型可能就不是Y=X1+X2了,有可能是Y=2X1,或者Y=-X1+3X2。
? ?下邊這個(gè)例子當(dāng)中,在同一個(gè)數(shù)據(jù)上加入了一些噪音,用隨機(jī)森林算法進(jìn)行特征選擇。
from sklearn.linear_model import LinearRegressionsize = 100 np.random.seed(seed=5)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]).Tlr = LinearRegression() lr.fit(X,Y) print "Linear model:", pretty_print_linear(lr.coef_)Linear model: -1.291 * X0 + 1.591 * X1 + 2.747 * X2
? ?系數(shù)之和接近3,基本上和上上個(gè)例子的結(jié)果一致,應(yīng)該說(shuō)學(xué)到的模型對(duì)于預(yù)測(cè)來(lái)說(shuō)還是不錯(cuò)的。但是,如果從系數(shù)的字面意思上去解釋特征的重要性的話,X3對(duì)于輸出變量來(lái)說(shuō)具有很強(qiáng)的正面影響,而X1具有負(fù)面影響,而實(shí)際上所有特征與輸出變量之間的影響是均等的。
? ?同樣的方法和套路可以用到類似的線性模型上,比如邏輯回歸。
3.1 正則化模型
? ?正則化就是把額外的約束或者懲罰項(xiàng)加到已有模型(損失函數(shù))上,以防止過(guò)擬合并提高泛化能力。損失函數(shù)由原來(lái)的E(X,Y)變?yōu)镋(X,Y)+alpha||w||,w是模型系數(shù)組成的向量(有些地方也叫參數(shù)parameter,coefficients),||·||一般是L1或者L2范數(shù),alpha是一個(gè)可調(diào)的參數(shù),控制著正則化的強(qiáng)度。當(dāng)用在線性模型上時(shí),L1正則化和L2正則化也稱為L(zhǎng)asso和Ridge。
3.2 L1正則化/Lasso
? ?L1正則化將系數(shù)w的l1范數(shù)作為懲罰項(xiàng)加到損失函數(shù)上,由于正則項(xiàng)非零,這就迫使那些弱的特征所對(duì)應(yīng)的系數(shù)變成0。因此L1正則化往往會(huì)使學(xué)到的模型很稀疏(系數(shù)w經(jīng)常為0),這個(gè)特性使得L1正則化成為一種很好的特征選擇方法。
Scikit-learn為線性回歸提供了Lasso,為分類提供了L1邏輯回歸。
下面的例子在波士頓房?jī)r(jià)數(shù)據(jù)上運(yùn)行了Lasso,其中參數(shù)alpha是通過(guò)grid search進(jìn)行優(yōu)化的。
from sklearn.linear_model import Lasso from sklearn.preprocessing import StandardScaler from sklearn.datasets import load_bostonboston = load_boston() scaler = StandardScaler() X = scaler.fit_transform(boston["data"]) Y = boston["target"] names = boston["feature_names"]lasso = Lasso(alpha=.3) lasso.fit(X, Y)print "Lasso model: ", pretty_print_linear(lasso.coef_, names, sort = True)Lasso model: -3.707 * LSTAT + 2.992 * RM + -1.757 * PTRATIO + -1.081 * DIS + -0.7 * NOX + 0.631 * B + 0.54 * CHAS + -0.236 * CRIM + 0.081 * ZN + -0.0 * INDUS + -0.0 * AGE + 0.0 * RAD + -0.0 * TAX
? ?可以看到,很多特征的系數(shù)都是0。如果繼續(xù)增加alpha的值,得到的模型就會(huì)越來(lái)越稀疏,即越來(lái)越多的特征系數(shù)會(huì)變成0。
然而,L1正則化像非正則化線性模型一樣也是不穩(wěn)定的,如果特征集合中具有相關(guān)聯(lián)的特征,當(dāng)數(shù)據(jù)發(fā)生細(xì)微變化時(shí)也有可能導(dǎo)致很大的模型差異。
3.3 L2正則化/Ridge regression
? ?L2正則化將系數(shù)向量的L2范數(shù)添加到了損失函數(shù)中。由于L2懲罰項(xiàng)中系數(shù)是二次方的,這使得L2和L1有著諸多差異,最明顯的一點(diǎn)就是,L2正則化會(huì)讓系數(shù)的取值變得平均。對(duì)于關(guān)聯(lián)特征,這意味著他們能夠獲得更相近的對(duì)應(yīng)系數(shù)。還是以Y=X1+X2為例,假設(shè)X1和X2具有很強(qiáng)的關(guān)聯(lián),如果用L1正則化,不論學(xué)到的模型是Y=X1+X2還是Y=2X1,懲罰都是一樣的,都是2alpha。但是對(duì)于L2來(lái)說(shuō),第一個(gè)模型的懲罰項(xiàng)是2alpha,但第二個(gè)模型的是4*alpha??梢钥闯?#xff0c;系數(shù)之和為常數(shù)時(shí),各系數(shù)相等時(shí)懲罰是最小的,所以才有了L2會(huì)讓各個(gè)系數(shù)趨于相同的特點(diǎn)。
? ?可以看出,L2正則化對(duì)于特征選擇來(lái)說(shuō)一種穩(wěn)定的模型,不像L1正則化那樣,系數(shù)會(huì)因?yàn)榧?xì)微的數(shù)據(jù)變化而波動(dòng)。所以L2正則化和L1正則化提供的價(jià)值是不同的,L2正則化對(duì)于特征理解來(lái)說(shuō)更加有用:表示能力強(qiáng)的特征對(duì)應(yīng)的系數(shù)是非零。
? ?回過(guò)頭來(lái)看看3個(gè)互相關(guān)聯(lián)的特征的例子,分別以10個(gè)不同的種子隨機(jī)初始化運(yùn)行10次,來(lái)觀察L1和L2正則化的穩(wěn)定性。
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" % inp.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]).Tlr = LinearRegression()lr.fit(X,Y)print "Linear model:", pretty_print_linear(lr.coef_)ridge = Ridge(alpha=10)ridge.fit(X,Y)print "Ridge model:", pretty_print_linear(ridge.coef_)printRandom seed 0 Linear model: 0.728 * X0 + 2.309 * X1 + -0.082 * X2 Ridge model: 0.938 * X0 + 1.059 * X1 + 0.877 * X2
Random seed 1 Linear model: 1.152 * X0 + 2.366 * X1 + -0.599 * X2 Ridge model: 0.984 * X0 + 1.068 * X1 + 0.759 * X2
Random seed 2 Linear model: 0.697 * X0 + 0.322 * X1 + 2.086 * X2 Ridge model: 0.972 * X0 + 0.943 * X1 + 1.085 * X2
Random seed 3 Linear model: 0.287 * X0 + 1.254 * X1 + 1.491 * X2 Ridge model: 0.919 * X0 + 1.005 * X1 + 1.033 * X2
Random seed 4 Linear model: 0.187 * X0 + 0.772 * X1 + 2.189 * X2 Ridge model: 0.964 * X0 + 0.982 * X1 + 1.098 * X2
Random seed 5 Linear model: -1.291 * X0 + 1.591 * X1 + 2.747 * X2 Ridge model: 0.758 * X0 + 1.011 * X1 + 1.139 * X2
Random seed 6 Linear model: 1.199 * X0 + -0.031 * X1 + 1.915 * X2 Ridge model: 1.016 * X0 + 0.89 * X1 + 1.091 * X2
Random seed 7 Linear model: 1.474 * X0 + 1.762 * X1 + -0.151 * X2 Ridge model: 1.018 * X0 + 1.039 * X1 + 0.901 * X2
Random seed 8 Linear model: 0.084 * X0 + 1.88 * X1 + 1.107 * X2 Ridge model: 0.907 * X0 + 1.071 * X1 + 1.008 * X2
Random seed 9 Linear model: 0.714 * X0 + 0.776 * X1 + 1.364 * X2 Ridge model: 0.896 * X0 + 0.903 * X1 + 0.98 * X2
? ?可以看出,不同的數(shù)據(jù)上線性回歸得到的模型(系數(shù))相差甚遠(yuǎn),但對(duì)于L2正則化模型來(lái)說(shuō),結(jié)果中的系數(shù)非常的穩(wěn)定,差別較小,都比較接近于1,能夠反映出數(shù)據(jù)的內(nèi)在結(jié)構(gòu)。
4 隨機(jī)森林
? ?隨機(jī)森林具有準(zhǔn)確率高、魯棒性好、易于使用等優(yōu)點(diǎn),這使得它成為了目前最流行的機(jī)器學(xué)習(xí)算法之一。隨機(jī)森林提供了兩種特征選擇的方法:mean decrease impurity和mean decrease accuracy。
4.1 平均不純度減少 mean decrease impurity
? ?隨機(jī)森林由多個(gè)決策樹構(gòu)成。決策樹中的每一個(gè)節(jié)點(diǎn)都是關(guān)于某個(gè)特征的條件,為的是將數(shù)據(jù)集按照不同的響應(yīng)變量一分為二。利用不純度可以確定節(jié)點(diǎn)(最優(yōu)條件),對(duì)于分類問題,通常采用基尼不純度或者信息增益,對(duì)于回歸問題,通常采用的是方差或者最小二乘擬合。當(dāng)訓(xùn)練決策樹的時(shí)候,可以計(jì)算出每個(gè)特征減少了多少樹的不純度。對(duì)于一個(gè)決策樹森林來(lái)說(shuō),可以算出每個(gè)特征平均減少了多少不純度,并把它平均減少的不純度作為特征選擇的值。
下邊的例子是sklearn中基于隨機(jī)森林的特征重要度度量方法:
from sklearn.datasets import load_boston from sklearn.ensemble import RandomForestRegressor import numpy as np #Load boston housing dataset as an example boston = load_boston() X = boston["data"] Y = boston["target"] names = boston["feature_names"] rf = RandomForestRegressor() rf.fit(X, Y) print "Features sorted by their score:" print sorted(zip(map(lambda x: round(x, 4), rf.feature_importances_), names), reverse=True)Features sorted by their score: [(0.5298, 'LSTAT'), (0.4116, 'RM'), (0.0252, 'DIS'), (0.0172, 'CRIM'), (0.0065, 'NOX'), (0.0035, 'PTRATIO'), (0.0021, 'TAX'), (0.0017, 'AGE'), (0.0012, 'B'), (0.0008, 'INDUS'), (0.0004, 'RAD'), (0.0001, 'CHAS'), (0.0, 'ZN')]
? ?這里特征得分實(shí)際上采用的是Gini Importance。使用基于不純度的方法的時(shí)候,要記住:1、這種方法存在偏向,對(duì)具有更多類別的變量會(huì)更有利;2、對(duì)于存在關(guān)聯(lián)的多個(gè)特征,其中任意一個(gè)都可以作為指示器(優(yōu)秀的特征),并且一旦某個(gè)特征被選擇之后,其他特征的重要度就會(huì)急劇下降,因?yàn)椴患兌纫呀?jīng)被選中的那個(gè)特征降下來(lái)了,其他的特征就很難再降低那么多不純度了,這樣一來(lái),只有先被選中的那個(gè)特征重要度很高,其他的關(guān)聯(lián)特征重要度往往較低。在理解數(shù)據(jù)時(shí),這就會(huì)造成誤解,導(dǎo)致錯(cuò)誤的認(rèn)為先被選中的特征是很重要的,而其余的特征是不重要的,但實(shí)際上這些特征對(duì)響應(yīng)變量的作用確實(shí)非常接近的(這跟Lasso是很像的)。
? ?特征隨機(jī)選擇方法稍微緩解了這個(gè)問題,但總的來(lái)說(shuō)并沒有完全解決。下面的例子中,X0、X1、X2是三個(gè)互相關(guān)聯(lián)的變量,在沒有噪音的情況下,輸出變量是三者之和。
size = 10000 np.random.seed(seed=10) X_seed = np.random.normal(0, 1, size) X0 = 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) X = np.array([X0, X1, X2]).T Y = X0 + X1 + X2rf = RandomForestRegressor(n_estimators=20, max_features=2) rf.fit(X, Y); print "Scores for X0, X1, X2:", map(lambda x:round (x,3),rf.feature_importances_)Scores for X0, X1, X2: [0.278, 0.66, 0.062]
? ?當(dāng)計(jì)算特征重要性時(shí),可以看到X1的重要度比X2的重要度要高出10倍,但實(shí)際上他們真正的重要度是一樣的。盡管數(shù)據(jù)量已經(jīng)很大且沒有噪音,且用了20棵樹來(lái)做隨機(jī)選擇,但這個(gè)問題還是會(huì)存在。
? ?需要注意的一點(diǎn)是,關(guān)聯(lián)特征的打分存在不穩(wěn)定的現(xiàn)象,這不僅僅是隨機(jī)森林特有的,大多數(shù)基于模型的特征選擇方法都存在這個(gè)問題。
4.2 平均精確率減少 Mean decrease accuracy
? ?另一種常用的特征選擇方法就是直接度量每個(gè)特征對(duì)模型精確率的影響。主要思路是打亂每個(gè)特征的特征值順序,并且度量順序變動(dòng)對(duì)模型的精確率的影響。很明顯,對(duì)于不重要的變量來(lái)說(shuō),打亂順序?qū)δP偷木_率影響不會(huì)太大,但是對(duì)于重要的變量來(lái)說(shuō),打亂順序就會(huì)降低模型的精確率。
? ?這個(gè)方法sklearn中沒有直接提供,但是很容易實(shí)現(xiàn),下面繼續(xù)在波士頓房?jī)r(jià)數(shù)據(jù)集上進(jìn)行實(shí)現(xiàn)。
from sklearn.cross_validation import ShuffleSplit from sklearn.metrics import r2_score from collections import defaultdictX = 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) forfeat, score in scores.items()], reverse=True)Features sorted by their score: [(0.7276, 'LSTAT'), (0.5675, 'RM'), (0.0867, 'DIS'), (0.0407, 'NOX'), (0.0351, 'CRIM'), (0.0233, 'PTRATIO'), (0.0168, 'TAX'), (0.0122, 'AGE'), (0.005, 'B'), (0.0048, 'INDUS'), (0.0043, 'RAD'), (0.0004, 'ZN'), (0.0001, 'CHAS')]
? ?在這個(gè)例子當(dāng)中,LSTAT和RM這兩個(gè)特征對(duì)模型的性能有著很大的影響,打亂這兩個(gè)特征的特征值使得模型的性能下降了73%和57%。注意,盡管這些我們是在所有特征上進(jìn)行了訓(xùn)練得到了模型,然后才得到了每個(gè)特征的重要性測(cè)試,這并不意味著我們?nèi)拥裟硞€(gè)或者某些重要特征后模型的性能就一定會(huì)下降很多,因?yàn)榧幢隳硞€(gè)特征刪掉之后,其關(guān)聯(lián)特征一樣可以發(fā)揮作用,讓模型性能基本上不變。
5 兩種頂層特征選擇算法
? ?之所以叫做頂層,是因?yàn)樗麄兌际墙⒃诨谀P偷奶卣鬟x擇方法基礎(chǔ)之上的,例如回歸和SVM,在不同的子集上建立模型,然后匯總最終確定特征得分。
5.1 穩(wěn)定性選擇 Stability selection
? ?穩(wěn)定性選擇是一種基于二次抽樣和選擇算法相結(jié)合較新的方法,選擇算法可以是回歸、SVM或其他類似的方法。它的主要思想是在不同的數(shù)據(jù)子集和特征子集上運(yùn)行特征選擇算法,不斷的重復(fù),最終匯總特征選擇結(jié)果,比如可以統(tǒng)計(jì)某個(gè)特征被認(rèn)為是重要特征的頻率(被選為重要特征的次數(shù)除以它所在的子集被測(cè)試的次數(shù))。理想情況下,重要特征的得分會(huì)接近100%。稍微弱一點(diǎn)的特征得分會(huì)是非0的數(shù),而最無(wú)用的特征得分將會(huì)接近于0。
? ?sklearn在隨機(jī)lasso和隨機(jī)邏輯回歸中有對(duì)穩(wěn)定性選擇的實(shí)現(xiàn)。
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)Features sorted by their score: [(1.0, 'RM'), (1.0, 'PTRATIO'), (1.0, 'LSTAT'), (0.62, 'CHAS'), (0.595, 'B'), (0.39, 'TAX'), (0.385, 'CRIM'), (0.25, 'DIS'), (0.22, 'NOX'), (0.125, 'INDUS'), (0.045, 'ZN'), (0.02, 'RAD'), (0.015, 'AGE')]
? ?在上邊這個(gè)例子當(dāng)中,最高的3個(gè)特征得分是1.0,這表示他們總會(huì)被選作有用的特征(當(dāng)然,得分會(huì)收到正則化參數(shù)alpha的影響,但是sklearn的隨機(jī)lasso能夠自動(dòng)選擇最優(yōu)的alpha)。接下來(lái)的幾個(gè)特征得分就開始下降,但是下降的不是特別急劇,這跟純lasso的方法和隨機(jī)森林的結(jié)果不一樣。能夠看出穩(wěn)定性選擇對(duì)于克服過(guò)擬合和對(duì)數(shù)據(jù)理解來(lái)說(shuō)都是有幫助的:總的來(lái)說(shuō),好的特征不會(huì)因?yàn)橛邢嗨频奶卣?、關(guān)聯(lián)特征而得分為0,這跟Lasso是不同的。對(duì)于特征選擇任務(wù),在許多數(shù)據(jù)集和環(huán)境下,穩(wěn)定性選擇往往是性能最好的方法之一。
5.2 遞歸特征消除 Recursive feature elimination (RFE)
? ?遞歸特征消除的主要思想是反復(fù)的構(gòu)建模型(如SVM或者回歸模型)然后選出最好的(或者最差的)的特征(可以根據(jù)系數(shù)來(lái)選),把選出來(lái)的特征放到一遍,然后在剩余的特征上重復(fù)這個(gè)過(guò)程,直到所有特征都遍歷了。這個(gè)過(guò)程中特征被消除的次序就是特征的排序。因此,這是一種尋找最優(yōu)特征子集的貪心算法。
? ?RFE的穩(wěn)定性很大程度上取決于在迭代的時(shí)候底層用哪種模型。例如,假如RFE采用的普通的回歸,沒有經(jīng)過(guò)正則化的回歸是不穩(wěn)定的,那么RFE就是不穩(wěn)定的;假如采用的是Ridge,而用Ridge正則化的回歸是穩(wěn)定的,那么RFE就是穩(wěn)定的。
? ?Sklearn提供了RFE包,可以用于特征消除,還提供了RFECV,可以通過(guò)交叉驗(yàn)證來(lái)對(duì)的特征進(jìn)行排序。
from sklearn.feature_selection import RFE from sklearn.linear_model import LinearRegressionboston = 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))Features sorted by their rank: [(1.0, 'NOX'), (2.0, 'RM'), (3.0, 'CHAS'), (4.0, 'PTRATIO'), (5.0, 'DIS'), (6.0, 'LSTAT'), (7.0, 'RAD'), (8.0, 'CRIM'), (9.0, 'INDUS'), (10.0, 'ZN'), (11.0, 'TAX'), (12.0, 'B'), (13.0, 'AGE')]
6 一個(gè)完整的例子
? ?下面將本文所有提到的方法進(jìn)行實(shí)驗(yàn)對(duì)比,數(shù)據(jù)集采用Friedman #1 回歸數(shù)據(jù)(這篇論文中的數(shù)據(jù))。數(shù)據(jù)是用這個(gè)公式產(chǎn)生的:
? ? ? ? X1到X5是由單變量分布生成的,e是標(biāo)準(zhǔn)正態(tài)變量N(0,1)。另外,原始的數(shù)據(jù)集中含有5個(gè)噪音變量 X5,...,X10,跟響應(yīng)變量是獨(dú)立的。我們?cè)黾恿?個(gè)額外的變量X11,...X14,分別是X1,...,X4的關(guān)聯(lián)變量,通過(guò)f(x)=x+N(0,0.01)生成,這將產(chǎn)生大于0.999的關(guān)聯(lián)系數(shù)。這樣生成的數(shù)據(jù)能夠體現(xiàn)出不同的特征排序方法應(yīng)對(duì)關(guān)聯(lián)特征時(shí)的表現(xiàn)。? ?接下來(lái)將會(huì)在上述數(shù)據(jù)上運(yùn)行所有的特征選擇方法,并且將每種方法給出的得分進(jìn)行歸一化,讓取值都落在0-1之間。對(duì)于RFE來(lái)說(shuō),由于它給出的是順序而不是得分,我們將最好的5個(gè)的得分定為1,其他的特征的得分均勻的分布在0-1之間。
from sklearn.datasets import load_boston from sklearn.linear_model import (LinearRegression, Ridge, Lasso, RandomizedLasso) from sklearn.feature_selection import RFE, f_regression from sklearn.preprocessing import MinMaxScaler from sklearn.ensemble import RandomForestRegressor import numpy as np from minepy import MINEnp.random.seed(0)size = 750 X = np.random.uniform(0, 1, (size, 14))#"Friedamn #1” regression problem Y = (10 * np.sin(np.pi*X[:,0]*X[:,1]) + 20*(X[:,2] - .5)**2 +10*X[:,3] + 5*X[:,4] + np.random.normal(0,1)) #Add 3 additional correlated variables (correlated with X1-X3) X[:,10:] = X[:,:4] + np.random.normal(0, .025, (size,4))names = ["x%s" % i for i in range(1,15)]ranks = {}def rank_to_dict(ranks, names, order=1):minmax = MinMaxScaler()ranks = minmax.fit_transform(order*np.array([ranks]).T).T[0]ranks = map(lambda x: round(x, 2), ranks)return dict(zip(names, ranks ))lr = LinearRegression(normalize=True) lr.fit(X, Y) ranks["Linear reg"] = rank_to_dict(np.abs(lr.coef_), names)ridge = Ridge(alpha=7) ridge.fit(X, Y) ranks["Ridge"] = rank_to_dict(np.abs(ridge.coef_), names)lasso = Lasso(alpha=.05) lasso.fit(X, Y) ranks["Lasso"] = rank_to_dict(np.abs(lasso.coef_), names)rlasso = RandomizedLasso(alpha=0.04) rlasso.fit(X, Y) ranks["Stability"] = rank_to_dict(np.abs(rlasso.scores_), names)#stop the search when 5 features are left (they will get equal scores) rfe = RFE(lr, n_features_to_select=5) rfe.fit(X,Y) ranks["RFE"] = rank_to_dict(map(float, rfe.ranking_), names, order=-1)rf = RandomForestRegressor() rf.fit(X,Y) ranks["RF"] = rank_to_dict(rf.feature_importances_, names)f, pval = f_regression(X, Y, center=True) ranks["Corr."] = rank_to_dict(f, names)mine = MINE() mic_scores = [] for i in range(X.shape[1]):mine.compute_score(X[:,i], Y)m = mine.mic()mic_scores.append(m)ranks["MIC"] = rank_to_dict(mic_scores, names)r = {} for name in names:r[name] = round(np.mean([ranks[method][name] for method in ranks.keys()]), 2)methods = sorted(ranks.keys()) ranks["Mean"] = r methods.append("Mean")print "\t%s" % "\t".join(methods) for name in names:print "%s\t%s" % (name, "\t".join(map(str, [ranks[method][name] for method in methods])))從以上結(jié)果中可以找到一些有趣的發(fā)現(xiàn):
? ?特征之間存在線性關(guān)聯(lián)關(guān)系,每個(gè)特征都是獨(dú)立評(píng)價(jià)的,因此X1,...X4的得分和X11,...X14的得分非常接近,而噪音特征X5,...,X10正如預(yù)期的那樣和響應(yīng)變量之間幾乎沒有關(guān)系。由于變量X3是二次的,因此X3和響應(yīng)變量之間看不出有關(guān)系(除了MIC之外,其他方法都找不到關(guān)系)。這種方法能夠衡量出特征和響應(yīng)變量之間的線性關(guān)系,但若想選出優(yōu)質(zhì)特征來(lái)提升模型的泛化能力,這種方法就不是特別給力了,因?yàn)樗械膬?yōu)質(zhì)特征都不可避免的會(huì)被挑出來(lái)兩次。
? ?Lasso能夠挑出一些優(yōu)質(zhì)特征,同時(shí)讓其他特征的系數(shù)趨于0。當(dāng)如需要減少特征數(shù)的時(shí)候它很有用,但是對(duì)于數(shù)據(jù)理解來(lái)說(shuō)不是很好用。(例如在結(jié)果表中,X11,X12,X13的得分都是0,好像他們跟輸出變量之間沒有很強(qiáng)的聯(lián)系,但實(shí)際上不是這樣的)
? ?MIC對(duì)特征一視同仁,這一點(diǎn)上和關(guān)聯(lián)系數(shù)有點(diǎn)像,另外,它能夠找出X3和響應(yīng)變量之間的非線性關(guān)系。
? ?隨機(jī)森林基于不純度的排序結(jié)果非常鮮明,在得分最高的幾個(gè)特征之后的特征,得分急劇的下降。從表中可以看到,得分第三的特征比第一的小4倍。而其他的特征選擇算法就沒有下降的這么劇烈。
? ?Ridge將回歸系數(shù)均勻的分?jǐn)偟礁鱾€(gè)關(guān)聯(lián)變量上,從表中可以看出,X11,...,X14和X1,...,X4的得分非常接近。
? ?穩(wěn)定性選擇常常是一種既能夠有助于理解數(shù)據(jù)又能夠挑出優(yōu)質(zhì)特征的這種選擇,在結(jié)果表中就能很好的看出。像Lasso一樣,它能找到那些性能比較好的特征(X1,X2,X4,X5),同時(shí),與這些特征關(guān)聯(lián)度很強(qiáng)的變量也得到了較高的得分。
總結(jié)
Tips
? ?什么是卡方檢驗(yàn)?用方差來(lái)衡量某個(gè)觀測(cè)頻率和理論頻率之間差異性的方法
? ?什么是皮爾森卡方檢驗(yàn)?這是一種最常用的卡方檢驗(yàn)方法,它有兩個(gè)用途:1是計(jì)算某個(gè)變量對(duì)某種分布的擬合程度,2是根據(jù)兩個(gè)觀測(cè)變量的Contingency table來(lái)計(jì)算這兩個(gè)變量是否是獨(dú)立的。主要有三個(gè)步驟:第一步用方差和的方式來(lái)計(jì)算觀測(cè)頻率和理論頻率之間卡方值;第二步算出卡方檢驗(yàn)的自由度(行數(shù)-1乘以列數(shù)-1);第三步比較卡方值和對(duì)應(yīng)自由度的卡方分布,判斷顯著性。
? ?什么是p-value?簡(jiǎn)單地說(shuō),p-value就是為了驗(yàn)證假設(shè)和實(shí)際之間一致性的統(tǒng)計(jì)學(xué)意義的值,即假設(shè)檢驗(yàn)。有些地方叫右尾概率,根據(jù)卡方值和自由度可以算出一個(gè)固定的p-value,
? ?什么是響應(yīng)變量(response value)?簡(jiǎn)單地說(shuō),模型的輸入叫做explanatroy variables,模型的輸出叫做response variables,其實(shí)就是要驗(yàn)證該特征對(duì)結(jié)果造成了什么樣的影響
? ?什么是統(tǒng)計(jì)能力(statistical power)?
? ?什么是度量(metric)?
? ?什么是零假設(shè)(null hypothesis)?在相關(guān)性檢驗(yàn)中,一般會(huì)取“兩者之間無(wú)關(guān)聯(lián)”作為零假設(shè),而在獨(dú)立性檢驗(yàn)中,一般會(huì)取“兩者之間是獨(dú)立”作為零假設(shè)。與零假設(shè)相對(duì)的是備擇假設(shè)(對(duì)立假設(shè)),即希望證明是正確的另一種可能。
? ?什么是多重共線性?
? ?什么是grid search?
That's it
References
總結(jié)
- 上一篇: Delphi对话框初始地址Initial
- 下一篇: java小基础之instanceof运算