特徵工程系列:特徵篩選的原理與實現

2019-07-27     用戶77267181483

【轉】datawhale

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.Embedded方法(嵌入式)

將特徵選擇嵌入到模型訓練當中,其訓練可能是相同的模型,但是特徵選擇完成後,還能給予特徵選擇完成的特徵和模型訓練出的超參數,再次訓練優化。

主要思想:在模型既定的情況下學習出對提高模型準確性最好的特徵。也就是在確定模型的過程中,挑選出那些對模型的訓練有重要意義的特徵。

主要方法:用帶有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 總結

  1. 去掉取值變化小的特徵方法一般用在特徵選擇前作為一個預處理的工作,即先去掉取值變化小的特徵,然後再使用其他特徵選擇方法選擇特徵。如果機器資源充足,並且希望儘量保留所有信息,可以把閾值設置得比較高,或者只過濾離散型特徵只有一個取值的特徵。
  2. 單變量特徵選擇可以用於理解數據、數據的結構、特點,也可以用於排除不相關特徵,但是它不能發現冗餘特徵。

去掉取值變化小的特徵方法和單變量特徵選擇方法都屬於過濾式類特徵篩選方法,但是學習算法無法向特徵搜索算法傳遞對特徵的需求。為了真正關注的是學習問題本身,我們將在《特徵工程系列:特徵篩選的原理與實現(下)》中繼續介紹Wrapper方法和Embedded方法的原理與實現。

0x00 前言

我們在《特徵工程系列:特徵篩選的原理與實現(上)》中介紹了特徵選擇的分類,並詳細介紹了過濾式特徵篩選的原理與實現。本篇繼續介紹封裝式和嵌入式特徵篩選的原理與實現

0x01 特徵選擇實現方法三:線性模型與正則化

1.主要思想

當所有特徵在相同尺度上時,最重要的特徵應該在模型中具有最高係數,而與輸出變量不相關的特徵應該具有接近零的係數值。即使使用簡單的線性回歸模型,當數據不是很嘈雜(或者有大量數據與特徵數量相比)並且特徵(相對)獨立時,這種方法也能很好地工作。

2.正則化模型

正則化就是把額外的約束或者懲罰項加到已有模型(損失函數)上,以防止過擬合併提高泛化能力。損失函數由原來的E(X,Y)變為E(X,Y)+alpha||w||,w是模型係數組成的向量(有些地方也叫參數parameter,coefficients),||·||一般是L1或者L2範數,alpha是一個可調的參數,控制著正則化的強度。當用在線性模型上時,L1正則化和L2正則化也稱為Lasso和Ridge。

1)L1正則化/Lasso regression

L1正則化將係數w的l1範數作為懲罰項加到損失函數上,由於正則項非零,這就迫使那些弱的特徵所對應的係數變成0。因此L1正則化往往會使學到的模型很稀疏(係數w經常為0),這個特性使得L1正則化成為一種很好的特徵選擇方法。

Lasso能夠挑出一些優質特徵,同時讓其他特徵的係數趨於0。當如需要減少特徵數的時候它很有用,但是對於數據理解來說不是很好用。

2)L2正則化/Ridge regression

L2正則化將係數向量的L2範數添加到了損失函數中。

  • 由於L2懲罰項中係數是二次方的,這使得L2和L1有著諸多差異,最明顯的一點就是,L2正則化會讓係數的取值變得平均。
  • 對於關聯特徵,這意味著他們能夠獲得更相近的對應係數。
  • Ridge將回歸係數均勻的分攤到各個關聯變量上。

L2正則化對於特徵選擇來說一種穩定的模型,不像L1正則化那樣,係數會因為細微的數據變化而波動。所以L2正則化和L1正則化提供的價值是不同的,L2正則化對於特徵理解來說更加有用:表示能力強的特徵對應的係數是非零。

3.原理介紹

多元線性回歸,具有n個特徵值,預測公式如下。



多元線性回歸方程演變成求θ。

每個特徵都有對應的權重係數coef,特徵的權重係數的正負值代表特徵與目標值是正相關還是負相關,特徵的權重係數的絕對值代表重要性。

sklearn中 中LinearRegression的fit()方法就是通過訓練集求出θ,LinearRegression的兩個屬性intercept和coef分別對應θ0和θ1-θn。


