這是我github以前總結(jié)的一篇基于屬性選擇的notebook心傀,結(jié)合了網(wǎng)上的一些代碼,做了一些解釋性注釋
1. 去掉取值變化小的特征
這應(yīng)該是最簡(jiǎn)單的特征選擇方法了:假設(shè)某特征的特征值只有0和1,并且在所有輸入樣本中匾乓, 95%的實(shí)例的該特征取值都是1懒震,那就可以認(rèn)為這個(gè)特征作用不大。如果100%都是1岂贩, 那這個(gè)特征就沒(méi)意義了茫经。當(dāng)特征值都是離散型變量的時(shí)候這種方法才能用, 如果是連續(xù)型變量萎津,就需要將連續(xù)變量離散化之后才能用卸伞,而且實(shí)際當(dāng)中, 一般不太會(huì)有95%以上都取某個(gè)值的特征存在锉屈,所以這種方法雖然簡(jiǎn)單但是不太好用荤傲。 可以把它作為特征選擇的預(yù)處理,先去掉那些取值變化小的特征颈渊, 然后再?gòu)慕酉聛?lái)提到的的特征選擇方法中選擇合適的進(jìn)行進(jìn)一步的特征選擇遂黍。
還可以使用標(biāo)準(zhǔn)差來(lái)判斷特征,如果標(biāo)準(zhǔn)差在0左右徘徊則可以將該屬性丟棄
2. 單變量特征選擇
單變量特征選擇能夠?qū)γ恳粋€(gè)特征進(jìn)行測(cè)試俊嗽,衡量該特征和響應(yīng)變量之間的關(guān)系雾家,根據(jù)得分扔掉不好的特征。 對(duì)于回歸和分類(lèi)問(wèn)題可以采用卡方檢驗(yàn)等方式對(duì)特征進(jìn)行測(cè)試乌询。
這種方法比較簡(jiǎn)單榜贴,易于運(yùn)行,易于理解妹田,通常對(duì)于理解數(shù)據(jù)有較好的效果 (但對(duì)特征優(yōu)化唬党、提高泛化能力來(lái)說(shuō)不一定有效);這種方法有許多改進(jìn)的版本鬼佣、變種驶拱。
2.1Pearson相關(guān)系數(shù)(線性相關(guān))
皮爾森相關(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表示沒(méi)有線性相關(guān)箭养。
import numpy as np
from scipy.stats import pearsonr
np.random.seed(0) # 保證每次隨機(jī)取值一樣
size = 300
x = np.random.normal(0, 1, size)
print('皮爾遜相關(guān)系數(shù)和顯著性分別為:')
print( "Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print( "Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))
###########################################################################
皮爾遜相關(guān)系數(shù)和顯著性分別為:
Lower noise (0.71824836862138408, 7.3240173129983507e-49)
Higher noise (0.057964292079338155, 0.31700993885324752)
說(shuō)明皮爾遜相關(guān)系數(shù)簡(jiǎn)稱(chēng)r值,顯著性簡(jiǎn)稱(chēng)p值
首先看顯著性值哥牍,也就是sig值或稱(chēng)p值毕泌。
它是判斷r值喝检,也即相關(guān)系數(shù)有沒(méi)有統(tǒng)計(jì)學(xué)意義的。
判定標(biāo)準(zhǔn)一般為0.05撼泛。
高噪聲時(shí):
由表可知挠说,兩變量之間的相關(guān)性系數(shù)r=0.057964292079338155,
其p值為0.31700993885324752>0.05,所以相關(guān)性系數(shù)沒(méi)有統(tǒng)計(jì)學(xué)意義愿题。
無(wú)論r值大小损俭,都表明兩者之間沒(méi)有相關(guān)性。
如果p值<0.05抠忘,那么就表明兩者之間有相關(guān)性撩炊。
然后再看r值,|r|值越大崎脉,相關(guān)性越好拧咳,正數(shù)指正相關(guān),負(fù)數(shù)指負(fù)相關(guān)囚灼。
一般認(rèn)為:
|r|大于等于0.8時(shí)為兩變量間高度相關(guān)骆膝;
|r|大于等于0.5小于0.8時(shí)認(rèn)為兩變量中度相關(guān);
|r|大于等于0.3小于0.5時(shí)認(rèn)為兩變量低度相關(guān)或弱相關(guān)灶体,
|r|小于0.3說(shuō)明相關(guān)程度為極弱相關(guān)或無(wú)相關(guān)阅签。
所以判斷相關(guān)性,先看p值蝎抽,看有沒(méi)有相關(guān)性政钟。
再看r值,看相關(guān)性是強(qiáng)還是弱樟结。
r 值判斷標(biāo)準(zhǔn)
0.8-1.0 極強(qiáng)相關(guān)
0.6-0.8 強(qiáng)相關(guān)
0.4-0.6 中等程度相關(guān)
0.2-0.4 弱相關(guān)
0.0-0.2 極弱相關(guān)或無(wú)相關(guān)
x = np.random.uniform(-1, 1, 100000)
print( pearsonr(x, x**2))
##########################################################
(-0.0023080470761233087, 0.46547550833628804)
請(qǐng)看上面例子,x與x的平方是非線性關(guān)系养交,而且是極強(qiáng)相關(guān),但是皮爾遜相關(guān)系數(shù)很低
注意:Pearson相關(guān)系數(shù)的一個(gè)明顯缺陷是瓢宦,作為特征排序機(jī)制碎连,
他只對(duì)線性關(guān)系敏感。如果關(guān)系是非線性的驮履,即便兩個(gè)變量具有一一對(duì)應(yīng)的關(guān)系鱼辙,
Pearson相關(guān)性也可能會(huì)接近0。
2.2 互信息和最大信息系數(shù)MI MIC
以上就是經(jīng)典的互信息公式了玫镐。想把互信息直接用于特征選擇其實(shí)不是太方便,
MI其實(shí)是一個(gè)聚類(lèi)的評(píng)分指標(biāo):
1倒戏、它不屬于度量方式,也沒(méi)有辦法歸一化恐似,在不同數(shù)據(jù)及上的結(jié)果無(wú)法做比較杜跷;
2、對(duì)于連續(xù)變量的計(jì)算不是很方便(X和Y都是集合,x葱椭,y都是離散的取值),
通常變量需要先離散化口四,而互信息的結(jié)果對(duì)離散化的方式很敏感孵运。
BUT :
MIC最大信息系數(shù)克服了這兩個(gè)問(wèn)題(也就是你可以直接使用連續(xù)變量,不歸一化)蔓彩。
它首先尋找一種最優(yōu)的離散化方式治笨,然后把互信息取值轉(zhuǎn)換成一種度量方式,
取值區(qū)間在[0赤嚼,1]旷赖。minepy提供了MIC功能。
from minepy import MINE
m = MINE()
x = np.random.uniform(-1, 1, 10000)
m.compute_score(x, x**2)
print('最大最大信息系數(shù)MIC為: %.2f' % float(m.mic()))
###################################################################
最大最大信息系數(shù)MIC為: 1.00
??看到了嗎更卒,就算是非線性也可以的得到正確值
注意: MIC的統(tǒng)計(jì)能力遭到了一些質(zhì)疑等孵,當(dāng)零假設(shè)不成立時(shí)(即統(tǒng)計(jì)檢驗(yàn)時(shí)預(yù)先建立的假設(shè)不成立時(shí)),
MIC的統(tǒng)計(jì)就會(huì)受到影響蹂空。
在有的數(shù)據(jù)集上不存在這個(gè)問(wèn)題俯萌,但有的數(shù)據(jù)集上就存在這個(gè)問(wèn)題。
2.3 距離相關(guān)系數(shù)
距離相關(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ú)立的。
這里沒(méi)有python包锈玉,直接github源碼
# 地址https://www.snip2code.com/Snippet/1545497/Computes-the-distance-correlation-betwee
# 我自己改了一下輸入
"""Computes the distance correlation between two matrices.
https://en.wikipedia.org/wiki/Distance_correlation
"""
import numpy as np
from scipy.spatial.distance import pdist, squareform
__author__ = "Kailash Budhathoki"
__email__ = "kbudhath@mpi-inf.mpg.de"
__copyright__ = "Copyright (c) 2016"
__license__ = "MIT"
def dcov(X, Y):
"""Computes the distance covariance between matrices X and Y.
"""
n = X.shape[0]
XY = np.multiply(X, Y)
cov = np.sqrt(XY.sum()) / n
return cov
def dvar(X):
"""Computes the distance variance of a matrix X.
"""
return np.sqrt(np.sum(X ** 2 / X.shape[0] ** 2))
def cent_dist(X):
"""Computes the pairwise euclidean distance between rows of X and centers
each cell of the distance matrix with row mean, column mean, and grand mean.
"""
M = squareform(pdist(X)) # distance matrix
rmean = M.mean(axis=1)
cmean = M.mean(axis=0)
gmean = rmean.mean()
R = np.tile(rmean, (M.shape[0], 1)).transpose()
C = np.tile(cmean, (M.shape[1], 1))
G = np.tile(gmean, M.shape)
CM = M - R - C + G
return CM
# 主函數(shù)dcor
def dcor(X, Y):
"""Computes the distance correlation between two matrices X and Y.
X and Y must have the same number of rows.
>>> X = np.matrix('1;2;3;4;5')
>>> Y = np.matrix('1;2;9;4;4')
>>> dcor(X, Y)
0.76267624241686649
"""
X = np.matrix(np.array(X)).T
Y = np.matrix(np.array(Y)).T
assert X.shape[0] == Y.shape[0]
A = cent_dist(X)
B = cent_dist(Y)
dcov_AB = dcov(A, B)
dvar_A = dvar(A)
dvar_B = dvar(B)
dcor = 0.0
if dvar_A > 0.0 and dvar_B > 0.0:
dcor = dcov_AB / np.sqrt(dvar_A * dvar_B)
return dcor
a = [1,2,3,4,5]
b = [1,2,9,4,4]
print('距離系數(shù)是: %.2f'% dcor(a, b))
#####################################################################
距離系數(shù)是: 0.76
盡管有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í)模型的特征排序
這種方法的思路是直接使用你要用的機(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)系是非線性的泼诱,
可以用基于樹(shù)的方法(決策樹(shù)、隨機(jī)森林)赊锚、或者擴(kuò)展的線性模型等治筒。基于樹(shù)的方法比較易于使用舷蒲,
因?yàn)樗麄儗?duì)非線性關(guān)系的建模比較好耸袜,并且不需要太多的調(diào)試。
但要注意過(guò)擬合問(wèn)題牲平,因此樹(shù)的深度最好不要太大堤框,再就是運(yùn)用交叉驗(yàn)證。
注意: 樹(shù)模型天生就可以用來(lái)做模型選擇(分支節(jié)點(diǎn))
# 為了直觀展示纵柿,
from sklearn.model_selection import cross_val_score, ShuffleSplit
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
import pandas as pd
#加載數(shù)據(jù)
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
data = pd.DataFrame(X, columns=names)
data['target'] = Y
print('讓我們看看數(shù)據(jù)形狀,前幾列為屬性胰锌,最后一列target為類(lèi)標(biāo)簽')
data.head(10)
rf = RandomForestRegressor(n_estimators=20, max_depth=4)
scores = []
# 將每個(gè)屬性得分計(jì)算出來(lái)(交叉驗(yàn)證可參考cv:http://blog.csdn.net/not_guy/article/details/77652850)
for i in range(data.shape[1]-1):
score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2",
cv=ShuffleSplit(len(data), 3, .3))
scores.append((round(np.mean(score), 3), data.columns[i]))
scores = sorted(scores, reverse=True)
print('屬性得分分別為:')
for each in scores:
print(each[1]+' 的得分為: '+str(each[0]) )
################################################################
屬性得分分別為:
RM 的得分為: 0.643
LSTAT 的得分為: 0.636
NOX 的得分為: 0.42
PTRATIO 的得分為: 0.372
TAX 的得分為: 0.323
INDUS 的得分為: 0.32
ZN 的得分為: 0.189
RAD 的得分為: 0.166
CRIM 的得分為: 0.156
B 的得分為: 0.141
CHAS 的得分為: 0.033
AGE 的得分為: 0.015
DIS 的得分為: -0.072
3 線性模型和正則化
單變量特征選擇方法獨(dú)立的衡量每個(gè)特征與響應(yīng)變量之間的關(guān)系,另一種主流的特征選擇方法是基于機(jī)器學(xué)習(xí)模型的方法藐窄。
有些機(jī)器學(xué)習(xí)方法本身就具有對(duì)特征進(jìn)行打分的機(jī)制资昧,或者很容易將其運(yùn)用到特征選擇任務(wù)中,例如回歸模型荆忍,SVM格带,決策樹(shù),隨機(jī)森林等等刹枉。
說(shuō)句題外話叽唱,這種方法好像在一些地方叫做wrapper類(lèi)型,大概意思是說(shuō)微宝,特征排序模型和機(jī)器學(xué)習(xí)模型耦合在一起的棺亭,對(duì)應(yīng)的非wrapper類(lèi)型的特征選擇方法叫做filter類(lèi)型。
下面將介紹如何用回歸模型的系數(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)單的線性回歸模型也一樣能取得非常好的效果湿痢。
# 邏輯回歸擬合函數(shù)
from sklearn.linear_model import LinearRegression
import numpy as np
np.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)
#輔助函數(shù)幫助輸出系數(shù)
def pretty_print_linear(coefs, names = None, sort = False):
"""
:param coefs: 系數(shù)列表
:param names: 屬性名
:param sort: 是否按重要度降序排列
:return:
"""
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('生成X維度為3涝缝,Y = X0 + 2*X1 + noise')
print ("線性函數(shù)擬合結(jié)果為:", pretty_print_linear(lr.coef_))
print('可以看出Y對(duì)X0,X1相關(guān)性更大, X基本沒(méi)有相關(guān)')
##################################################################
生成X維度為3,Y = X0 + 2*X1 + noise
線性函數(shù)擬合結(jié)果為: 0.984 * X0 + 1.995 * X1 + -0.041 * X2
可以看出Y對(duì)X0,X1相關(guān)性更大, X基本沒(méi)有相關(guān)
在這個(gè)例子當(dāng)中,盡管數(shù)據(jù)中存在一些噪音拒逮,但這種特征選擇模型仍然能夠很好的體現(xiàn)出數(shù)據(jù)的底層結(jié)構(gòu)罐氨。
當(dāng)然這也是因?yàn)槔又械倪@個(gè)問(wèn)題非常適合用線性模型來(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)象也稱(chēng)為多重共線性.
例如,假設(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屈藐。
from sklearn.linear_model import LinearRegression
size = 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]).T
lr = LinearRegression()
lr.fit(X,Y)
print('真是的函數(shù)為:X0+X1+X2+noise') print ("線性函數(shù)擬合結(jié)果為:", pretty_printlinear(lr.coef))
系數(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í)際上所有特征與輸出變量之間的影響是均等的铅歼。
同樣的方法和套路可以用到類(lèi)似的線性模型上公壤,比如邏輯回歸。
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正則化也稱(chēng)為L(zhǎng)asso和Ridge。原理可見(jiàn)
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正則化成為一種很好的特征選擇方法医增。
L1范數(shù)是指向量中各個(gè)元素絕對(duì)值之和,也有個(gè)美稱(chēng)叫“稀疏規(guī)則算子”(Lasso regularization)老虫。
現(xiàn)在我們來(lái)分析下這個(gè)價(jià)值一個(gè)億的問(wèn)題:為什么L1范數(shù)會(huì)使權(quán)值稀疏叶骨?
有人可能會(huì)這樣給你回答“它是L0范數(shù)的最優(yōu)凸近似”。實(shí)際上祈匙,
還存在一個(gè)更美的回答:任何的規(guī)則化算子忽刽,如果他在Wi=0的地方不可微,并且可以分解為一個(gè)“求和”的形式夺欲,那么這個(gè)規(guī)則化算子就可以實(shí)現(xiàn)稀疏跪帝。
來(lái)個(gè)一句話總結(jié):L1范數(shù)和L0范數(shù)可以實(shí)現(xiàn)稀疏,L1因具有比L0更好的優(yōu)化求解特性而被廣泛應(yīng)用些阅。
參數(shù)稀疏有什么好處呢伞剑?這里扯兩點(diǎn):
1)特征選擇(Feature Selection):
大家對(duì)稀疏規(guī)則化趨之若鶩的一個(gè)關(guān)鍵原因在于它能實(shí)現(xiàn)特征的自動(dòng)選擇。一般來(lái)說(shuō)市埋,xi的大部分元素(也就是特征)
都是和最終的輸出yi沒(méi)有關(guān)系或者不提供任何信息的纸泄,在最小化目標(biāo)函數(shù)的時(shí)候考慮xi這些額外的特征,雖然可以獲得更小的訓(xùn)練誤差腰素,
但在預(yù)測(cè)新的樣本時(shí)聘裁,這些沒(méi)用的信息反而會(huì)被考慮,從而干擾了對(duì)正確yi的預(yù)測(cè)弓千。稀疏規(guī)則化算子的引入就是為了完成特征自動(dòng)選擇的光榮使命衡便,
它會(huì)學(xué)習(xí)地去掉這些沒(méi)有信息的特征,也就是把這些特征對(duì)應(yīng)的權(quán)重置為0洋访。
2)可解釋性(Interpretability):
另一個(gè)青睞于稀疏的理由是镣陕,模型更容易解釋。例如患某種病的概率是y姻政,然后我們收集到的數(shù)據(jù)x是1000維的呆抑,
也就是我們需要尋找這1000種因素到底是怎么影響患上這種病的概率的。假設(shè)我們這個(gè)是個(gè)回歸模型:y=w1x1+w2x2+…+w1000x1000+b
(當(dāng)然了汁展,為了讓y限定在[0,1]的范圍鹊碍,一般還得加個(gè)Logistic函數(shù))厌殉。
通過(guò)學(xué)習(xí),如果最后學(xué)習(xí)到的w就只有很少的非零元素侈咕,例如只有5個(gè)非零的wi公罕,
那么我們就有理由相信,這些對(duì)應(yīng)的特征在患病分析上面提供的信息是巨大的耀销,
決策性的楼眷。也就是說(shuō),患不患這種病只和這5個(gè)因素有關(guān)熊尉,那醫(yī)生就好分析多了罐柳。但如果1000個(gè)wi都非0,醫(yī)生面對(duì)這1000種因素狰住,累覺(jué)不愛(ài)张吉。
Scikit-learn為線性回歸提供了Lasso,為分類(lèi)提供了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
print('還是上面的那個(gè)數(shù)據(jù)集:')
lasso = Lasso(alpha=.3)
lasso.fit(data.loc[:, :'LSTAT'], data['target'])
print ("lasso模型選擇結(jié)果為: ")
print(pretty_print_linear(lasso.coef_, names, sort = True))
###########################################################
lasso模型選擇結(jié)果為:
3.092 * RM + -1.04 * DIS + -0.772 * PTRATIO + -0.617 * LSTAT + 0.28 * RAD + -0.091 * CRIM + 0.05 * ZN + -0.018 * INDUS + -0.015 * TAX + 0.01 * B + -0.001 * AGE + 0.0 * CHAS + -0.0 * NOX
可以看到查邢,很多特征的系數(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瘫里。 可以看出实蔽,系數(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ù)是非零哆姻。
L1 與L2的不同就在于L1在和每個(gè)坐標(biāo)軸相交的地方都有“角”出現(xiàn)宣增,而目標(biāo)函數(shù)的測(cè)地線除非位置擺得非常好, 大部分時(shí)候都會(huì)在角的地方相交矛缨。注意到在角的位置就會(huì)產(chǎn)生稀疏性爹脾,例如圖中的相交點(diǎn)就有w1=0携取,而更高維的時(shí)候(想象一下三維的L1-ball 是什么樣的驾诈?)除了角點(diǎn)以外,還有很多邊的輪廓也是既有很大的概率成為第一次相交的地方柄瑰,又會(huì)產(chǎn)生稀疏性落竹。
相比之下泌霍,L2 就沒(méi)有這樣的性質(zhì),因?yàn)闆](méi)有角述召,所以第一次相交的地方出現(xiàn)在具有稀疏性的位置的概率就變得非常小了朱转。這就從直觀上來(lái)解釋了為什么L1-regularization 能產(chǎn)生稀疏性,而L2-regularization 不行的原因了积暖。
因此藤为,一句話總結(jié)就是:L1會(huì)趨向于產(chǎn)生少量的特征,而其他的特征都是0夺刑,而L2會(huì)選擇更多的特征凉蜂,這些特征都會(huì)接近于0。Lasso在特征選擇時(shí)候非常有用性誉,而Ridge就只是一種規(guī)則化而已窿吩。
回過(guò)頭來(lái)看看3個(gè)互相關(guān)聯(lián)的特征的例子,分別以10個(gè)不同的種子隨機(jī)初始化運(yùn)行10次错览,來(lái)觀察L1和L2正則化的穩(wěn)定性纫雁。
from sklearn.metrics import r2_score
size = 100
#We run the method 10 times with different random seeds
for i in range(10):
print("第 %s 組X和Y" % str(i+1))
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("邏輯回歸參數(shù):", pretty_print_linear(lr.coef_))
ridge = Ridge(alpha=10)
ridge.fit(X,Y)
print("嶺回歸參數(shù):", pretty_print_linear(ridge.coef_))
##################################################################
第 1 組X和Y
邏輯回歸參數(shù): 0.728 * X0 + 2.309 * X1 + -0.082 * X2
嶺回歸參數(shù): 0.938 * X0 + 1.059 * X1 + 0.877 * X2
第 2 組X和Y
邏輯回歸參數(shù): 1.152 * X0 + 2.366 * X1 + -0.599 * X2
嶺回歸參數(shù): 0.984 * X0 + 1.068 * X1 + 0.759 * X2
第 3 組X和Y
邏輯回歸參數(shù): 0.697 * X0 + 0.322 * X1 + 2.086 * X2
嶺回歸參數(shù): 0.972 * X0 + 0.943 * X1 + 1.085 * X2
第 4 組X和Y
邏輯回歸參數(shù): 0.287 * X0 + 1.254 * X1 + 1.491 * X2
嶺回歸參數(shù): 0.919 * X0 + 1.005 * X1 + 1.033 * X2
第 5 組X和Y
邏輯回歸參數(shù): 0.187 * X0 + 0.772 * X1 + 2.189 * X2
嶺回歸參數(shù): 0.964 * X0 + 0.982 * X1 + 1.098 * X2
第 6 組X和Y
邏輯回歸參數(shù): -1.291 * X0 + 1.591 * X1 + 2.747 * X2
嶺回歸參數(shù): 0.758 * X0 + 1.011 * X1 + 1.139 * X2
第 7 組X和Y
邏輯回歸參數(shù): 1.199 * X0 + -0.031 * X1 + 1.915 * X2
嶺回歸參數(shù): 1.016 * X0 + 0.89 * X1 + 1.091 * X2
第 8 組X和Y
邏輯回歸參數(shù): 1.474 * X0 + 1.762 * X1 + -0.151 * X2
嶺回歸參數(shù): 1.018 * X0 + 1.039 * X1 + 0.901 * X2
第 9 組X和Y
邏輯回歸參數(shù): 0.084 * X0 + 1.88 * X1 + 1.107 * X2
嶺回歸參數(shù): 0.907 * X0 + 1.071 * X1 + 1.008 * X2
第 10 組X和Y
邏輯回歸參數(shù): 0.714 * X0 + 0.776 * X1 + 1.364 * X2
嶺回歸參數(shù): 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)曲管。
比較一下:
第 1 組X和Y
邏輯回歸參數(shù): 0.728 X0 + 2.309 X1 + -0.082 X2
嶺回歸參數(shù): 0.938 X0 + 1.059 X1 + 0.877 X2
原函數(shù)應(yīng)該為Y=X0+X1+X2+noise
邏輯回歸出現(xiàn)了 多重共線性
而嶺回歸 相對(duì)穩(wěn)定,而且系數(shù)也比較合理
4 隨機(jī)森林
隨機(jī)森林具有準(zhǔn)確率高硕糊、魯棒性好院水、易于使用等優(yōu)點(diǎn),這使得它成為了目前最流行的機(jī)器學(xué)習(xí)算法之一简十。 隨機(jī)森林提供了兩種特征選擇的方法:mean decrease impurity和mean decrease accuracy檬某。
4.1 平均不純度減少
隨機(jī)森林由多個(gè)決策樹(shù)構(gòu)成。決策樹(shù)中的每一個(gè)節(jié)點(diǎn)都是關(guān)于某個(gè)特征的條件螟蝙,為的是將數(shù)據(jù)集按照不同的響應(yīng)變量一分為二恢恼。
利用不純度可以確定節(jié)點(diǎn)(最優(yōu)條件),對(duì)于分類(lèi)問(wèn)題胰默,通常采用基尼不純度或者信息增益场斑,
對(duì)于回歸問(wèn)題,通常采用的是方差或者最小二乘擬合牵署。當(dāng)訓(xùn)練決策樹(shù)的時(shí)候漏隐,可以計(jì)算出每個(gè)特征減少了多少樹(shù)的不純度。
對(duì)于一個(gè)決策樹(shù)森林來(lái)說(shuō)碟刺,可以算出每個(gè)特征平均減少了多少不純度锁保,并把它平均減少的不純度作為特征選擇的值薯酝。
from sklearn.ensemble import RandomForestRegressor
import numpy as np
# 還是上面的data數(shù)據(jù)
rf = RandomForestRegressor()
for i in range(2):
rf.fit(data.iloc[:,:-1], data.iloc[:,-1])
print ("第 %s 次運(yùn)行, 各屬性得分分別是:" % str(i+1))
result = sorted(zip(map(lambda x: round(x, 4), rf.feature_importances_), names), reverse=True)
for each in result:
print(str(each[1]) + ' 的得分為: ' + str(each[0]), end=' ')
print()
print()
#####################################################################
第 1 次運(yùn)行, 各屬性得分分別是:
RM 的得分為: 0.5296 LSTAT 的得分為: 0.2694 DIS 的得分為: 0.0726 CRIM 的得分為: 0.0377 NOX 的得分為: 0.0299 PTRATIO 的得分為: 0.0175 AGE 的得分為: 0.0144 B 的得分為: 0.0105 TAX 的得分為: 0.0095 INDUS 的得分為: 0.0043 RAD 的得分為: 0.0036 ZN 的得分為: 0.0006 CHAS 的得分為: 0.0005
第 2 次運(yùn)行, 各屬性得分分別是:
LSTAT 的得分為: 0.4246 RM 的得分為: 0.3821 DIS 的得分為: 0.0539 CRIM 的得分為: 0.0406 NOX 的得分為: 0.0225 PTRATIO 的得分為: 0.0215 AGE 的得分為: 0.0167 TAX 的得分為: 0.014 B 的得分為: 0.0106 INDUS 的得分為: 0.0067 CHAS 的得分為: 0.0041 RAD 的得分為: 0.0015 ZN 的得分為: 0.0014
上面對(duì)數(shù)據(jù)集運(yùn)行了兩次半沽,可以看出兩次運(yùn)行每個(gè)數(shù)據(jù)的重要度都有變化,第一次運(yùn)行RM的得分最高吴菠,第二次運(yùn)行LSTAT得分最高
原因:
這里特征得分實(shí)際上采用的是Gini Importance者填。
使用基于不純度的方法的時(shí)候,要記鬃隹:1占哟、這種方法存在偏向,對(duì)具有更多類(lèi)別的變量會(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是很像的)。
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 + X2
rf = RandomForestRegressor(n_estimators=20, max_features=2)
rf.fit(X, Y);
print ("Scores for X0, X1, X2:", list(map(lambda x:round (x,3),rf.feature_importances_)))
##################################################################
Scores for X0, X1, X2: [0.27200000000000002, 0.54800000000000004, 0.17899999999999999]
特征隨機(jī)選擇方法稍微緩解了這個(gè)問(wèn)題袍患,但總的來(lái)說(shuō)并沒(méi)有完全解決坦康。
上面的例子中,X0诡延、X1滞欠、X2是三個(gè)互相關(guān)聯(lián)的變量,在沒(méi)有噪音的情況下肆良,輸出變量是三者之和筛璧。
當(dāng)計(jì)算特征重要性時(shí),可以看到X1的重要度比X2的重要度要高出3倍惹恃,但實(shí)際上他們真正的重要度是一樣的夭谤。
盡管數(shù)據(jù)量已經(jīng)很大且沒(méi)有噪音,且用了20棵樹(shù)來(lái)做隨機(jī)選擇巫糙,但這個(gè)問(wèn)題還是會(huì)存在朗儒。
需要注意的一點(diǎn)是,關(guān)聯(lián)特征的打分存在不穩(wěn)定的現(xiàn)象参淹,這不僅僅是隨機(jī)森林特有的醉锄,
大多數(shù)基于模型的特征選擇方法都存在這個(gè)問(wèn)題。
4.2 平均精確率減少
另一種常用的特征選擇方法就是直接度量每個(gè)特征對(duì)模型精確率的影響浙值。
主要思路是打亂每個(gè)特征的特征值順序恳不,并且度量順序變動(dòng)對(duì)模型的精確率的影響。
很明顯开呐,對(duì)于不重要的變量來(lái)說(shuō)烟勋,打亂順序?qū)δP偷木_率影響不會(huì)太大,
但是對(duì)于重要的變量來(lái)說(shuō)筐付,打亂順序就會(huì)降低模型的精確率卵惦。
from sklearn.cross_validation import ShuffleSplit
from sklearn.metrics import r2_score
from collections import defaultdict
rf = RandomForestRegressor()
scores = defaultdict(list)
#隨機(jī)得到索引
for train_idx, test_idx in ShuffleSplit(data.shape[0], 100, .3):
X_train, X_test = data.iloc[train_idx, :-1].values, data.iloc[test_idx, :-1].values
Y_train, Y_test = data.iloc[train_idx, -1].values, data.iloc[test_idx, -1] .values
# 訓(xùn)練
r = rf.fit(X_train, Y_train)
acc = r2_score(Y_test, rf.predict(X_test))
for i in range(X_train.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) # 將每一次得到的分?jǐn)?shù)加入字典
print ("屬性得分為:")
# 計(jì)算平均值
result = sorted([(round(np.mean(score), 4), feat) for
feat, score in scores.items()], reverse=True)
for each in result:
print(each[1] + ' 的平均分為: ' + str(each[0]))
###################################################################
屬性得分為:
LSTAT 的平均分為: 0.7312
RM 的平均分為: 0.5769
DIS 的平均分為: 0.0865
NOX 的平均分為: 0.0416
CRIM 的平均分為: 0.0401
PTRATIO 的平均分為: 0.0236
TAX 的平均分為: 0.0167
AGE 的平均分為: 0.0119
B 的平均分為: 0.0054
INDUS 的平均分為: 0.0052
RAD 的平均分為: 0.0021
CHAS 的平均分為: 0.0004
ZN 的平均分為: 0.0003
注意:請(qǐng)看代碼 (acc-shuff_acc)/acc
如果屬性A的順序?qū)?zhǔn)確度影響很大,則shuff_acc值會(huì)在acc的基礎(chǔ)上變小,則(acc-shuff_acc)的值會(huì)變大
所以最終結(jié)果(acc-shuff_acc)/acc 值越大則屬性A對(duì)Y值影響程度越大瓦戚,該屬性越重要
在這個(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或其他類(lèi)似的方法。
它的主要思想是在不同的數(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 ("屬性選擇得分:")
result = sorted(zip(map(lambda x: round(x, 4), rlasso.scores_),
names), reverse=True)
for each in result:
print(each[1] + ' 的平均分為: ' + str(each[0]))
###################################################################
屬性選擇得分:
RM 的平均分為: 1.0
PTRATIO 的平均分為: 1.0
LSTAT 的平均分為: 1.0
B 的平均分為: 0.68
CHAS 的平均分為: 0.675
TAX 的平均分為: 0.42
CRIM 的平均分為: 0.345
NOX 的平均分為: 0.24
DIS 的平均分為: 0.185
INDUS 的平均分為: 0.145
ZN 的平均分為: 0.05
RAD 的平均分為: 0.025
AGE 的平均分為: 0.015
在上邊這個(gè)例子當(dāng)中灶伊,最高的3個(gè)特征得分是1.0疆前,這表示他們總會(huì)被選作有用的特征
(當(dāng)然,得分會(huì)收到正則化參數(shù)alpha的影響谁帕,但是sklearn的隨機(jī)lasso能夠自動(dòng)選擇最優(yōu)的alpha)峡继。
接下來(lái)的幾個(gè)特征得分就開(kāi)始下降冯袍,但是下降的不是特別急劇匈挖,這跟純lasso的方法和隨機(jī)森林的結(jié)果不一樣。
能夠看出穩(wěn)定性選擇對(duì)于克服過(guò)擬合和對(duì)數(shù)據(jù)理解來(lái)說(shuō)都是有幫助的:
總的來(lái)說(shuō)康愤,好的特征不會(huì)因?yàn)橛邢嗨频奶卣骼苎㈥P(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采用的普通的回歸脖卖,沒(méi)有經(jīng)過(guò)正則化的回歸是不穩(wěn)定的乒省,那么RFE就是不穩(wěn)定的;
假如采用的是Ridge畦木,而用Ridge正則化的回歸是穩(wěn)定的袖扛,那么RFE就是穩(wěn)定的。
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"]
#選擇模型十籍,可以使lr也可以是lasso或者其他
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 ("屬性選擇得分:")
result = sorted(zip(map(lambda x: round(x, 4), rlasso.scores_),
names), reverse=True)
for each in result:
print(each[1] + ' 的平均分為: ' + str(each[0]))
#################################################################
RM 的平均分為: 1.0
PTRATIO 的平均分為: 1.0
LSTAT 的平均分為: 1.0
B 的平均分為: 0.68
CHAS 的平均分為: 0.675
TAX 的平均分為: 0.42
CRIM 的平均分為: 0.345
NOX 的平均分為: 0.24
DIS 的平均分為: 0.185
INDUS 的平均分為: 0.145
ZN 的平均分為: 0.05
RAD 的平均分為: 0.025
AGE 的平均分為: 0.015