數(shù)據(jù)維度爆炸怎么辦?詳解5大常用的特征選擇方法
每日干貨?&?每月組隊(duì)學(xué)習(xí),不錯(cuò)過
作者:Edwin Jarvis,cnblog博客整理
在許多機(jī)器學(xué)習(xí)相關(guān)的書里,很難找到關(guān)于特征選擇的內(nèi)容,因?yàn)樘卣鬟x擇要解決的問題往往被視為機(jī)器學(xué)習(xí)的一個(gè)子模塊,一般不會(huì)單獨(dú)拿出來討論。
減少特征數(shù)量、降維,使模型泛化能力更強(qiáng),減少過擬合
增強(qiáng)對(duì)特征和特征值之間的理解
好的特征選擇能夠提升模型的性能,更能幫助我們理解數(shù)據(jù)的特點(diǎn)、底層結(jié)構(gòu),這對(duì)進(jìn)一步改善模型、算法都有著重要作用。
本文將結(jié)合Scikit-learn提供的例子介紹幾種常用的特征選擇方法,它們各自的優(yōu)缺點(diǎn)和問題。本文目錄如下:

一、去掉取值變化小的特征?
英文:Removing features with low variance
二、單變量特征選擇?
英文: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)化、提高泛化能力來說不一定有效);這種方法有許多改進(jìn)的版本、變種。
2.1 Pearson相關(guān)系數(shù)?
英文:Pearson Correlation
Pearson Correlation速度快、易于計(jì)算,經(jīng)常在拿到數(shù)據(jù)(經(jīng)過清洗和特征提取之后的)之后第一時(shí)間就執(zhí)行。Scipy的pearsonr方法能夠同時(shí)計(jì)算相關(guān)系數(shù)和p-value,
import numpy as npfrom scipy.stats import pearsonrnp.random.seed(0)size = 300x = 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))

這個(gè)例子中,我們比較了變量在加入噪音之前和之后的差異。當(dāng)噪音比較小的時(shí)候,相關(guān)性很強(qiáng),p-value很低。
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è)值來判斷的話,有時(shí)候會(huì)具有很強(qiáng)的誤導(dǎo)性,如Anscombe’s quartet,最好把數(shù)據(jù)可視化出來,以免得出錯(cuò)誤的結(jié)論。
2.2 互信息和最大信息系數(shù)?
英文:Mutual information and maximal information coefficient (MIC)
以上就是經(jīng)典的互信息公式了。想把互信息直接用于特征選擇其實(shí)不是太方便:1、它不屬于度量方式,也沒有辦法歸一化,在不同數(shù)據(jù)及上的結(jié)果無法做比較;2、對(duì)于連續(xù)變量的計(jì)算不是很方便(X和Y都是集合,x,y都是離散的取值),通常變量需要先離散化,而互信息的結(jié)果對(duì)離散化的方式很敏感。
最大信息系數(shù)克服了這兩個(gè)問題。它首先尋找一種最優(yōu)的離散化方式,然后把互信息取值轉(zhuǎn)換成一種度量方式,取值區(qū)間在[0,1]。minepy提供了MIC功能。
反過頭來看y=x^2這個(gè)例子,MIC算出來的互信息值為1(最大的取值)。
from minepy import MINEm = MINE()x = np.random.uniform(-1, 1, 10000)m.compute_score(x, x**2)print m.mic()
1.0
2.3 距離相關(guān)系數(shù)?
英文:Distance correlation
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ī)r(jià)數(shù)據(jù)集上使用sklearn的隨機(jī)森林回歸給出一個(gè)單變量選擇的例子:
from sklearn.cross_validation import cross_val_score, ShuffleSplitfrom sklearn.datasets import load_bostonfrom sklearn.ensemble import RandomForestRegressor#Load boston housing dataset as an exampleboston = 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)

三、線性模型和正則化
單變量特征選擇方法獨(dú)立的衡量每個(gè)特征與響應(yīng)變量之間的關(guān)系,另一種主流的特征選擇方法是基于機(jī)器學(xué)習(xí)模型的方法。有些機(jī)器學(xué)習(xí)方法本身就具有對(duì)特征進(jìn)行打分的機(jī)制,或者很容易將其運(yùn)用到特征選擇任務(wù)中,例如回歸模型,SVM,決策樹,隨機(jī)森林等等。說句題外話,這種方法好像在一些地方叫做wrapper類型,大概意思是說,特征排序模型和機(jī)器學(xué)習(xí)模型是耦盒在一起的,對(duì)應(yīng)的非wrapper類型的特征選擇方法叫做filter類型。
下面將介紹如何用回歸模型的系數(shù)來選擇特征。越是重要的特征在模型中對(duì)應(yīng)的系數(shù)就會(huì)越大,而跟輸出變量越是無關(guān)的特征對(duì)應(yīng)的系數(shù)就會(huì)越接近于0。在噪音不多的數(shù)據(jù)上,或者是數(shù)據(jù)量遠(yuǎn)遠(yuǎn)大于特征數(shù)的數(shù)據(jù)上,如果特征之間相對(duì)來說是比較獨(dú)立的,那么即便是運(yùn)用最簡(jiǎn)單的線性回歸模型也一樣能取得非常好的效果。
from sklearn.linear_model import LinearRegressionimport numpy as npnp.random.seed(0)size = 5000#A dataset with 3 featuresX = np.random.normal(0, 1, (size, 3))#Y = X0 + 2*X1 + noiseY = X[:,0] + 2*X[:,1] + np.random.normal(0, 2, size)lr = LinearRegression()lr.fit(X, Y)#A helper method for pretty-printing linear modelsdef 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_

