在進(jìn)行數(shù)據(jù)處理或機(jī)器學(xué)習(xí)時,哪些特征該涵蓋進(jìn)來,,哪些則要剔除掉是一個重要的問題,。如果將無關(guān)的特征納入進(jìn)來,就造成了特征冗余,,還有可能影響預(yù)測準(zhǔn)確率,。在現(xiàn)有特征中,,如何有效地進(jìn)行特征選擇呢?
特征選擇的一般流程
特征選擇的一般過程:
- 生成子集:搜索特征子集,,為評價函數(shù)提供特征子集
- 設(shè)置評價函數(shù):評價特征子集的好壞
- 確定停止準(zhǔn)則:與評價函數(shù)相關(guān),,一般是閾值,評價函數(shù)達(dá)到一定標(biāo)準(zhǔn)后就可停止搜索
- 驗證:在驗證數(shù)據(jù)集上驗證選出來的特征子集的有效性
理論上我們可以枚舉出所有的特征子集,,但是,, 當(dāng)特征數(shù)量很大的時候, 這個搜索空間會很大,,如何找最優(yōu)特征還是需要一些經(jīng)驗結(jié)論,。
特征選擇的常用方法
根據(jù)特征選擇的形式,可分為三大類方法:
- 過濾法(Filter):按照發(fā)散性或相關(guān)性對各個特征進(jìn)行評分,,設(shè)定閾值或者待選擇特征的個數(shù)進(jìn)行篩選
- 包裝法(Wrapper):根據(jù)評價函數(shù),,每次選擇若干特征,或者排除若干特征
- 嵌入法Embedded():先使用某些機(jī)器學(xué)習(xí)的模型進(jìn)行訓(xùn)練,,得到各個特征的權(quán)值系數(shù),,根據(jù)系數(shù)從大到小選擇特征(類似于Filter,只不過系數(shù)是通過訓(xùn)練得來的)
- 特征合成,。比較經(jīng)典的降維方法有主成分分析法(PCA),,它可以將多個原始維度數(shù)據(jù)合成新維度數(shù)據(jù)。
過濾法
過濾法的基本想法是:分別對每個特征 ,,計算 相對于預(yù)測結(jié)果 的信息量 ,,得到 個結(jié)果。然后 按照從大到小排序,,輸出前 個特征,。
但這里有兩個重要細(xì)節(jié)需要考慮:1.使用什么方法評價信息量 2.如何選。
評價方法
- 相關(guān)系數(shù)方法(如Pearson,,Kendal系數(shù)等),,看特征與結(jié)果的相關(guān)性;
- 卡方檢驗,,假設(shè)檢驗的重要方法,,看特征與結(jié)果之間是否獨(dú)立;
- 互信息和最大信息系數(shù),,信息論的方法,;
- 方差選擇法,通過特征本身的變異率進(jìn)行篩選,,變異率小的特征不考慮
相關(guān)系數(shù)
皮爾森相關(guān)系數(shù)是一種簡單的,,能幫助理解特征和響應(yīng)變量之間關(guān)系的方法,衡量的是變量之間的線性相關(guān)性,,結(jié)果的取值區(qū)間為[-1,1] ,, -1 表示完全的負(fù)相關(guān),, +1 表示完全的正相關(guān), 0 表示沒有線性相關(guān)性,。Scipy
的pearsonr
方法能夠同時計算相關(guān)系數(shù)和p-value
from scipy.stats import pearsonr
x1 = [51, 80, 95, 19, 73, 84, 65, 30, 1, 35, 13, 61, 36, 65, 57, 40, 15, 73, 58, 62] # 特征1數(shù)據(jù)
x2 = [7.0, 27.5, 23.0, 32.0, 15.5, 44.0, 10.5, 29.5, 36.0, 47.5, 27.0, 28.5, 26.5, 41.5, 12.5, 0.5, 19.0, 48.5, 0.5, 24.0] #特征2數(shù)據(jù)
y = [14, 64, 54, 72, 36, 92, 24, 62, 72, 95, 55, 64, 60, 84, 33, 5, 40, 99, 2, 48] # 結(jié)果數(shù)據(jù)
print(pearsonr(x1,y))
print(pearsonr(x2,y))
輸出結(jié)果為
PearsonRResult(statistic=0.020864449411346502, pvalue=0.930425438739739)
PearsonRResult(statistic=0.9939219884168465, pvalue=1.0516806437334743e-18)
通過結(jié)果可以看到x1與y之間幾乎沒有線性相關(guān)性,,x2與y之間的相關(guān)性則非常強(qiáng)。我們將圖畫出來:
import numpy as np
import matplotlib.pyplot as plt
plt.xkcd()
plt.rcParams['font.family'] = ['SimHei']
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.scatter(x1,y,label='Pearson相關(guān)性為0.020')
plt.xlabel('x1')
plt.ylabel('y')
plt.legend()
plt.subplot(1,2,2)
plt.scatter(x2,y,label='Pearson相關(guān)性為0.994')
plt.xlabel('x2')
plt.ylabel('y')
plt.legend()
plt.tight_layout()
plt.savefig('images/feature0101.png')
plt.show()
線性相關(guān)性強(qiáng)的兩個變量之間數(shù)據(jù)點(diǎn)在一條直線周圍,。不過Pearson相關(guān)系數(shù)的一個明顯缺陷是,,它只是測量的變量之間的線性相關(guān)性。如果關(guān)系是非線性的,,Pearson相關(guān)性也可能會接近 0 ,。比如下面這幅圖,二者之間有二次關(guān)系,,但線性相關(guān)系數(shù)為0.
x3 = range(-10,11)
y2 = [x**2 for x in x3]
plt.scatter(x3,y2,label='Pearson相關(guān)性為0.0')
plt.tight_layout()
plt.savefig('images/feature0102.png')
plt.show()
卡方檢驗
經(jīng)典的卡方檢驗是依據(jù)總體分布狀況,,計算出分類變量中各類別的期望頻數(shù),與分布的觀察頻數(shù)進(jìn)行對比,,判斷期望頻數(shù)與觀察頻數(shù)是否有顯著差異.
兩個變量之間是否獨(dú)立的檢驗步驟如下(:
- (2)根據(jù)概率的乘法法則計算理論數(shù):理論數(shù)的計算方法,;
- (3)計算檢驗統(tǒng)計量(其中表示觀察值,,表示期望值);
- (4)確定自由度:2×2列聯(lián)表的自由度,,是列聯(lián)表的行數(shù),,是列聯(lián)表的列數(shù),若自由度=1,,則應(yīng)做連續(xù)性校正,;
- (6)根據(jù)p值或臨界值得出是否要拒絕原假設(shè)的結(jié)論
例子
巴西醫(yī)生馬廷思收集犯有各種貪污,、受賄罪的官員與廉潔官員之壽命的調(diào)查資料:500名貪官中有348人壽命小于平均壽命、152人的壽命大于或等于平均壽命,;590名廉潔官中有93人的壽命小于平均壽命,、497人的壽命大于或等于平均壽命.這里的“平均壽命”是指“當(dāng)?shù)厝司鶋勖保嚪治龉賳T在經(jīng)濟(jì)上是否清白與他們壽命的長短之間是否獨(dú)立?
列 列聯(lián)表
| 短壽 | 長壽 | 合計 |
---|
貪官 | 348 | 152 | 500 |
廉潔官 | 93 | 497 | 590 |
合計 | 441 | 649 | 1090 |
由計算公式得 , 所以我們有 的把握可以認(rèn)為在經(jīng)濟(jì)上不清白的人易過早死亡.
我們可以借助scipy
中的統(tǒng)計函數(shù)stats.chi2_contigency
進(jìn)行計算
import pandas as pd
df = pd.DataFrame([[348,152],[93,497]],index=['貪官','廉潔官'],columns=['短壽','長壽']) # 構(gòu)建數(shù)據(jù)
from scipy.stats import chi2_contingency
chi2_contingency(df)
結(jié)果如下:
Chi2ContingencyResult(statistic=323.40433728617546, pvalue=2.626485030719825e-72, dof=1, expected_freq=array([[202.29357798, 297.70642202],
[238.70642202, 351.29357798]]))
通過結(jié)果第二項P值(極?。┩茢喑鼍芙^原假設(shè),,認(rèn)為是否貪污與壽命長短之間是有關(guān)聯(lián)的。
通過sklearn
庫中的特征選擇函數(shù)和卡方函數(shù)可以方便的對數(shù)據(jù)進(jìn)行篩選,,我們以鳶尾花數(shù)據(jù)集為例:
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest # 選取最優(yōu)的2個特征
from sklearn.feature_selection import chi2 # 引入卡方特征篩選方法
iris = load_iris() # 加載數(shù)據(jù)集
X, y = iris.data, iris.target #iris數(shù)據(jù)集
前五條數(shù)據(jù)如下:
| sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | target |
---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 0 |
1 | 4.9 | 3 | 1.4 | 0.2 | 0 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 0 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 0 |
4 | 5 | 3.6 | 1.4 | 0.2 | 0 |
接下來進(jìn)行特征篩選:
#選擇K個最好的特征,,返回選擇特征后的數(shù)據(jù)
X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
結(jié)果如下:array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2],
[1.7, 0.4],
...]]
很明顯,最后的結(jié)果選擇的是 petal length (cm) 和 petal width (cm)作為相關(guān)性最強(qiáng)的特征,。
互信息與最大信息系數(shù)
經(jīng)典的互信息(Mutual information)也是評價類別型變量對類別型變量的相關(guān)性的,,互信息公式如下:
當(dāng)是0/1離散值的時候,,這個公式如上。很容易推廣到 是多個離散值的情況,。這里的 和 都是從訓(xùn)練集上得到的,。 公式根據(jù) KL 距離(Kullback-Leibler)獲得:
也就是說, MI 衡量的是 x_i 和 y 的獨(dú)立性。如果它倆獨(dú)立 P(x_i,y)=p(x_i)p(y) ,,那么 KL 距離值為0,,也就是 和 不相關(guān)了,可以去除 ,。相反,,如果兩者密切相關(guān),那么 MI 值會很大,。在對 MI 進(jìn)行排名后,,最后剩余的問題就是如何選擇 個值(前 k 個 )。
方差選擇法
方差方法先要計算各個特征的方差,,然后根據(jù)閾值,,選擇方差大于閾值的特征。為了消除特征量綱不統(tǒng)一的問題,,可以先進(jìn)行特征歸一化處理,。
包裝法
基本思想:對于每一個待選的特征子集,都在訓(xùn)練集上訓(xùn)練一遍模型,,然后在測試集上根據(jù)誤差大小選擇出特征子集,。需要先選定特定算法,通常選用普遍效果較好的算法,, 例如隨機(jī)森林Random Forest,,支持向量機(jī)SVM, k近鄰kNN等等,。具體生成子集的方法可以采用前向搜索法(增量式添加新特征),、后向搜索法(在最全子集中逐個遞減)、遞歸特征消除法(使用一個基模型來進(jìn)行多輪訓(xùn)練,,每輪訓(xùn)練后通過學(xué)習(xí)器返回的特征重要性,,消除若干權(quán)重較低的特征,再基于新的特征集進(jìn)行下一輪訓(xùn)練)
這里介紹遞歸特征消除法(Recursive feature elimination)的Python實現(xiàn),。我們對乳腺癌數(shù)據(jù)進(jìn)行特征消除,,先導(dǎo)入數(shù)據(jù):
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest # 選取最優(yōu)的2個特征
from sklearn.feature_selection import chi2 # 引入卡方特征篩選方法
iris = load_iris() # 加載數(shù)據(jù)集
X, y = iris.data, iris.target #iris數(shù)據(jù)集
前五條數(shù)據(jù)如下:
| 0 | 1 | 2 | 3 | 4 |
---|
mean radius | 17.99 | 20.57 | 19.69 | 11.42 | 20.29 |
mean texture | 10.38 | 17.77 | 21.25 | 20.38 | 14.34 |
mean perimeter | 122.8 | 132.9 | 130 | 77.58 | 135.1 |
mean area | 1001 | 1326 | 1203 | 386.1 | 1297 |
mean smoothness | 0.1184 | 0.08474 | 0.1096 | 0.1425 | 0.1003 |
mean compactness | 0.2776 | 0.07864 | 0.1599 | 0.2839 | 0.1328 |
mean concavity | 0.3001 | 0.0869 | 0.1974 | 0.2414 | 0.198 |
mean concave points | 0.1471 | 0.07017 | 0.1279 | 0.1052 | 0.1043 |
mean symmetry | 0.2419 | 0.1812 | 0.2069 | 0.2597 | 0.1809 |
mean fractal dimension | 0.07871 | 0.05667 | 0.05999 | 0.09744 | 0.05883 |
radius error | 1.095 | 0.5435 | 0.7456 | 0.4956 | 0.7572 |
texture error | 0.9053 | 0.7339 | 0.7869 | 1.156 | 0.7813 |
perimeter error | 8.589 | 3.398 | 4.585 | 3.445 | 5.438 |
area error | 153.4 | 74.08 | 94.03 | 27.23 | 94.44 |
smoothness error | 0.006399 | 0.005225 | 0.00615 | 0.00911 | 0.01149 |
compactness error | 0.04904 | 0.01308 | 0.04006 | 0.07458 | 0.02461 |
concavity error | 0.05373 | 0.0186 | 0.03832 | 0.05661 | 0.05688 |
concave points error | 0.01587 | 0.0134 | 0.02058 | 0.01867 | 0.01885 |
symmetry error | 0.03003 | 0.01389 | 0.0225 | 0.05963 | 0.01756 |
fractal dimension error | 0.006193 | 0.003532 | 0.004571 | 0.009208 | 0.005115 |
worst radius | 25.38 | 24.99 | 23.57 | 14.91 | 22.54 |
worst texture | 17.33 | 23.41 | 25.53 | 26.5 | 16.67 |
worst perimeter | 184.6 | 158.8 | 152.5 | 98.87 | 152.2 |
worst area | 2019 | 1956 | 1709 | 567.7 | 1575 |
worst smoothness | 0.1622 | 0.1238 | 0.1444 | 0.2098 | 0.1374 |
worst compactness | 0.6656 | 0.1866 | 0.4245 | 0.8663 | 0.205 |
worst concavity | 0.7119 | 0.2416 | 0.4504 | 0.6869 | 0.4 |
worst concave points | 0.2654 | 0.186 | 0.243 | 0.2575 | 0.1625 |
worst symmetry | 0.4601 | 0.275 | 0.3613 | 0.6638 | 0.2364 |
worst fractal dimension | 0.1189 | 0.08902 | 0.08758 | 0.173 | 0.07678 |
target | 0 | 0 | 0 | 0 | 0 |
一共有30個特征,我們現(xiàn)在要選出和腫瘤良性/惡性相關(guān)的最重要的5個特征:
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier # 隨機(jī)森林
#遞歸特征消除法,,返回特征選擇后的數(shù)據(jù)
#參數(shù)estimator為基模型
#參數(shù)n_features_to_select為選擇的特征個數(shù)
RFE(estimator=RandomForestClassifier(), n_features_to_select=5).fit_transform(cancer.data, cancer.target)
模型流程:
最后篩選得到的5個特征為:
array([[1.471e-01, 2.538e+01, 1.846e+02, 2.019e+03, 2.654e-01],
[7.017e-02, 2.499e+01, 1.588e+02, 1.956e+03, 1.860e-01],
[1.279e-01, 2.357e+01, 1.525e+02, 1.709e+03, 2.430e-01],
...,
[5.302e-02, 1.898e+01, 1.267e+02, 1.124e+03, 1.418e-01],
[1.520e-01, 2.574e+01, 1.846e+02, 1.821e+03, 2.650e-01],
[0.000e+00, 9.456e+00, 5.916e+01, 2.686e+02, 0.000e+00]])
嵌入法
基于懲罰項的特征選擇法
通過L1正則項來選擇特征:L1正則方法具有稀疏解的特性,,因此天然具備特征選擇的特性。我們所說的正則化,就是在原來的損失的基礎(chǔ)上,,加上了一些正則化項或者稱為模型復(fù)雜度懲罰項,。以線性回歸為例子。最初的損失函數(shù)(最小二乘法):
加上L1正則項 (lasso回歸) :
加上L2正則項 (嶺回歸):
這里用邏輯回歸模型+L1政策項對乳腺癌數(shù)據(jù)進(jìn)行特征選擇
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#帶L1懲罰項的邏輯回歸作為基模型的特征選擇
feature_new = SelectFromModel(LogisticRegression(penalty='l1', solver='liblinear',C=0.25)).fit_transform(X,y)
輸出消除特征之后的新數(shù)據(jù):
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#帶L1懲罰項的邏輯回歸作為基模型的特征選擇
feature_new = SelectFromModel(LogisticRegression(penalty='l1', solver='liblinear',C=0.25)).fit_transform(X,y)
輸出消除特征之后新特征的形狀:
feature_new.shape
(569,7)
說明經(jīng)過特征消除之后剩下7個特征,。我們可以通過調(diào)節(jié)模型中的系數(shù)C
來調(diào)整最終確定的特征數(shù)量,。
特征合成
PCA方法
PCA把原先的個特征用數(shù)目更少的個特征取代,新的個特征一要保證最大化樣本方差,,二保證相互獨(dú)立的,。新特征是舊特征的線性組合,提供一個新的框架來解釋結(jié)果,。
PCA 算法步驟
設(shè)有 個樣本, 每個樣本有 個指標(biāo) (變量): , 得到原始數(shù)據(jù)矩陣:
- 對原始指標(biāo)數(shù)據(jù)矩陣 做標(biāo)準(zhǔn)化 (或中心化) 處理, 并計算標(biāo)準(zhǔn)化樣本數(shù)據(jù)矩陣的協(xié)方差矩陣, 其中
- 求出 的特征值 和相應(yīng)的特征向量, 以及相應(yīng)的正交化單位特征向量
- 選擇主成分,。在已確定的全部個主成分中合理選擇個,一般用方差貢獻(xiàn)率
解釋主成分所反映信息量的大小,,的確定是以累計貢獻(xiàn)率
達(dá)到足夠大(一般在 以上)為原則,。另外, 也可以考慮特征值大于 1 、陡坡圖,、平行分析等原則,。前 個主成分表示為
其中, 稱為因子載荷。
- 計算指標(biāo)在不同主成分線性組合中的系數(shù):
我們使用sklearn的函數(shù)進(jìn)行PCA算法
from sklearn.datasets import load_breast_cancer
from sklearn.decomposition import PCA
cancer = load_breast_cancer() # 加載數(shù)據(jù)集
X = cancer.data
n_components = 5
pca = PCA(n_components=n_components)
pca.fit(X)
# 顯示結(jié)果
n_feature = X.shape[1]
col_names = ['X'+str(i) for i in range(1,n_feature+1)]
index_names = ['F'+str(i) for i in range(1,n_components+1)]
comps = pd.DataFrame(pca.components_,index=index_names,columns=col_names)
print('解釋方差:',pca.explained_variance_)
print('解釋方差占比:',pca.explained_variance_ratio_)
解釋方差:[4.43782605e+05 7.31010006e+03 7.03833742e+02 5.46487379e+01
3.98900178e+01]
解釋方差占比:[9.82044672e-01 1.61764899e-02 1.55751075e-03 1.20931964e-04
8.82724536e-05]
其實從解釋方差占比來看,,第一個主成分就已經(jīng)解釋98%的方差變動了,。我們不妨看一下解釋方差的陡坡圖:
plt.plot(range(1,6),pca.explained_variance_ratio_,label='解釋性方差占比')
plt.plot(range(1,6),pca.explained_variance_ratio_.cumsum(),label='累計方差占比')
plt.legend()
plt.tight_layout()
plt.savefig('images/feature0104.png')
plt.xlabel('主成分個數(shù)')
plt.show()
參考資料:
- 孫佳偉【機(jī)器學(xué)習(xí)】特征選擇(Feature Selection)方法匯總 https://zhuanlan.zhihu.com/p/74198735
- 模型視角 用主成分分析法PCA進(jìn)行綜合評價(附Python代碼)https://mp.weixin.qq.com/s/9KMvpCHY2m46Y2YRGlPl_w