4.代碼實現

1)普通線性模型

#獲取boston數據
boston=datasets.load_boston()
x=boston.data
y=boston.target
#過濾掉異常值
x=x[y<50]
y=y[y<50]
reg=LinearRegression()
reg.fit(x,y)
#求排序後的coef
coefSort=reg.coef_.argsort()
#featureNameSort: 按對標記值的影響,從小到大的各特徵值名稱
#featureCoefSore:按對標記值的影響,從小到大的coef_
featureNameSort=boston.feature_names[coefSort]
featureCoefSore=reg.coef_[coefSort]
print("featureNameSort:", featureNameSort)
print("featureCoefSore:", featureCoefSore)
# 輸出:featureNameSort: ['NOX' 'DIS' 'PTRATIO' 'LSTAT' 'CRIM' 'INDUS' 'AGE' 'TAX' 'B' 'ZN' 'RAD' 'CHAS' 'RM']
featureCoefSore: [-1.24268073e+01 -1.21088069e+00 -8.38888137e-01 -3.50952134e-01
-1.05574295e-01 -4.35179251e-02 -2.36116881e-02 -1.37702943e-02 7.93577159e-03
3.52748549e-02 2.50740082e-01 4.55405227e-01 3.75411229e+00]

結果分析:

  • 正相關影響係數最大的特徵值是」RM」:房間的平均數量,係數值為3.75。
  • 負相關影響係數最大的特徵值是」NOX」:一氧化氮濃度,係數值為-1.24。

2)L1正則化線性模型

#A helper method for pretty-printing linear models
def 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)
from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_boston
boston = 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: {}".format(
pretty_print_linear(lasso.coef_, names, sort = True)))
# 輸出:Lasso model: -3.707 * LSTAT + 2.992 * RM + -1.757 * PTRATIO
+ -1.081 * DIS + -0.7 * NOX + 0.631 * B + 0.54 * CHAS + -0.236 * CRIM
+ 0.081 * ZN + -0.0 * INDUS + -0.0 * AGE + 0.0 * RAD + -0.0 * TAX

許多特徵具有係數0。L1正則化回歸的穩定性與非正則化線性模型類似,這意味著當數據中存在相關特徵時,係數(以及特徵等級)即使在小數據變化時也會發生顯著變化。

3)L2正則化線性模型

from sklearn.linear_model import Ridge
from sklearn.metrics import r2_score
size = 100
#We run the method 10 times with different random seeds
for i in range(10):
print("Random seed {}".format(i))
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("Linear model: {}".format(pretty_print_linear(lr.coef_)))
ridge = Ridge(alpha=10)
ridge.fit(X,Y)
print("Ridge model: {}".format(pretty_print_linear(ridge.coef_)))
# 輸出
Random seed 0
Linear model: 0.728 * X0 + 2.309 * X1 + -0.082 * X2
Ridge model: 0.938 * X0 + 1.059 * X1 + 0.877 * X2
Random seed 1
Linear model: 1.152 * X0 + 2.366 * X1 + -0.599 * X2
Ridge model: 0.984 * X0 + 1.068 * X1 + 0.759 * X2
Random seed 2
Linear model: 0.697 * X0 + 0.322 * X1 + 2.086 * X2
Ridge model: 0.972 * X0 + 0.943 * X1 + 1.085 * X2
Random seed 3
Linear model: 0.287 * X0 + 1.254 * X1 + 1.491 * X2
Ridge model: 0.919 * X0 + 1.005 * X1 + 1.033 * X2
Random seed 4
Linear model: 0.187 * X0 + 0.772 * X1 + 2.189 * X2
Ridge model: 0.964 * X0 + 0.982 * X1 + 1.098 * X2
Random seed 5
Linear model: -1.291 * X0 + 1.591 * X1 + 2.747 * X2
Ridge model: 0.758 * X0 + 1.011 * X1 + 1.139 * X2
Random seed 6
Linear model: 1.199 * X0 + -0.031 * X1 + 1.915 * X2
Ridge model: 1.016 * X0 + 0.89 * X1 + 1.091 * X2
Random seed 7
Linear model: 1.474 * X0 + 1.762 * X1 + -0.151 * X2
Ridge model: 1.018 * X0 + 1.039 * X1 + 0.901 * X2
Random seed 8
Linear model: 0.084 * X0 + 1.88 * X1 + 1.107 * X2
Ridge model: 0.907 * X0 + 1.071 * X1 + 1.008 * X2
Random seed 9
Linear model: 0.714 * X0 + 0.776 * X1 + 1.364 * X2
Ridge model: 0.896 * X0 + 0.903 * X1 + 0.98 * X2

