目錄html
更新、更全的《機器學習》的更新網站,更有python、go、數據結構與算法、爬蟲、人工智能教學等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlpython
特徵工程在工業上有這麼一句廣爲流傳的話:數據和特徵決定了機器學習的上限,而模型和算法只是逼近這個上限而已。接下來將給你介紹特徵工程的第一個分支,特徵選擇。算法
對於一個學習任務來講,若是某一個特徵和咱們的學習任務沒有太大關係,咱們把它稱之爲無關特徵(irrelevant feature),如我的長相和財富自由;若是某一個特徵和咱們的學習任務有太大關係,咱們把它稱之爲相關特徵(relevant feature),而咱們接下來要講的特徵選擇(feature select)則是要從給定的原生特徵集合彙總選出相關特徵的子集,即篩選掉無關特徵。數據結構
篩選掉無關特徵通常是在訓練模型以前,因此特徵選擇也屬於構建機器學習系統中的數據預處理。dom
若是咱們有一個學習任務是爲了分析一我的具有什麼條件更可能財富自由,讓咱們想象一下,雖然你可能想象不到,我就直說了,這個社會上財富自由的人我的長相通常般的有不少;我的長相挺漂亮的如明星也會有很;我的長相相比較不隨時代潮流的也會有,這能夠必定程度上代表我的是否能財富自由和我的長相沒有關係。機器學習
可是咱們可能再對我的條件數據挖掘的時候,把這一個特徵也當作影響模型準確度的條件之一,若是隻有幾個維度的特徵,或幾個無關特徵,咱們計算機能夠應付的過來,可是若是出現維數災難的時候,每多一個無關特徵對咱們的計算機來講,計算量都是龐大的,這個時候咱們就得考慮過濾掉這些可能無心義的特徵了,畢竟若將紛繁複雜的因素抽絲剝繭,只留下關鍵因素,真相每每容易看清。性能
上述所說的長相多是經過咱們認知判斷出來的,工業上可沒有這麼多能夠經過認知判斷出來的無關特徵,而咱們所要講述的特徵選擇乾的就是這件事。學習
上一節講到了特徵選擇的任務是儘量的過濾掉無關特徵,可是除了無關特徵以外,有時候咱們還會碰到冗餘特徵(redundant feature)。優化
冗餘特徵能夠理解爲能夠從其餘特徵中推演出來的特徵,好比咱們正在考慮立方體對象,若是咱們有了立方體地面寬\(a\)和底面長\(b\)這兩個特徵,若是再給咱們立方體底面的面積\(S\)的話,則這個面積\(S\)即爲冗餘特徵。可是若是咱們的學習任務是爲了計算一個立方體的體積\(V\),經過立方體體積公式能夠知道給咱們\(S\)比給咱們\(a\)和\(b\)更好,由於給了\(a\)和\(b\)咱們還須要計算出\(S\)。對於這種冗餘特徵能夠考慮特徵與特徵之間的相關性。網站
還有一種冗餘特徵,如學生的成績只分爲及格和不及格,有時候咱們能夠只考慮及格的學生狀況,由於沒考慮到及格狀況的學生就是不及格,這樣也能夠適當的進行特徵選擇。
過濾式選擇主要是,經過不一樣的方法去檢測特徵與樣本之間的相關度,而後依據不一樣方法的檢驗規則篩選特徵。對特徵過濾以後再訓練模型。
卡方檢驗能夠檢驗某個特徵分佈與輸出值分佈之間的相關性,咱們能夠給定卡方值閾值,選擇過濾掉卡方值較大的部分特徵。經過也能夠經過p值判斷,p值爲結果爲可信程度的一個遞減指標,p值越大,咱們越不能認爲樣本中變量的關聯是整體中各變量關聯的可靠指標。
# 卡方檢驗示例 import numpy as np from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 X = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]] y = np.array([[2], [4], [5]])
# 使用SelectKBest進行特徵選擇 selector = SelectKBest(score_func=chi2, k=4) selector = selector.fit(X, y) print('卡方值:{}'.format(selector.scores_))
卡方值:[nan 0.5 5.2 0. ]
# 直接使用chi2類獲取chi_values值 chi_value, p_value = chi2(X, y) print('卡方值:{}\np值:{}'.format(chi_value, p_value))
卡方值:[nan 0.5 5.2 0. ] p值:[ nan 0.77880078 0.07427358 1. ]
首先咱們能夠計算出全部特徵的方差\(D(x_i)\quad(i=1,2,\cdots,n)\),而後給定一個方差閾值\(\epsilon\),若是\(D(x_i)>\epsilon\),則該保留該特徵,反之,過濾掉該特徵。通常方差小於1,特徵對模型的做用可能並不大;若是方差爲0,即全部樣本的特徵取值都是同樣的,則該特徵必定是無用的,能夠直接捨棄。同理可使用from sklearn.feature_selection import SelectKBest
選擇特徵,此處很少贅述。
# 方差過濾示例 from sklearn.feature_selection import VarianceThreshold X = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]] selector = VarianceThreshold()
print('經過方差過濾特徵:\n{}'.format(selector.fit_transform(X, y)))
經過方差過濾特徵: [[2 0] [1 4] [1 1]]
曾經在線性迴歸代碼中,咱們使用過該方法。咱們能夠計算訓練集中樣本特徵與輸出值之間的相關度,選擇相關度較大的部分特徵,此處我麼選擇pearsonr係數舉例。
對於pearsonr係數,它衡量的是變量之間的線性相關性,取值範圍爲\([-1,1]\),其中1表明變量徹底正相關,-1表明徹底負相關。
# 相關係數過濾示例 import numpy as np import scipy as sc a = [1, 2, 3, 4] b = [2, 3, 6, 9] c = [-2, -4, -6, -7] a = np.array(a) b = np.array(b) c = np.array(c)
print('a和b之間的皮爾遜相關係數:{}'.format(sc.stats.pearsonr(a, b)[0])) print('a和c之間的皮爾遜相關係數:{}'.format(sc.stats.pearsonr(a, c)[0]))
a和b之間的皮爾遜相關係數:0.9797958971132713 a和c之間的皮爾遜相關係數:-0.9897782665572894
F檢驗,最經常使用的別名叫作聯合假設檢驗(joint hypotheses test),此外也稱方差比率檢驗、方差齊性檢驗,通產如卡方檢驗,給定F值閾值,選擇F值較大的部分特徵。F檢驗能夠檢驗分類和迴歸問題,在scikit-learn庫中分別對應from sklearn.feature_selection import f_classif
和from sklearn.feature_selection import f_regression
此處只給出迴歸問題的代碼,而且同理可使用from sklearn.feature_selection import SelectKBest
選擇特徵,此處很少贅述。
# F檢驗示例 import numpy as np from sklearn.feature_selection import f_classif from sklearn.feature_selection import f_regression X = [[1, 2, 4, 3], [2, 1, 4, 3], [3, 1, 1, 4]] y = np.array([[2], [4], [5]]).ravel()
f_value, p_value = f_regression(X, y) print('f_value:{}\np_value:{}'.format(f_value, p_value))
f_value:[27. 8.33333333 1.33333333 1.33333333] p_value:[0.12103772 0.21229562 0.45437105 0.45437105]
互信息即信息增益,互信息值越大,說明該特徵和輸出值之間的相關性越大,即篩選掉互信息值較小的特徵。通常能夠計算分類和迴歸問題中特徵與輸出之間的互信息,在scikit-learn庫中分別對應from sklearn.feature_selection import mutual_info_classif
和from sklearn.feature_selection import mutual_info_regression
,此處只給出迴歸問題的代碼,而且同理可使用from sklearn.feature_selection import SelectKBest
選擇特徵,此處很少贅述。
# 互信息過濾示例 import numpy as np from sklearn.feature_selection import mutual_info_regression from sklearn.feature_selection import mutual_info_classif X = [[1., 2., 4., 3.], [2., 1., 4., 3.], [3., 1., 1., 4.]] y = np.array([[2.], [4.], [5.]]).ravel()
mi = mutual_info_regression(X, y, n_neighbors=1) print('mi:{}'.format(mi))
mi:[0.5 0.16666667 0. 0.16666667]
包裹式選擇並非直接對特徵進行選擇,而是把最終將要使用的學習器的性能做爲特徵子集的評價標準,即選擇最有利於學習器性能的特徵子集。
包裹式選擇從學習器性能上看,較於過濾式特徵選擇會更好,可是因爲是從不一樣的學習器中選擇最優的學習器,須要訓練多個學習器,所以計算機的計算開銷較於過濾式特徵選擇會大不少。
遞歸特徵消除能夠理解成,沒訓練一次模型,消除若干個權值係數較小的特徵,而後基於新的特徵值進行下一輪訓練,不斷重複上述的過程。
咱們以較爲經典的SVM-REF舉例,SVM在第一輪訓練的時候,獲得超平面\(S=w^Tx+b=0\),若是每一個訓練數據有\(n\)個特徵,則SVM-REF會消除\(n\)個特徵中\({w_i}^2,\quad(i=1,2,\cdots,n)\)最小的特徵,所以特徵數將變成\(n-1\)個,而後對訓練集繼續訓練,使用上述方法將特徵變成\(n-2\)個……
在scikit-learn庫中可使用from sklearn.feature_selection import RFE
和from sklearn.feature_selection import RFECV
方法用於遞歸特徵消除,此處使用CV方法讓模型自動消除指定個數的特徵。
# 遞歸特徵消除示例 from sklearn.datasets import make_friedman1 from sklearn.feature_selection import RFECV from sklearn.svm import SVR # 生成10維特徵的50個樣本 X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) estimator = SVR(kernel="linear") selector = RFECV(estimator, step=1, cv=4) selector = selector.fit(X, y)
print('特徵個數:{}'.format(selector.n_features_))
特徵個數:6
print('被選定的特徵:{}'.format(selector.support_))
被選定的特徵:[ True True True True True False False False True False]
print('特徵排名:{}'.format(selector.ranking_))
特徵排名:[1 1 1 1 1 5 3 2 1 4]
嵌入式特徵選擇是將特徵選擇過程與學習器訓練過程融爲一體,即二者在同一個優化過程當中完成。嵌入式特徵通常須要能獲得特徵權重係數或特徵重要度的學習器,也就是說如線性迴歸、邏輯迴歸、決策樹、隨機森林均可以做爲嵌入式特徵選的學習器。
一般使用最多的是L1正則化和L2正則化,在線性迴歸的正則化中講到,L1和L2正則化能夠解決過擬合問題,可是L1和L2正則化有時候也被用來作特徵選擇。當正則化係數越大的時候,對模型的懲罰力度也越大,所以會致使特徵的權重係數變成0,這樣特徵對於模型而言就沒有意義了,所以便達到了特徵選擇的目的。
在scikit-learn庫中可使用from sklearn.feature_selection import SelectFromModel
來選擇特徵,此處使用L1正則化和隨機森林舉例。
# 嵌入式選擇示例 from sklearn.datasets import make_friedman1 from sklearn.linear_model import Lasso from sklearn.ensemble import RandomForestRegressor from sklearn.feature_selection import SelectFromModel X, y = make_friedman1(n_samples=100, n_features=10, random_state=0) # 有係數的線性模型中,L1正則化可生成一個稀疏矩陣 lasso = Lasso() lasso.fit(X, y) model = SelectFromModel(lasso) new_X = model.fit(X, y) print('L1正則化:{}'.format(new_X.get_support())) # 無係數的模型中,根據重要性篩選無關特徵 rf = RandomForestRegressor(n_estimators=10) rf.fit(X, y) model = SelectFromModel(rf) new_X = model.fit(X, y) print('隨機森林:{}'.format(new_X.get_support()))
L1正則化:[False False False True False False False False False False] 隨機森林:[ True False False True False False False False False False]
高級特徵能夠理解成,訓練數據特徵沒有給咱們的信息,就那冗餘特徵中的例子舉例,若是獲得了正方體的邊長\(a\),進而能夠獲得正方體的某一個面的表面積\(S=a^2\),進而又能夠獲得立方體的體積\(V=a^3\),進而能夠獲得…也就是說,高級特徵能夠一直找下去。這也必定程度說明了冗餘特徵有時候也多是有益特徵,因此對冗餘特徵作處理也須要多多考慮。
在Kaggle之類的算法競賽中,高分團隊主要使用的方法除了集成學習算法,剩下的主要就是在尋找高級特徵。因此尋找高級特徵通常是模型優化的必要步驟之一。可是須要注意的是,在第一次創建模型的時候,咱們能夠先不尋找高級特徵,獲得之後基準模型後,再尋找高級特徵進行優化。
上述只是簡單的舉例能夠如此尋找高級特徵,工業上可能用的就不是如此簡單方法找高級特徵,不一樣的問題有不一樣的尋找高級特徵的方法。而後在找高級特徵的時候須要注意的是,尋找高級特徵的過程會極大的增長特徵維度,這個也是須要考慮的。若是能夠的話,解決聚類問題時高級特徵儘可能少一點,解決分類迴歸問題時高級特徵能夠多一點。
特徵選擇是特徵工程中很重要的一步,不只能很大程度的獲取重要特徵,並在必定程度上下降維數災難帶來的風險,細心地同窗會發現咱們特徵選擇的基礎是創建在,原始數據都比較完美的狀況,接下來咱們將聊一聊數據不完美的狀況該如何處理,我知道你可能想問:什麼是數據不完美呢?下一篇特徵預處理將告訴你答案。