下邊這個(gè)例子當(dāng)中,在同一個(gè)數(shù)據(jù)上加入了一些噪音,用隨機(jī)森林算法進(jìn)行特征選擇。
from sklearn.linear_model import LinearRegressionsize = 100np.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_)

同樣的方法和套路可以用到類似的線性模型上,比如邏輯回歸。
3.1 正則化模型
正則化就是把額外的約束或者懲罰項(xiàng)加到已有模型(損失函數(shù))上,以防止過擬合并提高泛化能力。損失函數(shù)由原來的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
下面的例子在波士頓房?jī)r(jià)數(shù)據(jù)上運(yùn)行了Lasso,其中參數(shù)alpha是通過grid search進(jìn)行優(yōu)化的。
from sklearn.linear_model import Lassofrom sklearn.preprocessing import StandardScalerfrom 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)

然而,L1正則化像非正則化線性模型一樣也是不穩(wěn)定的,如果特征集合中具有相關(guān)聯(lián)的特征,當(dāng)數(shù)據(jù)發(fā)生細(xì)微變化時(shí)也有可能導(dǎo)致很大的模型差異。
3.3 L2正則化/Ridge regression
回過頭來看看3個(gè)互相關(guān)聯(lián)的特征的例子,分別以10個(gè)不同的種子隨機(jī)初始化運(yùn)行10次,來觀察L1和L2正則化的穩(wěn)
from sklearn.linear_model import Ridgefrom sklearn.metrics import r2_scoresize = 100#We run the method 10 times with different random seedsfor 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_)

可以看出,不同的數(shù)據(jù)上線性回歸得到的模型(系數(shù))相差甚遠(yuǎn),但對(duì)于L2正則化模型來說,結(jié)果中的系數(shù)非常的穩(wěn)定,差別較小,都比較接近于1,能夠反映出數(shù)據(jù)的內(nèi)在結(jié)構(gòu)。
隨機(jī)森林具有準(zhǔn)確率高、魯棒性好、易于使用等優(yōu)點(diǎn),這使得它成為了目前最流行的機(jī)器學(xué)習(xí)算法之一。隨機(jī)森林提供了兩種特征選擇的方法:mean decrease impurity和mean decrease accuracy。
4.1 平均不純度減少?
英文:mean decrease impurity
下邊的例子是sklearn中基于隨機(jī)森林的特征重要度度量方法:
from sklearn.datasets import load_bostonfrom sklearn.ensemble import RandomForestRegressorimport numpy as np#Load boston housing dataset as an exampleboston = 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)

特征隨機(jī)選擇方法稍微緩解了這個(gè)問題,但總的來說并沒有完全解決。下面的例子中,X0、X1、X2是三個(gè)互相關(guān)聯(lián)的變量,在沒有噪音的情況下,輸出變量是三者之和。
size = 10000np.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]).TY = 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_)

需要注意的一點(diǎn)是,關(guān)聯(lián)特征的打分存在不穩(wěn)定的現(xiàn)象,這不僅僅是隨機(jī)森林特有的,大多數(shù)基于模型的特征選擇方法都存在這個(gè)問題。
4.2 平均精確率減少?
英文:Mean decrease accuracy
這個(gè)方法sklearn中沒有直接提供,但是很容易實(shí)現(xiàn),下面繼續(xù)在波士頓房?jī)r(jià)數(shù)據(jù)集上進(jìn)行實(shí)現(xiàn)。
from sklearn.cross_validation import ShuffleSplitfrom sklearn.metrics import r2_scorefrom 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 datafor 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)

在這個(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ā)揮作用,讓模型性能基本上不變。
五、兩種頂層特征選擇算法
之所以叫做頂層,是因?yàn)樗麄兌际墙⒃诨谀P偷奶卣鬟x擇方法基礎(chǔ)之上的,例如回歸和SVM,在不同的子集上建立模型,然后匯總最終確定特征得分。
5.1 穩(wěn)定性選擇
sklearn在隨機(jī)lasso和隨機(jī)邏輯回歸中有對(duì)穩(wěn)定性選擇的實(shí)現(xiàn)。
from sklearn.linear_model import RandomizedLassofrom sklearn.datasets import load_bostonboston = load_boston()#using the Boston housing data.#Data gets scaled automatically by sklearn's implementationX = 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)