從示例中可以看出,線性回歸的係數變化很大,具體取決於生成的數據。然而,對於L2正則化模型,係數非常穩定並且密切反映數據的生成方式(所有係數接近1)。

0x02 特徵選擇實現方法四:隨機森林選擇

隨機森林具有準確率高、魯棒性好、易於使用等優點,這使得它成為了目前最流行的機器學習算法之一。隨機森林提供了兩種特徵選擇的方法:mean decrease impurity和mean decrease accuracy。

1.平均不純度減少(mean decrease impurity)

1)原理介紹

  • 隨機森林由多顆CART決策樹構成,決策樹中的每一個節點都是關於某個特徵的條件,為的是將數據集按照不同的響應變量一分為二。
  • CART利用不純度可以確定節點(最優條件),對於分類問題,通常採用基尼不純度,對於回歸問題,通常採用的是方差或者最小二乘擬合。
  • 當訓練決策樹的時候,可以計算出每個特徵減少了多少樹的不純度。對於一個決策樹森林來說,可以算出每個特徵平均減少了多少不純度,並把它平均減少的不純度作為特徵選擇的標準。
  • 隨機森林基於不純度的排序結果非常鮮明,在得分最高的幾個特徵之後的特徵,得分急劇的下降。

2)代碼實現

from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
import numpy as np
#Load boston housing dataset as an example
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
# 訓練隨機森林模型,並通過feature_importances_屬性獲取每個特徵的重要性分數。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))

2.平均精確度減少(mean decrease accuracy)

1)原理介紹

  • 通過直接度量每個特徵對模型精確率的影響來進行特徵選擇。
  • 主要思路是打亂每個特徵的特徵值順序,並且度量順序變動對模型的精確率的影響。
  • 對於不重要的變量來說,打亂順序對模型的精確率影響不會太大。
  • 對於重要的變量來說,打亂順序就會降低模型的精確率。

2)代碼實現

from sklearn.cross_validation import ShuffleSplit
from sklearn.metrics import r2_score
from collections import defaultdict
X = boston["data"]
Y = boston["target"]
rf = RandomForestRegressor()
scores = defaultdict(list)
#crossvalidate the scores on a number of different random splits of the data
for 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]
# 使用修改前的原始特徵訓練模型,其acc作為後續混洗特徵值後的對比標準。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))

0x03 特徵選擇實現方法五:頂層特徵選擇

頂層特徵選擇發建立在基於模型的特徵選擇方法基礎之上的,例如線性回歸和SVM等,在不同的子集上建立模型,然後匯總最終確定特徵得分。

1.穩定性選擇(Stability selection)

穩定性選擇常常是一種既能夠有助於理解數據又能夠挑出優質特徵的這種選擇。

1)原理介紹

  • 穩定性選擇是一種基於二次抽樣和選擇算法相結合較新的方法,選擇算法可以是回歸、SVM或其他類似的方法。
  • 它的主要思想是在不同的數據子集和特徵子集上運行特徵選擇算法,不斷的重複,最終匯總特徵選擇結果。比如可以統計某個特徵被認為是重要特徵的頻率(被選為重要特徵的次數除以它所在的子集被測試的次數)。
  • 理想情況下,重要特徵的得分會接近100%。稍微弱一點的特徵得分會是非0的數,而最無用的特徵得分將會接近於0。

2)代碼實現

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("Features sorted by their score:")
print(sorted(zip(map(lambda x: round(x, 4), rlasso.scores_), names),
reverse=True))

2.遞歸特徵消除(Recursive feature elimination,RFE)

