文章主要參考于大神城東(部分認(rèn)為有問(wèn)題的地方進(jìn)行了修改)
1. 特征工程是什么?
數(shù)據(jù)和特征決定了機(jī)器學(xué)習(xí)的上限,而模型和算法只是逼近了這個(gè)上線而已。特征工程的本質(zhì)是一項(xiàng)工程活動(dòng),目的是最大限度地從原始數(shù)據(jù)中提取特征以供算法和模型使用。通過(guò)總結(jié)和歸納,人們認(rèn)為特征工程包括以下方面:
本文使用python sklearn IRIS(鳶尾花)數(shù)據(jù)集來(lái)對(duì)特征處理功能進(jìn)行說(shuō)明,IRIS數(shù)據(jù)集包含4個(gè)特征(Sepal.Length(花萼長(zhǎng)度),Sepal.Width(花萼寬度),Petal.Length(花瓣長(zhǎng)度),Petal.Width(花瓣寬度)),特征都為正浮點(diǎn)數(shù),單位為厘米。目標(biāo)值為鳶尾花的分類(Iris Setosa(山鳶尾) , Iris Versicolour(雜色鳶尾),IrisVirginica (維吉尼亞鳶尾))
from sklearn.datasets import load_iris
#導(dǎo)入IRIS 數(shù)據(jù)集
iris = load_iris()
#特征矩陣
iris.data
#目標(biāo)向量
iris.target
2. 數(shù)據(jù)預(yù)處理
通過(guò)特征提取,我們能得到未經(jīng)處理的特征,這是特征可能存在以下問(wèn)題:
-
不屬于同一量綱:即特征的規(guī)格不一樣,不能放在一起比較。無(wú)量綱化可以解決這一問(wèn)題。
- 標(biāo)準(zhǔn)化
# 使用preproccessing庫(kù)的 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) - 區(qū)間縮放法
區(qū)間縮放法的思路有多種,常見(jiàn)的一種為利用兩個(gè)最值進(jìn)行縮放:# 使用preproccessing庫(kù)的 MinMaxScaler類對(duì)數(shù)據(jù)進(jìn)行區(qū)間縮放代碼如下: from sklearn.preprocessing import MinMaxScaler # 區(qū)間縮放,返回值為縮放到[0,1]區(qū)間的數(shù)據(jù) MinMaxScaler().fit_transform(iris.data) - 數(shù)據(jù)歸一化
歸一化是依照特征矩陣的行處理數(shù)據(jù),其目的在于樣本向量在點(diǎn)乘運(yùn)算或其他核函數(shù)計(jì)算相似性時(shí),擁有統(tǒng)一的標(biāo)準(zhǔn),也就是說(shuō)都轉(zhuǎn)化為“單位向量”# 使用preprocessing庫(kù)的 Normalizer 類對(duì)數(shù)據(jù)進(jìn)行歸一化的代碼如下: from sklearn.preprocessing import Normalizer # 歸一化,返回值為歸一化后的數(shù)據(jù) Normalizer().fit_transform(iris.data)
無(wú)量綱化使不同規(guī)格的數(shù)據(jù)轉(zhuǎn)化到同一規(guī)格。常用的無(wú)量綱方法有標(biāo)準(zhǔn)化和區(qū)間縮放法。區(qū)間縮放法利用了界值信息,將特征的取值區(qū)間縮放到某個(gè)特點(diǎn)的范圍,例如[0,1]
- 標(biāo)準(zhǔn)化
-
信息冗余:對(duì)魚某些定量特征,其包含的有效信息為區(qū)間劃分,列如學(xué)習(xí)成績(jī),假若只關(guān)心“及格”或“不及格”,那么可以將定量的考分,轉(zhuǎn)化為“1”和“0”表示及格和未及格,二值化可以解決這一問(wèn)題。
定量特征二值化的核心在于設(shè)定一個(gè)閥值,大于閥值的賦值為1,小于等于閥值的賦值為0:#使用preprocessing 庫(kù)的 Binarizer類對(duì)數(shù)據(jù)進(jìn)行二值化的代碼如下: from sklearn.preprocessing import Binarizer # 二值化,閥值設(shè)置為3, 返回值為二值化后的數(shù)據(jù) Binarizer(threshold = 3).fit_transform(iris.data) -
定性特征不能直接使用:某些機(jī)器學(xué)習(xí)算法和模型只能接受定量特征的輸入,那么需要獎(jiǎng)定性特征轉(zhuǎn)化為定量特征。最簡(jiǎn)單的方式是為每一種定性值,但這種方式過(guò)于靈活,增加了調(diào)參的工作。通常使用啞編碼的方式將定性特征轉(zhuǎn)化為定量特征:假設(shè)有N種定性值,則將這一個(gè)特征擴(kuò)展為N種特征,當(dāng)原始特征值為第i種定性值時(shí),第i個(gè)擴(kuò)展特征賦值為1,其他擴(kuò)展特征賦值為0.啞編碼的方式相比直接指定的方式,不用增加調(diào)參的工作,對(duì)于線性模型來(lái)說(shuō),使用啞編碼的特征可達(dá)到的非線性的效果。
import pandas as pd from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import LabelEncoder # 啞編碼,返回值為啞編碼后的數(shù)據(jù) testData = pd.DataFrame({'pet':['cat','dog','dog','fish'],'age':[4,6,3,3], 'salary':[4,5,1,1]}) OneHotEncoder(sparse = False).fit_transform(testData[['age']]) # 對(duì)于字符型變量,OneHotEncoder目前無(wú)法對(duì)其進(jìn)行編碼
可以采用方法,曲線救國(guó)
arry = LabelEncoder().fit_transform(testdata['pet'])
OneHotEncoder(sparse = False).fit_transform(arry.reshape(-1,-1))
```
- 存在缺失值:缺失值需要補(bǔ)充。
- 信息利用率低:不同的機(jī)器學(xué)習(xí)算法和模型對(duì)數(shù)據(jù)中信息的利用是不同的,之前提到在線性模型中,使用對(duì)定性特征啞編碼可以達(dá)到非線性的效果。類似地,對(duì)定量變量多項(xiàng)式化,或者進(jìn)行其他的轉(zhuǎn)化,都能達(dá)到非線性的效果
常見(jiàn)的數(shù)據(jù)變換有基于多項(xiàng)式的,基于指數(shù)函數(shù)的,基于對(duì)數(shù)函數(shù)的# 基于多項(xiàng)式的變幻 from sklearn.preprocessing import PolynomialFeatures # 多項(xiàng)式轉(zhuǎn)換 # 參數(shù)digree 為度, 默認(rèn)值為2 PolynomialFeatures().fit_transform(iris.data) # 基于單變?cè)瘮?shù)的數(shù)據(jù)可以使用統(tǒng)一的方式完成 from numpy import loglp from sklearn.preprocessing import FunctionTransformer # 自定義轉(zhuǎn)換函數(shù)為對(duì)數(shù)函數(shù)的數(shù)據(jù)變換 # 第一個(gè)參數(shù)是單變?cè)瘮?shù) FunctionTransformer(loglp).fit_transform(iris.data)
我們可以使用sklearn中的preprocessing庫(kù)進(jìn)行數(shù)據(jù)預(yù)處理,可以覆蓋以上問(wèn)題的解決方案。
3. 特征選擇
當(dāng)數(shù)據(jù)預(yù)處理完成后,我們需要選擇有意義的特征輸入機(jī)械學(xué)習(xí)的算法和模型中進(jìn)行訓(xùn)練。通常來(lái)說(shuō),從兩個(gè)方面考慮來(lái)選擇特征:
- 特征是否發(fā)散:如果一個(gè)特征不發(fā)散,例如方差接近于0,也就是說(shuō)樣本在這個(gè)特征上基本上沒(méi)有差異,這個(gè)特征對(duì)于樣本區(qū)分并沒(méi)有什么用。
- 特征與目標(biāo)的相關(guān)性:這點(diǎn)比較顯而易見(jiàn),與目標(biāo)相關(guān)性高的特征,應(yīng)當(dāng)優(yōu)選選擇。除方差法外。本文介紹的其他方法均從相關(guān)性考慮。
根據(jù)特征選擇的形式又可以將特征選擇的方法分為3種:
-
Filter : 過(guò)濾法,按照發(fā)散性或者相關(guān)性對(duì)各個(gè)特征進(jìn)行評(píng)分,設(shè)定閥值或者待選閥值的個(gè)數(shù),選擇特征
過(guò)濾法與后續(xù)機(jī)器學(xué)習(xí)算法的選擇無(wú)關(guān)。- 方差法(計(jì)算各個(gè)特征的方差,根據(jù)閥值,選擇方差大于閥值的特征)
from sklearn.feature_selection import VarianceThreshold # 方差選擇法,返回值為特征選擇后的數(shù)據(jù) # 參數(shù)threshold為方差的閥值 VarianceThreshold(threshold = 3).fit_transform(iris.data)- 相關(guān)系數(shù)法(先要計(jì)算各個(gè)特征對(duì)目標(biāo)值的相關(guān)系數(shù)以及相關(guān)系數(shù)的P值)
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ù) SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)- 卡方檢驗(yàn)
經(jīng)典的卡方檢驗(yàn)是檢驗(yàn)定性自變量對(duì)性因變量的相關(guān)性。假設(shè)自變量有N種取值,因變量有M種取值,考慮自變量等于i且因變量等于j的樣本頻數(shù)的觀察值與期望的差距,構(gòu)建統(tǒng)計(jì)量:
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)-
互信息法
經(jīng)典的互信息也是平價(jià)定性自變量對(duì)定性因變量的相關(guān)性的
from sklearn.feature_selection import SelectKBest from minepy import MINE # 由于MINE的設(shè)計(jì)不是函數(shù)式的,定義mic方法將其為函數(shù)式,返回一個(gè)二元組, 二元組的第二項(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 xmic(x,Y)).T, k = 2).fit_transform(iris.data, iris.target) -
Wrapper : 包裝法,根據(jù)目標(biāo)函數(shù)(通常是預(yù)測(cè)效果評(píng)分),每次選擇若干特征,或者排除若干特征。
- 遞歸特征消除法
遞歸消除特征法使用一個(gè)基模型來(lái)進(jìn)行多輪訓(xùn)練,每輪訓(xùn)練后,消除若干權(quán)值系數(shù)的特征,再基于新的特征集進(jìn)行下一輪訓(xùn)練。
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) - 遞歸特征消除法
-
Embedded : 集成法,先使用某些機(jī)器學(xué)習(xí)的算法和模型進(jìn)行訓(xùn)練,得到各個(gè)特征的權(quán)值系數(shù),根據(jù)系數(shù)從大到小選擇特征。類似于 Filter方法,但是是通過(guò)訓(xùn)練來(lái)確定特征的
- 基于懲罰項(xiàng)的特征選擇法(沒(méi)看懂~)
- 基于樹(shù)模型的特征選擇法
from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import GradientBoostingClassifier # GBDT作為基模型的特征選擇 selectFromModel(GradientBoostingClassifier()).fit_transform(iris.data,iris.target)
- 降維
當(dāng)特征選擇完成以后,可以直接訓(xùn)練模型了,但是可能由于特征矩陣過(guò)大,導(dǎo)致計(jì)算量大,訓(xùn)練時(shí)間長(zhǎng)的問(wèn)題,因此降低特征矩陣維度也是必不可少的。常見(jiàn)的降維方法除了以上提到的基于L1懲罰的模型以外,另外還有主成分分析法(PCA)和線性判別分析(LDA),線性判別分析本身也是一個(gè)分類模型。PCA和LDA有很多的相似點(diǎn),其本質(zhì)是要將原始的樣本映射到維度更低的樣本空間中,但是PCA和LDA的映射目標(biāo)不一樣:PCA是為了讓映射后的樣本具有最大的發(fā)散性;而LDA是為了讓映射后的樣本具有最好的分類性能。所以說(shuō)PCA是一種無(wú)監(jiān)督的降維方法,而LDA是一種有監(jiān)督的降維方法。- 主成分分析法(PCA)
from sklearn.decomposition import PCA from sklearn.decomposition import PCA #主成分分析法,返回降維后的數(shù)據(jù) #參數(shù)n_components為主成分?jǐn)?shù)目 PCA(n_components=2).fit_transform(iris.data)- 線性判別分析法(LDA)
from sklearn.lda import LDA #線性判別分析法,返回降維后的數(shù)據(jù) #參數(shù)n_components為降維后的維數(shù) LDA(n_components=2).fit_transform(iris.data, iris.target)