在上邊這個(gè)例子當(dāng)中,最高的3個(gè)特征得分是1.0,這表示他們總會(huì)被選作有用的特征(當(dāng)然,得分會(huì)收到正則化參數(shù)alpha的影響,但是sklearn的隨機(jī)lasso能夠自動(dòng)選擇最優(yōu)的alpha)。接下來的幾個(gè)特征得分就開始下降,但是下降的不是特別急劇,這跟純lasso的方法和隨機(jī)森林的結(jié)果不一樣。能夠看出穩(wěn)定性選擇對(duì)于克服過擬合和對(duì)數(shù)據(jù)理解來說都是有幫助的:總的來說,好的特征不會(huì)因?yàn)橛邢嗨频奶卣?、關(guān)聯(lián)特征而得分為0,這跟Lasso是不同的。對(duì)于特征選擇任務(wù),在許多數(shù)據(jù)集和環(huán)境下,穩(wěn)定性選擇往往是性能最好的方法之一。
5.2 遞歸特征消除
Sklearn提供了RFE包,可以用于特征消除,還提供了RFECV,可以通過交叉驗(yàn)證來對(duì)的特征進(jìn)行排序。
from sklearn.feature_selection import RFEfrom sklearn.linear_model import LinearRegressionboston = load_boston()X = boston["data"]Y = boston["target"]names = boston["feature_names"]#use linear regression as the modellr = LinearRegression()#rank all features, i.e continue the elimination until the last onerfe = 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))

六、一個(gè)完整的例子

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)變量,通過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)。
接下來將會(huì)在上述數(shù)據(jù)上運(yùn)行所有的特征選擇方法,并且將每種方法給出的得分進(jìn)行歸一化,讓取值都落在0-1之間。對(duì)于RFE來說,由于它給出的是順序而不是得分,我們將最好的5個(gè)的得分定為1,其他的特征的得分均勻的分布在0-1之間。
from sklearn.datasets import load_bostonfrom sklearn.linear_model import (LinearRegression, Ridge,Lasso, RandomizedLasso)from sklearn.feature_selection import RFE, f_regressionfrom sklearn.preprocessing import MinMaxScalerfrom sklearn.ensemble import RandomForestRegressorimport numpy as npfrom minepy import MINEnp.random.seed(0)size = 750X = np.random.uniform(0, 1, (size, 14))#"Friedamn #1” regression problemY = (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"] = rmethods.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):
Lasso能夠挑出一些優(yōu)質(zhì)特征,同時(shí)讓其他特征的系數(shù)趨于0。當(dāng)如需要減少特征數(shù)的時(shí)候它很有用,但是對(duì)于數(shù)據(jù)理解來說不是很好用。(例如在結(jié)果表中,X11,X12,X13的得分都是0,好像他們跟輸出變量之間沒有很強(qiáng)的聯(lián)系,但實(shí)際上不是這樣的)
穩(wěn)定性選擇常常是一種既能夠有助于理解數(shù)據(jù)又能夠挑出優(yōu)質(zhì)特征的這種選擇,在結(jié)果表中就能很好的看出。像Lasso一樣,它能找到那些性能比較好的特征(X1,X2,X4,X5),同時(shí),與這些特征關(guān)聯(lián)度很強(qiáng)的變量也得到了較高的得分。
七、總結(jié)
特征選擇在很多機(jī)器學(xué)習(xí)和數(shù)據(jù)挖掘場(chǎng)景中都是非常有用的。在使用的時(shí)候要弄清楚自己的目標(biāo)是什么,然后找到哪種方法適用于自己的任務(wù)。當(dāng)選擇最優(yōu)特征以提升模型性能的時(shí)候,可以采用交叉驗(yàn)證的方法來驗(yàn)證某種方法是否比其他方法要好。當(dāng)用特征選擇的方法來理解數(shù)據(jù)的時(shí)候要留心,特征選擇模型的穩(wěn)定性非常重要,穩(wěn)定性差的模型很容易就會(huì)導(dǎo)致錯(cuò)誤的結(jié)論。對(duì)數(shù)據(jù)進(jìn)行二次采樣然后在子集上運(yùn)行特征選擇算法能夠有所幫助,如果在各個(gè)子集上的結(jié)果是一致的,那就可以說在這個(gè)數(shù)據(jù)集上得出來的結(jié)論是可信的,可以用這種特征選擇模型的結(jié)果來理解數(shù)據(jù)。
來源:https://www.cnblogs.com/hhh5460/p/5186226.html
“整理不易,點(diǎn)贊三連↓