1)原理介紹

  • 遞歸特徵消除的主要思想是反覆的構建模型(如SVM或者回歸模型)然後選出最好的(或者最差的)的特徵(可以根據係數來選),把選出來的特徵放到一遍,然後在剩餘的特徵上重複這個過程,直到所有特徵都遍歷了。
  • 這個過程中特徵被消除的次序就是特徵的排序。因此,這是一種尋找最優特徵子集的貪心算法。
  • RFE的穩定性很大程度上取決於在疊代的時候底層用哪種模型。
  • 假如RFE採用的普通的回歸,沒有經過正則化的回歸是不穩定的,那麼RFE就是不穩定的。
  • 假如RFE採用的是Ridge,而用Ridge正則化的回歸是穩定的,那麼RFE就是穩定的。

2)代碼實現

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"]
#use linear regression as the model
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("Features sorted by their rank:")
print(sorted(zip(map(lambda x: round(x, 4), rfe.ranking_), names)))
結果輸出
Features sorted by their rank:
[(1, 'NOX'), (2, 'RM'), (3, 'CHAS'), (4, 'PTRATIO'), (5, 'DIS'),
(6, 'LSTAT'), (7, 'RAD'), (8, 'CRIM'), (9, 'INDUS'), (10, 'ZN'),
(11, 'TAX'), (12, 'B'), (13, 'AGE')]

0xFF 總結

  1. 單變量特徵選擇可以用於理解數據、數據的結構、特點,也可以用於排除不相關特徵,但是它不能發現冗餘特徵。
  2. 正則化的線性模型可用於特徵理解和特徵選擇。相比起L1正則化,L2正則化的表現更加穩定,L2正則化對於數據的理解來說很合適。由於響應變量和特徵之間往往是非線性關係,可以採用basis expansion的方式將特徵轉換到一個更加合適的空間當中,在此基礎上再考慮運用簡單的線性模型。
  3. 隨機森林是一種非常流行的特徵選擇方法,它易於使用。但它有兩個主要問題:
  • 重要的特徵有可能得分很低(關聯特徵問題)
  • 這種方法對特徵變量類別多的特徵越有利(偏向問題)
  1. 特徵選擇在很多機器學習和數據挖掘場景中都是非常有用的。在使用的時候要弄清楚自己的目標是什麼,然後找到哪種方法適用於自己的任務。
  • 當選擇最優特徵以提升模型性能的時候,可以採用交叉驗證的方法來驗證某種方法是否比其他方法要好。
  • 當用特徵選擇的方法來理解數據的時候要留心,特徵選擇模型的穩定性非常重要,穩定性差的模型很容易就會導致錯誤的結論。
  • 對數據進行二次採樣然後在子集上運行特徵選擇算法能夠有所幫助,如果在各個子集上的結果是一致的,那就可以說在這個數據集上得出來的結論是可信的,可以用這種特徵選擇模型的結果來理解數據。
  1. 關於訓練模型的特徵篩選,個人建議的實施流程 :
  2. 數據預處理後,先排除取值變化很小的特徵。如果機器資源充足,並且希望儘量保留所有信息,可以把閾值設置得比較高,或者只過濾離散型特徵只有一個取值的特徵。
  3. 如果數據量過大,計算資源不足(內存不足以使用所有數據進行訓練、計算速度過慢),可以使用單特徵選擇法排除部分特徵。這些被排除的特徵並不一定完全被排除不再使用,在後續的特徵構造時也可以作為原始特徵使用。
  4. 如果此時特徵量依然非常大,或者是如果特徵比較稀疏時,可以使用PCA(主成分分析)和LDA(線性判別)等方法進行特徵降維。
  5. 經過樣本採樣和特徵預篩選後,訓練樣本可以用於訓練模型。但是可能由於特徵數量比較大而導致訓練速度慢,或者想進一步篩選有效特徵或排除無效特徵(或噪音),我們可以使用正則化線性模型選擇法、隨機森林選擇法或者頂層特徵選擇法進一步進行特徵篩選。

最後,特徵篩選是為了理解數據或更好地訓練模型,我們應該根據自己的目標來選擇適合的方法。為了更好/更容易地訓練模型而進行的特徵篩選,如果計算資源充足,應儘量避免過度篩選特徵,因為特徵篩選很容易丟失有用的信息。如果只是為了減少無效特徵的影響,為了避免過擬合,可以選擇隨機森林和XGBoost等集成模型來避免對特徵過擬合。

文章來源: https://twgreatdaily.com/XuGmQWwB8g2yegNDnVE5.html