目錄
1 特征工程是什么?
2 數(shù)據(jù)預(yù)處理
2.1 無量綱化
2.1.1 標(biāo)準(zhǔn)化
2.1.2 區(qū)間縮放法
2.1.3 標(biāo)準(zhǔn)化與歸一化的區(qū)別
2.2 對(duì)定量特征二值化
2.3 對(duì)定性特征啞編碼
2.4 缺失值計(jì)算
2.5 數(shù)據(jù)變換3 特征選擇
3.1 Filter
3.1.1 方差選擇法
3.1.2 相關(guān)系數(shù)法
3.1.3 卡方檢驗(yàn)
3.1.4 互信息法
3.2 Wrapper
3.2.1 遞歸特征消除法
3.3 Embedded
3.3.1 基于懲罰項(xiàng)的特征選擇法
3.3.2 基于樹模型的特征選擇法4 降維
4.1 主成分分析法(PCA)
4.2 線性判別分析法(LDA)
5 總結(jié)
6 參考資料
1 特征工程是什么?
有這么一句話在業(yè)界廣泛流傳:數(shù)據(jù)和特征決定了機(jī)器學(xué)習(xí)的上限,而模型和算法只是逼近這個(gè)上限而已。那特征工程到底是什么呢?顧名思義,其本質(zhì)是一項(xiàng)工程活動(dòng),目的是最大限度地從原始數(shù)據(jù)中提取特征以供算法和模型使用。通過總結(jié)和歸納,人們認(rèn)為特征工程包括以下方面:

特征處理是特征工程的核心部分,sklearn提供了較為完整的特征處理方法,包括數(shù)據(jù)預(yù)處理,特征選擇,降維等。首次接觸到sklearn,通常會(huì)被其豐富且方便的算法模型庫吸引,但是這里介紹的特征處理庫也十分強(qiáng)大!
本文中使用sklearn中的IRIS(鳶尾花)數(shù)據(jù)集來對(duì)特征處理功能進(jìn)行說明。IRIS數(shù)據(jù)集由Fisher在1936年整理,包含4個(gè)特征(Sepal.Length(花萼長度)、Sepal.Width(花萼寬度)、Petal.Length(花瓣長度)、Petal.Width(花瓣寬度)),特征值都為正浮點(diǎn)數(shù),單位為厘米。目標(biāo)值為鳶尾花的分類(Iris Setosa(山鳶尾)、Iris Versicolour(雜色鳶尾),Iris Virginica(維吉尼亞鳶尾))。導(dǎo)入IRIS數(shù)據(jù)集的代碼如下:
from sklearn.datasets import load_iris
#導(dǎo)入IRIS數(shù)據(jù)集
iris = load_iris()
#特征矩陣
iris.data
#目標(biāo)向量
iris.target
2 數(shù)據(jù)預(yù)處理
通過特征提取,我們能得到未經(jīng)處理的特征,這時(shí)的特征可能有以下問題:
- 不屬于同一量綱:即特征的規(guī)格不一樣,不能夠放在一起比較。無量綱化可以解決這一問題。
- 信息冗余:對(duì)于某些定量特征,其包含的有效信息為區(qū)間劃分,例如學(xué)習(xí)成績,假若只關(guān)心“及格”或不“及格”,那么需要將定量的考分,轉(zhuǎn)換成“1”和“0”表示及格和未及格。二值化可以解決這一問題。
- 定性特征不能直接使用:某些機(jī)器學(xué)習(xí)算法和模型只能接受定量特征的輸入,那么需要將定性特征轉(zhuǎn)換為定量特征。最簡單的方式是為每一種定性值指定一個(gè)定量值,但是這種方式過于靈活,增加了調(diào)參的工作。通常使用啞編碼的方式將定性特征轉(zhuǎn)換為定量特征:假設(shè)有N種定性值,則將這一個(gè)特征擴(kuò)展為N種特征,當(dāng)原始特征值為第i種定性值時(shí),第i個(gè)擴(kuò)展特征賦值為1,其他擴(kuò)展特征賦值為0。啞編碼的方式相比直接指定的方式,不用增加調(diào)參的工作,對(duì)于線性模型來說,使用啞編碼后的特征可達(dá)到非線性的效果。
- 存在缺失值:缺失值需要補(bǔ)充。
- 信息利用率低:不同的機(jī)器學(xué)習(xí)算法和模型對(duì)數(shù)據(jù)中信息的利用是不同的,之前提到在線性模型中,使用對(duì)定性特征啞編碼可以達(dá)到非線性的效果。類似地,對(duì)定量變量多項(xiàng)式化,或者進(jìn)行其他的轉(zhuǎn)換,都能達(dá)到非線性的效果。
我們使用sklearn中的preproccessing庫來進(jìn)行數(shù)據(jù)預(yù)處理,可以覆蓋以上問題的解決方案。
2.1 無量綱化
無量綱化使不同規(guī)格的數(shù)據(jù)轉(zhuǎn)換到同一規(guī)格。常見的無量綱化方法有標(biāo)準(zhǔn)化和區(qū)間縮放法。標(biāo)準(zhǔn)化的前提是特征值服從正態(tài)分布,標(biāo)準(zhǔn)化后,其轉(zhuǎn)換成標(biāo)準(zhǔn)正態(tài)分布。區(qū)間縮放法利用了邊界值信息,將特征的取值區(qū)間縮放到某個(gè)特點(diǎn)的范圍,例如[0, 1]等。
2.1.1 標(biāo)準(zhǔn)化
標(biāo)準(zhǔn)化需要計(jì)算特征的均值和標(biāo)準(zhǔn)差,公式表達(dá)為:
使用preproccessing庫的StandardScaler類對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化的代碼如下:

from sklearn.preprocessing import StandardScaler
#標(biāo)準(zhǔn)化,返回值為標(biāo)準(zhǔn)化后的數(shù)據(jù)
StandardScaler().fit_transform(iris.data)
2.1.2 區(qū)間縮放法
區(qū)間縮放法的思路有多種,常見的一種為利用兩個(gè)最值進(jìn)行縮放,公式表達(dá)為:
使用preproccessing庫的MinMaxScaler類對(duì)數(shù)據(jù)進(jìn)行區(qū)間縮放的代碼如下:

from sklearn.preprocessing import MinMaxScaler
#區(qū)間縮放,返回值為縮放到[0, 1]區(qū)間的數(shù)據(jù)
MinMaxScaler().fit_transform(iris.data)
2.1.3 標(biāo)準(zhǔn)化與歸一化的區(qū)別
簡單來說,標(biāo)準(zhǔn)化是依照特征矩陣的列處理數(shù)據(jù),其通過求z-score的方法,將樣本的特征值轉(zhuǎn)換到同一量綱下。歸一化是依照特征矩陣的行處理數(shù)據(jù),其目的在于樣本向量在點(diǎn)乘運(yùn)算或其他核函數(shù)計(jì)算相似性時(shí),擁有統(tǒng)一的標(biāo)準(zhǔn),也就是說都轉(zhuǎn)化為“單位向量”。規(guī)則為l2的歸一化公式如下:

使用preproccessing庫的Normalizer類對(duì)數(shù)據(jù)進(jìn)行歸一化的代碼如下:
from sklearn.preprocessing import Normalizer
#歸一化,返回值為歸一化后的數(shù)據(jù)
Normalizer().fit_transform(iris.data)
2.2 對(duì)定量特征二值化
定量特征二值化的核心在于設(shè)定一個(gè)閾值,大于閾值的賦值為1,小于等于閾值的賦值為0,公式表達(dá)如下:

使用preproccessing庫的Binarizer類對(duì)數(shù)據(jù)進(jìn)行二值化的代碼如下:
from sklearn.preprocessing import Binarizer
#二值化,閾值設(shè)置為3,返回值為二值化后的數(shù)據(jù)
Binarizer(threshold=3).fit_transform(iris.data)
2.3 對(duì)定性特征啞編碼
由于IRIS數(shù)據(jù)集的特征皆為定量特征,故使用其目標(biāo)值進(jìn)行啞編碼(實(shí)際上是不需要的)。使用preproccessing庫的OneHotEncoder類對(duì)數(shù)據(jù)進(jìn)行啞編碼的代碼如下:
from sklearn.preprocessing import OneHotEncoder
# 啞編碼,對(duì)IRIS數(shù)據(jù)集的目標(biāo)值,返回值為啞編碼后的數(shù)據(jù)
OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))
2.4 缺失值計(jì)算
由于IRIS數(shù)據(jù)集沒有缺失值,故對(duì)數(shù)據(jù)集新增一個(gè)樣本,4個(gè)特征均賦值為NaN,表示數(shù)據(jù)缺失。使用preproccessing庫的Imputer類對(duì)數(shù)據(jù)進(jìn)行缺失值計(jì)算的代碼如下:
from numpy import vstack, array, nan
from sklearn.preprocessing import Imputer
#缺失值計(jì)算,返回值為計(jì)算缺失值后的數(shù)據(jù)
#參數(shù)missing_value為缺失值的表示形式,默認(rèn)為NaN
#參數(shù)strategy為缺失值填充方式,默認(rèn)為mean(均值)
Imputer().fit_transform(vstack((array([nan, nan, nan, nan]), iris.data)))
2.5 數(shù)據(jù)變換
常見的數(shù)據(jù)變換有基于多項(xiàng)式的、基于指數(shù)函數(shù)的、基于對(duì)數(shù)函數(shù)的。4個(gè)特征,度為2的多項(xiàng)式轉(zhuǎn)換公式如下:

使用preproccessing庫的PolynomialFeatures類對(duì)數(shù)據(jù)進(jìn)行多項(xiàng)式轉(zhuǎn)換的代碼如下:
from sklearn.preprocessing import PolynomialFeatures
#多項(xiàng)式轉(zhuǎn)換
#參數(shù)degree為度,默認(rèn)值為2
PolynomialFeatures().fit_transform(iris.data)
基于單變元函數(shù)的數(shù)據(jù)變換可以使用一個(gè)統(tǒng)一的方式完成,使用preproccessing庫的FunctionTransformer對(duì)數(shù)據(jù)進(jìn)行對(duì)數(shù)函數(shù)轉(zhuǎn)換的代碼如下:
from numpy import log1p
from sklearn.preprocessing import FunctionTransformer
#自定義轉(zhuǎn)換函數(shù)為對(duì)數(shù)函數(shù)的數(shù)據(jù)變換
#第一個(gè)參數(shù)是單變元函數(shù)
FunctionTransformer(log1p).fit_transform(iris.data)
3 特征選擇
當(dāng)數(shù)據(jù)預(yù)處理完成后,我們需要選擇有意義的特征輸入機(jī)器學(xué)習(xí)的算法和模型進(jìn)行訓(xùn)練。通常來說,從兩個(gè)方面考慮來選擇特征:
- 特征是否發(fā)散:如果一個(gè)特征不發(fā)散,例如方差接近于0,也就是說樣本在這個(gè)特征上基本上沒有差異,這個(gè)特征對(duì)于樣本的區(qū)分并沒有什么用。
- 特征與目標(biāo)的相關(guān)性:這點(diǎn)比較顯見,與目標(biāo)相關(guān)性高的特征,應(yīng)當(dāng)優(yōu)選選擇。除方差法外,本文介紹的其他方法均從相關(guān)性考慮。
根據(jù)特征選擇的形式又可以將特征選擇方法分為3種:
- Filter:過濾法,按照發(fā)散性或者相關(guān)性對(duì)各個(gè)特征進(jìn)行評(píng)分,設(shè)定閾值或者待選擇閾值的個(gè)數(shù),選擇特征。
- Wrapper:包裝法,根據(jù)目標(biāo)函數(shù)(通常是預(yù)測效果評(píng)分),每次選擇若干特征,或者排除若干特征。
- Embedded:嵌入法,先使用某些機(jī)器學(xué)習(xí)的算法和模型進(jìn)行訓(xùn)練,得到各個(gè)特征的權(quán)值系數(shù),根據(jù)系數(shù)從大到小選擇特征。類似于Filter方法,但是是通過訓(xùn)練來確定特征的優(yōu)劣。
我們使用sklearn中的feature_selection庫來進(jìn)行特征選擇。
3.1 Filter
3.1.1 方差選擇法
使用方差選擇法,先要計(jì)算各個(gè)特征的方差,然后根據(jù)閾值,選擇方差大于閾值的特征。使用feature_selection庫的VarianceThreshold類來選擇特征的代碼如下:
from sklearn.feature_selection import VarianceThreshold
#方差選擇法,返回值為特征選擇后的數(shù)據(jù)
#參數(shù)threshold為方差的閾值
VarianceThreshold(threshold=3).fit_transform(iris.data)
3.1.2 相關(guān)系數(shù)法
使用相關(guān)系數(shù)法,先要計(jì)算各個(gè)特征對(duì)目標(biāo)值的相關(guān)系數(shù)以及相關(guān)系數(shù)的P值。用feature_selection庫的SelectKBest類結(jié)合相關(guān)系數(shù)來選擇特征的代碼如下:
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#選擇K個(gè)最好的特征,返回選擇特征后的數(shù)據(jù)
#第一個(gè)參數(shù)為計(jì)算評(píng)估特征是否好的函數(shù),該函數(shù)輸入特征矩陣和目標(biāo)向量,輸出二元組(評(píng)分,P值)的數(shù)組,數(shù)組第i項(xiàng)為第i個(gè)特征的評(píng)分和P值。在此定義為計(jì)算相關(guān)系數(shù)
#參數(shù)k為選擇的特征個(gè)數(shù)
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
3.1.3 卡方檢驗(yàn)
經(jīng)典的卡方檢驗(yàn)是檢驗(yàn)定性自變量對(duì)定性因變量的相關(guān)性。假設(shè)自變量有N種取值,因變量有M種取值,考慮自變量等于i且因變量等于j的樣本頻數(shù)的觀察值與期望的差距,構(gòu)建統(tǒng)計(jì)量:

不難發(fā)現(xiàn),這個(gè)統(tǒng)計(jì)量的含義簡而言之就是自變量對(duì)因變量的相關(guān)性。用feature_selection庫的SelectKBest類結(jié)合卡方檢驗(yàn)來選擇特征的代碼如下:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#選擇K個(gè)最好的特征,返回選擇特征后的數(shù)據(jù)
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
3.1.4 互信息法
經(jīng)典的互信息也是評(píng)價(jià)定性自變量對(duì)定性因變量的相關(guān)性的,互信息計(jì)算公式如下:

為了處理定量數(shù)據(jù),最大信息系數(shù)法被提出,使用feature_selection庫的SelectKBest類結(jié)合最大信息系數(shù)法來選擇特征的代碼如下:
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的設(shè)計(jì)不是函數(shù)式的,定義mic方法將其為函數(shù)式的,返回一個(gè)二元組,二元組的第2項(xiàng)設(shè)置成固定的P值0.5
def mic(x, y):
m = MINE()
m.compute_score(x, y)
return (m.mic(), 0.5)
#選擇K個(gè)最好的特征,返回特征選擇后的數(shù)據(jù)
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
3.2 Wrapper
3.2.1 遞歸特征消除法
遞歸消除特征法使用一個(gè)基模型來進(jìn)行多輪訓(xùn)練,每輪訓(xùn)練后,消除若干權(quán)值系數(shù)的特征,再基于新的特征集進(jìn)行下一輪訓(xùn)練。使用feature_selection庫的RFE類來選擇特征的代碼如下:
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#遞歸特征消除法,返回特征選擇后的數(shù)據(jù)
#參數(shù)estimator為基模型
#參數(shù)n_features_to_select為選擇的特征個(gè)數(shù)
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
3.3 Embedded
3.3.1 基于懲罰項(xiàng)的特征選擇法
使用帶懲罰項(xiàng)的基模型,除了篩選出特征外,同時(shí)也進(jìn)行了降維。使用feature_selection庫的SelectFromModel類結(jié)合帶L1懲罰項(xiàng)的邏輯回歸模型,來選擇特征的代碼如下:
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#帶L1懲罰項(xiàng)的邏輯回歸作為基模型的特征選擇
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
實(shí)際上,L1懲罰項(xiàng)降維的原理在于保留多個(gè)對(duì)目標(biāo)值具有同等相關(guān)性的特征中的一個(gè),所以沒選到的特征不代表不重要。故,可結(jié)合L2懲罰項(xiàng)來優(yōu)化。具體操作為:若一個(gè)特征在L1中的權(quán)值為1,選擇在L2中權(quán)值差別不大且在L1中權(quán)值為0的特征構(gòu)成同類集合,將這一集合中的特征平分L1中的權(quán)值,故需要構(gòu)建一個(gè)新的邏輯回歸模型:
from sklearn.linear_model import LogisticRegression
class LR(LogisticRegression):
def __init__(self, threshold=0.01, dual=False, tol=1e-4, C=1.0,
fit_intercept=True, intercept_scaling=1, class_weight=None,
random_state=None, solver='liblinear', max_iter=100,
multi_class='ovr', verbose=0, warm_start=False, n_jobs=1):
#權(quán)值相近的閾值
self.threshold = threshold
LogisticRegression.__init__(self, penalty='l1', dual=dual, tol=tol, C=C,
fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight=class_weight,
random_state=random_state, solver=solver, max_iter=max_iter,
multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
#使用同樣的參數(shù)創(chuàng)建L2邏輯回歸
self.l2 = LogisticRegression(penalty='l2', dual=dual, tol=tol, C=C, fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight = class_weight, random_state=random_state, solver=solver, max_iter=max_iter, multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
def fit(self, X, y, sample_weight=None):
#訓(xùn)練L1邏輯回歸
super(LR, self).fit(X, y, sample_weight=sample_weight)
self.coef_old_ = self.coef_.copy()
#訓(xùn)練L2邏輯回歸
self.l2.fit(X, y, sample_weight=sample_weight)
cntOfRow, cntOfCol = self.coef_.shape
#權(quán)值系數(shù)矩陣的行數(shù)對(duì)應(yīng)目標(biāo)值的種類數(shù)目
for i in range(cntOfRow):
for j in range(cntOfCol):
coef = self.coef_[i][j]
#L1邏輯回歸的權(quán)值系數(shù)不為0
if coef != 0:
idx = [j]
#對(duì)應(yīng)在L2邏輯回歸中的權(quán)值系數(shù)
coef1 = self.l2.coef_[i][j]
for k in range(cntOfCol):
coef2 = self.l2.coef_[i][k]
#在L2邏輯回歸中,權(quán)值系數(shù)之差小于設(shè)定的閾值,且在L1中對(duì)應(yīng)的權(quán)值為0
if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:
idx.append(k)
#計(jì)算這一類特征的權(quán)值系數(shù)均值
mean = coef / len(idx)
self.coef_[i][idx] = mean
return self
使用feature_selection庫的SelectFromModel類結(jié)合帶L1以及L2懲罰項(xiàng)的邏輯回歸模型,來選擇特征的代碼如下:
from sklearn.feature_selection import SelectFromModel
# 帶L1和L2懲罰項(xiàng)的邏輯回歸作為基模型的特征選擇
# 參數(shù)threshold為權(quán)值系數(shù)之差的閾值
SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(iris.data, iris.target)
3.3.2 基于樹模型的特征選擇法
樹模型中GBDT也可用來作為基模型進(jìn)行特征選擇,使用feature_selection庫的SelectFromModel類結(jié)合GBDT模型,來選擇特征的代碼如下:
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作為基模型的特征選擇
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)
4 降維
當(dāng)特征選擇完成后,可以直接訓(xùn)練模型了,但是可能由于特征矩陣過大,導(dǎo)致計(jì)算量大,訓(xùn)練時(shí)間長的問題,因此降低特征矩陣維度也是必不可少的。常見的降維方法除了以上提到的基于L1懲罰項(xiàng)的模型以外,另外還有主成分分析法(PCA)和線性判別分析(LDA),線性判別分析本身也是一個(gè)分類模型。PCA和LDA有很多的相似點(diǎn),其本質(zhì)是要將原始的樣本映射到維度更低的樣本空間中,但是PCA和LDA的映射目標(biāo)不一樣:PCA是為了讓映射后的樣本具有最大的發(fā)散性;而LDA是為了讓映射后的樣本有最好的分類性能。所以說PCA是一種無監(jiān)督的降維方法,而LDA是一種有監(jiān)督的降維方法。
4.1 主成分分析法(PCA)
使用decomposition庫的PCA類選擇特征的代碼如下:
from sklearn.decomposition import PCA
#主成分分析法,返回降維后的數(shù)據(jù)
#參數(shù)n_components為主成分?jǐn)?shù)目
PCA(n_components=2).fit_transform(iris.data)
4.2 線性判別分析法(LDA)
使用lda庫的LDA類選擇特征的代碼如下:
from sklearn.lda import LDA
#線性判別分析法,返回降維后的數(shù)據(jù)
#參數(shù)n_components為降維后的維數(shù)
LDA(n_components=2).fit_transform(iris.data, iris.target)
5 總結(jié)
再讓我們回歸一下本文開始的特征工程的思維導(dǎo)圖,我們可以使用sklearn完成幾乎所有特征處理的工作,而且不管是數(shù)據(jù)預(yù)處理,還是特征選擇,抑或降維,它們都是通過某個(gè)類的方法fit_transform完成的,fit_transform要不只帶一個(gè)參數(shù):特征矩陣,要不帶兩個(gè)參數(shù):特征矩陣加目標(biāo)向量。這些難道都是巧合嗎?還是故意設(shè)計(jì)成這樣?方法fit_transform中有fit這一單詞,它和訓(xùn)練模型的fit方法有關(guān)聯(lián)嗎?接下來,我將在《使用sklearn優(yōu)雅地進(jìn)行數(shù)據(jù)挖掘》中闡述其中的奧妙!
6 參考資料
- FAQ: What is dummy coding?
- IRIS(鳶尾花)數(shù)據(jù)集
- 卡方檢驗(yàn)
- 干貨:結(jié)合Scikit-learn介紹幾種常用的特征選擇方法
- 機(jī)器學(xué)習(xí)中,有哪些特征選擇的工程方法?
- 機(jī)器學(xué)習(xí)中的數(shù)學(xué)(4)-線性判別分析(LDA), 主成分分析(PCA)
作者:城東
鏈接:https://www.zhihu.com/question/28641663/answer/110165221
來源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。