機器學習 (四): 特徵選擇


本博客是 <Machine Learing With Python> 一書 chapter 10 的讀書筆記

概述

特徵選擇即去掉對模型沒有價值的特徵, 根據手段不同可分爲三類:

  1. filter: 字面意思是過濾, 原理是根據統計特徵 (方差, 協方差, χ2\chi^2等) 按照一定閾值或者排名直接選擇特徵; 這種方法比較簡單, 就和過濾一樣沒什麼技術含量.
  2. wrapper: 字面意思是封裝, 原理是用你的模型不斷嘗試特徵的各個子集, 直到找到一個特徵最少且性能最好的子集; 我認爲 wrapper 的意思就是說不像 filter 一樣用一個簡單的統計屬性, 而是用一個複雜的函數 (即你的模型的封裝) 來衡量特徵的好壞.
  3. embedded: 有些學習算法, 如 AdaBoost 在訓練過程中會自動修改各個特徵的權重, embedded 方法即爲將特徵選擇過程嵌入到模型訓練過程中, 根據訓練的結果再從中選擇權重最大的幾個特徵 (由於本章中沒有提及該方法的具體實現, 所以本博客也不會對該方法進行詳細說明)

Filter 方法

根據方差

方差用來衡量一個隨機變量的離散程度, 方差越小表示該變量越穩定, 一般認爲 (但是我不贊成) 方差小的特徵含的信息量較小

直接根據一個閾值來濾掉特徵:

from sklearn.datasets import load_iris
from sklearn.feature_selection import VarianceThreshold
import numpy as np

data = load_iris().data
# 原本的特徵數量
print('orig dim: ', data.shape[1])
# 每個特徵的方差
print('var: ', data.var(axis=0))
# 以0.5爲閾值過濾後的特徵數量
print('new dim: ', VarianceThreshold(0.5).fit_transform(data).shape[1])

輸出

orig dim:  4
var:  [0.68112222 0.18871289 3.09550267 0.57713289]
new dim:  3

我們發現第二個特徵方差最小.
但是, 因爲方差的大小和數據的scale成平方關係, 所以在計算方差前應將特徵縮放到同一取值範圍

from sklearn.datasets import load_iris
from sklearn.preprocessing import maxabs_scale
import numpy as np

data = maxabs_scale(load_iris().data)
print('var: ', data.var(axis=0))

輸出

var:  [0.01091367 0.00974757 0.06501791 0.09234126]

我們發現縮放後四個特徵的方差都差不多. 此時就很難找到一個好的閾值來進行過濾了.

我個人認爲, 根據方差來選擇特徵是一個非常幼稚的想法, 特徵本身的發散程度和target並沒有相關性, 反而有時候恰恰是方差小的特徵纔是決定target的關鍵.

根據協方差

有些特徵之間可能會彼此相關, 在統計上表現爲二者之間的協方差很高, 此時需要去掉冗餘的特徵.

import pandas as pd
import numpy as np
import seaborn as sns

%matplotlib inline

a = np.stack([np.arange(10), np.arange(10) // 2 * 2, np.random.rand(10)]).T
a = pd.DataFrame(a)
a = np.triu(a.corr().abs())

sns.heatmap(a)


我們發現特徵0和特徵1的協方差很高 (接近1), 因此可以去掉2或者1的其中之一.

根據χ2\chi^2

χ2\chi^2檢驗 (針對離散特徵) 的邏輯就是對某一特徵與樣本標籤進行獨立性檢驗, 如果二者相互獨立, 那麼χ2=0\chi^2=0, 否則相關性與其值成正比.

from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

SelectKBest(chi2, 2).fit_transform(load_iris().data, load_iris().target)

Wrapper 方法

RFECV

全稱 Recursive Feature Elimination using Cross Validation
邏輯很簡單, 即用你想要訓練的模型, 先用全部特徵訓練, 然後逐步減少特徵, 每次訓練通過交叉驗證的方式來打分, 從而可以得到一個特徵最少, 得分最高的方案.

from sklearn.datasets import make_regression
from sklearn.feature_selection import RFECV
from sklearn import datasets, linear_model

# 創建一個用於線性迴歸的數據集, 其中有100個特徵, 但只有兩個是真正有用的
features, target = make_regression( n_samples = 1000,
                                    n_features = 100,
                                    n_informative = 2
                                  )
model = linear_model.LinearRegression()

refcv = RFECV(estimator=model, step=1, scoring="neg_mean_squared_error", cv = 5)
refcv.fit(features, target)
refcv.transform(features)

print(refcv.n_features_)

輸出

2

總結

特徵選擇這個工作是特徵工程中最爲重要的步驟, 但是這個步驟依靠的更多的是經驗和深入挖掘, sklearn 提供的 feature_selection 庫中的函數往往只能作爲粗略的預處理步驟 (比如從上千個特徵中選取一百個較爲重要的出來), 更進一步的處理還需要依靠自己.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章