本文為數據茶水間群友原創,經授權在本公眾號發表。
關於作者:JunLiang,一個熱愛挖掘的數據從業者,勤學好問、動手達人,期待與大家一起交流探討機器學習相關內容~
0x00 前言
數據和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已。由此可見,特征工程在機器學習中占有相當重要的地位。在實際應用當中,可以說特征工程是機器學習成功的關鍵。
那特征工程是什么?
特征工程是利用數據領域的相關知識來創建能夠使機器學習算法達到最佳性能的特征的過程。
特征工程又包含了Feature Selection(特征選擇)、Feature Extraction(特征提取)和Feature construction(特征構造)等子問題,本章內容主要討論特征選擇相關的方法及實現。
在實際項目中,我們可能會有大量的特征可使用,有的特征攜帶的信息豐富,有的特征攜帶的信息有重疊,有的特征則屬於無關特征,如果所有特征不經篩選地全部作為訓練特征,經常會出現維度災難問題,甚至會降低模型的准確性。因此,我們需要進行特征篩選,排除無效/冗余的特征,把有用的特征挑選出來作為模型的訓練數據。
0x01 特征選擇介紹
1.特征按重要性分類
-
相關特征:
對於學習任務(例如分類問題)有幫助,可以提升學習算法的效果;
-
無關特征:
對於我們的算法沒有任何幫助,不會給算法的效果帶來任何提升;
-
冗余特征:
不會對我們的算法帶來新的信息,或者這種特征的信息可以由其他的特征推斷出;
2.特征選擇的目的
對於一個特定的學習算法來說,哪一個特征是有效的是未知的。因此,需要從所有特征中選擇出對於學習算法有益的相關特征。而且在實際應用中,經常會出現維度災難問題。如果只選擇所有特征中的部分特征構建模型,那么可以大大減少學習算法的運行時間,也可以增加模型的可解釋性。
3.特征選擇的原則
獲取盡可能小的特征子集,不顯著降低分類精度、不影響分類分布以及特征子集應具有穩定、適應性強等特點。
0x02 特征選擇的方法
1.Filter方法(過濾式)
先進行特征選擇,然后去訓練學習器,所以特征選擇的過程與學習器無關。相當於先對特征進行過濾操作,然后用特征子集來訓練分類器。
主要思想:對每一維特征“打分”,即給每一維的特征賦予權重,這樣的權重就代表着該特征的重要性,然后依據權重排序。
主要方法:
-
Chi-squared test(卡方檢驗)
-
Information gain(信息增益)
-
Correlation coefficient scores(相關系數)
優點:運行速度快,是一種非常流行的特征選擇方法。
缺點:無法提供反饋,特征選擇的標准/規范的制定是在特征搜索算法中完成,學習算法無法向特征搜索算法傳遞對特征的需求。另外,可能處理某個特征時由於任意原因表示該特征不重要,但是該特征與其他特征結合起來則可能變得很重要。
2.Wrapper方法(封裝式)
直接把最后要使用的分類器作為特征選擇的評價函數,對於特定的分類器選擇最優的特征子集。
主要思想:將子集的選擇看作是一個搜索尋優問題,生成不同的組合,對組合進行評價,再與其他的組合進行比較。這樣就將子集的選擇看作是一個優化問題,這里有很多的優化算法可以解決,尤其是一些啟發式的優化算法,如GA、PSO(如:優化算法-粒子群算法)、DE、ABC(如:優化算法-人工蜂群算法)等。
主要方法:遞歸特征消除算法。
優點:對特征進行搜索時圍繞學習算法展開的,對特征選擇的標准/規范是在學習算法的需求中展開的,能夠考慮學習算法所屬的任意學習偏差,從而確定最佳子特征,真正關注的是學習問題本身。由於每次嘗試針對特定子集時必須運行學習算法,所以能夠關注到學習算法的學習偏差/歸納偏差,因此封裝能夠發揮巨大的作用。
缺點:運行速度遠慢於過濾算法,實際應用用封裝方法沒有過濾方法流行。
3.Enbedded方法(嵌入式)
將特征選擇嵌入到模型訓練當中,其訓練可能是相同的模型,但是特征選擇完成后,還能給予特征選擇完成的特征和模型訓練出的超參數,再次訓練優化。
主要思想:在模型既定的情況下學習出對提高模型准確性最好的特征。也就是在確定模型的過程中,挑選出那些對模型的訓練有重要意義的特征。
主要方法:用帶有L1正則化的項完成特征選擇(也可以結合L2懲罰項來優化)、隨機森林平均不純度減少法/平均精確度減少法。
優點:對特征進行搜索時圍繞學習算法展開的,能夠考慮學習算法所屬的任意學習偏差。訓練模型的次數小於Wrapper方法,比較節省時間。
缺點:運行速度慢。
0x03 特征選擇實現方法一:去掉取值變化小的特征(Removing features with low variance)
該方法一般用在特征選擇前作為一個預處理的工作,即先去掉取值變化小的特征,然后再使用其他特征選擇方法選擇特征。
考察某個特征下,樣本的方差值,可以認為給定一個閾值,拋棄哪些小於某個閾值的特征。
1.實現原理
-
離散型變量:
假設某特征的特征值只有0和1,並且在所有輸入樣本中,95%的實例的該特征取值都是1,那就可以認為這個特征作用不大。
如果100%都是1,那這個特征就沒意義了。
-
連續型變量:
需要將連續變量離散化之后才能用。
而且實際當中,一般不太會有95%以上都取某個值的特征存在,所以這種方法雖然簡單但是不太好用。可以把它作為特征選擇的預處理,先去掉那些取值變化小的特征,然后再從接下來提到的的特征選擇方法中選擇合適的進行進一步的特征選擇。
2.實現代碼
from sklearn.feature_selection import VarianceThreshold
X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
sel.fit_transform(X)
#array([[0, 1],
[1, 0],
[0, 0],
[1, 1],
[1, 0],
[1, 1]])
0x04 特征選擇實現方法二:單變量特征選擇
單變量特征選擇方法獨立的衡量每個特征與響應變量之間的關系,單變量特征選擇能夠對每一個特征進行測試,衡量該特征和響應變量之間的關系,根據得分扔掉不好的特征。該方法簡單,易於運行,易於理解,通常對於理解數據有較好的效果(但對特征優化、提高泛化能力來說不一定有效);這種方法有許多改進的版本、變種。
1.Pearson相關系數(Pearson Correlation)
皮爾森相關系數是一種最簡單的,能幫助理解特征和響應變量之間關系的方法,該方法衡量的是變量之間的線性相關性。
1)原理介紹
-
就是用x_i、x_j的協方差除以x_i的標准差和x_j的標准差,可以看成一種剔除了兩個變量量綱影響、標准化后的特殊協方差。
-
協方差是度量各個維度偏離其均值的程度,協方差的值為正值時說明兩者是正相關,否則是負相關的。
結果的取值區間為[-1,1],-1表示完全的負相關,+1表示完全的正相關,0表示沒有線性相關,絕對值表示相關性的強度。
-
標准差也稱均方差,是方差的算術平方根,能反映一個數據集的離散程度。
2)主要用於連續型特征的篩選,不適用於離散型特征的篩選。
3)優缺點
-
優點:
相關系數計算速度快、易於計算,經常在拿到數據(經過清洗和特征提取之后的)之后第一時間就執行。Pearson相關系數能夠表征豐富的關系,符合表示關系的正負,絕對值能夠表示強度。
-
缺點:
相關系數作為特征排序機制,它只對線性關系敏感,如果關系是非線性的,即便兩個變量具有一一對應的關系,相關系數系數也可能會接近0。
4)代碼實現
import numpy as np
from scipy.stats import pearsonr
np.random.seed(2019)
size=1000
x = np.random.normal(0, 1, size)
# 計算兩變量間的相關系數
print("Lower noise {}".format(pearsonr(x, x + np.random.normal(0, 1, size))))
print("Higher noise {}".format(pearsonr(x, x + np.random.normal(0, 10, size))))
2.互信息和最大信息系數(Mutual information and maximal information coefficient)
如果變量不是獨立的,那么我們可以通過考察聯合概率分布與邊緣概率分布乘積之間的 Kullback-Leibler 散度來判斷它們是否“接近”於相互獨立。
1)互信息方法
熵H(Y)與條件熵H(Y|X)之間的差稱為互信息,互信息與條件熵之間的關系:
其實,這就是ID3決策樹的特征選擇規則。
互信息法也是評價定性自變量對定性因變量的相關性的,但是並不方便直接用於特征選擇:
-
它不屬於度量方式,也沒有辦法進行歸一化,在不同的數據上的結果無法做比較。
-
只能用於離散型特征的選擇,連續型特征需要先進行離散化才能用互信息進行特征選擇,而互信息的結果對離散化的方式很敏感。
2)最大信息系數方法
由於互信息法並不方便直接用於特征選擇,因此引入了最大信息系數。最大信息數據首先尋找一種最優的離散方式,然后把互信息取值轉換成一種度量方式,取值區間為[0,1]。
3)最大信息系數方法代碼實現
x = np.random.normal(0,10,300)
z = x *x
pearsonr(x,z)
# 輸出-0.1
from minepy import MINE
m = MINE()
m.compute_score(x, z)
print(m.mic())
# 輸出1.0
3.距離相關系數(Distance correlation)
距離相關系數是為了克服Pearson相關系數的弱點而生的。
1)原理介紹
Pearson相關系數是0,我們也不能斷定這兩個變量是獨立的(有可能是非線性相關)。
例如x和x^2之間的Pearson相關系數是0,但是兩個變量並不是獨立的。
2)代碼實現
from scipy.spatial.distance import pdist, squareform
import numpy as np
from numbapro import jit, float32
def distcorr(X, Y):
""" Compute the distance correlation function
>>> a = [1,2,3,4,5]
>>> b = np.array([1,2,9,4,4])
>>> distcorr(a, b)
0.762676242417
"""
X = np.atleast_1d(X)
Y = np.atleast_1d(Y)
if np.prod(X.shape) == len(X):
X = X[:, None]
if np.prod(Y.shape) == len(Y):
Y = Y[:, None]
X = np.atleast_2d(X)
Y = np.atleast_2d(Y)
n = X.shape[0]
if Y.shape[0] != X.shape[0]:
raise ValueError('Number of samples must match')
a = squareform(pdist(X))
b = squareform(pdist(Y))
A = a - a.mean(axis=0)[None, :] - a.mean(axis=1)[:, None] + a.mean()
B = b - b.mean(axis=0)[None, :] - b.mean(axis=1)[:, None] + b.mean()
dcov2_xy = (A * B).sum()/float(n * n)
dcov2_xx = (A * A).sum()/float(n * n)
dcov2_yy = (B * B).sum()/float(n * n)
dcor = np.sqrt(dcov2_xy)/np.sqrt(np.sqrt(dcov2_xx) * np.sqrt(dcov2_yy))
return dcor
4.基於學習模型的特征排序(Model based ranking)
這種方法的思路是直接使用你要用的機器學習算法,針對每個單獨的特征和響應變量建立預測模型。如果特征與響應變量之間的關系是非線性的,則有許多替代方案,例如基於樹的方法(決策樹,隨機森林)、或者擴展的線性模型等。基於樹的方法是最簡單的方法之一,因為他們可以很好地模擬非線性關系,不需要太多的調整。但是要避免的主要是過度擬合,因此樹的深度應該相對較小,並且應該應用交叉驗證。
代碼實現
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')]
5.卡方檢驗
卡方檢驗是一種用途很廣的計數資料的假設檢驗方法,由卡爾•皮爾遜提出。卡方值描述兩個事件的獨立性或者描述實際觀察值與期望值的偏離程度。卡方值越大,表名實際觀察值與期望值偏離越大,也說明兩個事件的相互獨立性越弱。
1)原理介紹
CHI值(卡方值)用於衡量實際值與理論值的差異程度,除以T是為了避免不同觀察值與不同期望之間產生的偏差因T的不同而差別太大,所以除以E以消除這種弊端。
-
實際值與理論值偏差的絕對大小(由於平方的存在,差異被放大)
-
差異值與理論值的相對大小
2)實現流程
CHI值越大,說明兩個變量越不可能是獨立無關的,也就是說CHI值越大,兩個變量的相關程度也越高。
a. 對於特征變量x1,x2,…,xn,以及分類變量y。只需要計算CHI(x1,y)、CHI(x2,y)、…、CHI(xn,y),並按照CHI的值從大到小將特征排序。
b. 選擇合適的閾值,大於閾值的特征留下,小於閾值的特征刪除。這樣篩選出一組特征子集就是輸入模型訓練的特征。
3)只適用於分類問題中離散型特征篩選,不能用於分類問題中連續型特征的篩選,也不能用於回歸問題的特征篩選。
4)代碼實現
現實方法:
-
sklearn.feature_selection.SelectKBest:
返回k個最佳特征
-
sklearn.feature_selection.SelectPercentile:
返回表現最佳的前r%個特征
#導入sklearn庫中的SelectKBest和chi2
from sklearn.feature_selection import SelectKBest ,chi2
#選擇相關性最高的前5個特征
X_chi2 = SelectKBest(chi2, k=5).fit_transform(X, y)
X_chi2.shape
輸出:(27, 5)
0xFF 總結
-
去掉取值變化小的特征方法一般用在特征選擇前作為一個預處理的工作,即先去掉取值變化小的特征,然后再使用其他特征選擇方法選擇特征。如果機器資源充足,並且希望盡量保留所有信息,可以把閾值設置得比較高,或者只過濾離散型特征只有一個取值的特征。
-
單變量特征選擇可以用於理解數據、數據的結構、特點,也可以用於排除不相關特征,但是它不能發現冗余特征。
去掉取值變化小的特征方法和單變量特征選擇方法都屬於過濾式類特征篩選方法,但是學習算法無法向特征搜索算法傳遞對特征的需求。為了真正關注的是學習問題本身,我們將在《特征工程系列:特征篩選的原理與實現(下)》中繼續介紹Wrapper方法和Enbedded方法的原理與實現。
參考文獻:
-
[1] Feature selection – Part I: univariate selection. http://blog.datadive.net/selecting-good-features-part-i-univariate-selection/
-
[2] Selecting good features – Part II: linear models and regularization. http://blog.datadive.net/selecting-good-features-part-ii-linear-models-and-regularization/
-
[3] Feature selection. https://scikit-learn.org/stable/modules/feature_selection.html#univariate-feature-selection
-
[4] https://gist.github.com/satra/aa3d19a12b74e9ab7941