一、特徵工程的定義

特徵工程是機器學習中的重要環節,包括缺失值補全、特徵選擇、維度壓縮、到對輸入數據的範圍進行變換-k近鄰演算法(歸一化與標準化)

二、數據預處理

1、數據導入

直接使用sklearn中的iris 數據集,包括四個特徵:正浮點數類型

  • 花萼長度 Sepal.Length
  • 花萼寬度 Sepal.Width
  • 花瓣長度 Petal.Length
  • 花瓣寬度 Petal.Width

三個目標值分類:

  • Lris Setosa 山鳶尾
  • Lris Versicolor 雜色鳶尾
  • Lris Virginica 維吉尼亞鳶尾

#調用模塊
from sklearn.datasets import load_iris
#導入IRIS數據集
data = load_iris()
#導入數據和標籤
#特徵矩陣
data_X = data.data
#目標向量
data_y = data.target

#導入模塊
from sklearn.model_selection import train_test_split
from sklearn import datasets
#k近鄰函數
from sklearn.neighbors import KNeighborsClassifier
iris = datasets.load_iris()
#導入數據和標籤
iris_X = iris.data
iris_y = iris.target
#劃分為訓練集和測試集數據
X_train, X_test, y_train, y_test = train_test_split(iris_X, iris_y, test_size=0.3)
#print(y_train)
#設置knn分類器
knn = KNeighborsClassifier()
#進行訓練
knn.fit(X_train,y_train)
#使用訓練好的knn進行數據預測
print(knn.predict(X_test))
print(y_test)

2、數據預處理

由於未經處理的特徵,可能會存在不屬於同一量綱、定性特徵、存在缺失值、信息利用率低等問題,所以使用sklearn的proprecessing庫進行數據預處理,解決這些問題

2.1無量綱化

使不同規格的數據轉換到同一規格,標準化前提是特徵值服從正態分佈,標準化後,將其轉化為正態分佈,區間縮放法縮放到邊界值範圍之內。

2.1.1標準化

需要計算特徵值的均值與標準差

x^{}=frac{x-ar{x}}{S}

from sklearn.preprocessing import StandardScaler
#標準化,返回值為標準化後的數據
StandardScaler().fit_transform(data.data)

2.1.2 區間縮放法

常見為兩個最值進行縮放

x=frac{x-Min}{Max-Min}

from sklearn.preprocessing import MinMaxScaler
#區間縮放,返回值為縮放到【0,1】區間的數據
MinMaxScaler().fit_transform(data.data)

2.1.3 標準化與歸一化的區別

標準化依照矩陣的列,通過求z-score的方法。歸一化依照特徵矩陣的行處理數據,樣本向量在點乘運算或者其他函數計算相似性時,擁有統一的標準,轉化為「單位向量」。規則為l2的歸一化公式如下:

x^{}=frac{x}{sqrt{sum_{j}^{m}{x[j]^2 }}}

使用preprocessing庫的Normalizer類對資料庫進行歸一化的代碼如下:

from sklearn.preprocessing import Normalizer
#歸一化,返回值為歸一化後的數據
Normalizer().fit_transform(data.data)

2.2 對定量特徵進行二值化

核心在於設定一個閾值,大於閾值為1,小於等於閾值為0

使用preprocessing庫的Binarizer類對資料庫進行歸一化的代碼如下:

from sklearn.preprocessing import Binarizer
#二值化,閾值設置為3,返回值為二值化後的數據
Binarizer(threshold=3).fit_transform(data.data)

2.3 對定性特徵進行啞編碼

為了試驗,使用目標值進行啞編碼,實際不需要對目標值進行編碼。

使用preprocessing庫的OneHotEncoder類對資料庫進行歸一化的代碼如下:

from sklearn.preprocessing import OneHotEncoder
#啞編碼,對IRIS數據集的目標值,返回值為啞編碼後的數據
OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))

2.4 缺失值計算

由於現在數據集沒有缺失值,故對數據集新增一個樣本,4個特徵均賦值Nan,表示數據缺失。

使用preprocessing庫的Imputer類對資料庫進行歸一化的代碼如下:

from numpy import vstack,array,nan
from sklearn.preprocessing import Imputer
#缺失值計算,返回為計算缺失值後的數據
#參數missing_value為缺失值的表達形式,默認為NaN
#參數strategy為缺失值填充方式,默認為mean(均值)
Imputer().fit_transform(vstack((array([nan,nan,nan,nan]),data.data)))

2.5 數據變換

常見的數據變換有基於多項式、指數函數、對數函數的,4個特徵,度為2的多項式轉換公式如下:

使用preprocessing庫的polynomialFeatures類對資料庫進行歸一化的代碼如下:

from sklearn.preprocessing import PolynomialFeatures
#多項式轉換
#參數degree為度,默認值為2
PolynomialFeatures().fit_transform(data.data)

基於單變元函數的數據變換可以統一進行,使用preprocessing庫的FunctionTransformer類對資料庫進行對數函數轉換的代碼如下:

from numpy import log1p
from sklearn.preprocessing import FunctionTransformer
#自定義轉換函數為對數函數的數據變換
#第一個參數是單變元函數
FunctionTransformer(log1p).fit_transform(data.data)

三、特徵選擇

數據預處理完成後,選擇其中有意義的特徵輸入機器學習的演算法與模型中進行訓練,選擇特徵的考慮方面:

  • 數據是否發散-方差
  • 特徵與目標的相關性

根據特徵選擇的形式將特徵選擇方法分為3種:

  • Filter:過濾法,根據發散性與相關性對各個特徵進行評分,設定閾值或者待選擇閾值的個數,選擇特徵
  • Wrapper:包裝法,根據目標函數(通常是預測結果評分),每次選擇若干特徵,或者排除若干特徵
  • Embedded:集成法。先使用某些機器學習的演算法或者模型進行訓練,得到各個特徵的權值係數,根據係數從大到小選擇特徵,通過訓練來確定特徵的優劣

使用sklearn中的feature_selection庫來進行特徵選擇

3.1 Filter

3.1.1 方差選擇法

先計算各個特徵的方差,然後根據閾值,選擇方差大於閾值的特徵。

使用feature_selection庫的VarianceThreshold類來選擇特徵的代碼如下:

#Filter 方差選擇法
from sklearn.feature_selection import VarianceThreshold
#方差選擇法,返回值為特徵選擇後的數據
#參數threshold為方差的閾值
VarianceThreshold(threshold=3).fit_transform(data.data)

3.1.2 相關係數法

先計算各個特徵對目標值的相關係數以及相關係數的p值。

使用feature_selection庫的SelectKBest類來選擇特徵的代碼如下:

#相關係數法
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#選擇k個最好的特徵,返回選擇特徵後的數據
#第一個參數為計算評估特徵是否好的函數,該函數輸入特徵矩陣和目標向量,輸出二元組(評分,P值)的數組,數組第i項為第i個特徵的評分和P值,在此定義為計算相關係數)
#參數k為選擇的特徵個數
SelectKBest(lambda X, Y: array(list(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(data.data, data.target))

3.1.3 卡方檢驗

經典卡方檢驗是檢驗定性自變數對定性因變數的相關性。假設自變數有N種取值,因變數有M種取值,考慮自變數等於i且因變數等於j的樣本頻數的觀察值與期望的差距,構建統計量。

x^2=sum_{}^{}{frac{(A-E)^2}{E}} A為觀察頻數,E為期望頻數,n為總頻數

使用feature_selection庫的SelectKBest類來選擇特徵的代碼如下:

#卡方檢驗
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#選擇k個最好的特徵,返回選擇特徵後的數據
SelectKBest(chi2,k=2).fit_transform(data.data,data.target)

3.1.4 互信息法

經典的互信息也是評價定性自變數與因變數的相關性的。為了處理定量數據

#互信息法
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由於mine的設計不是函數式的,定義mic方法將其為函數式的,返回一個二元組,二元組的第2項設置成固定的P值0.5
#mic最大信息係數
def mic(x,y):
m=MINE()
m.compute_score(x,y)
return (m.mic(),0.5)
#選擇k個最好的特徵,返回特徵選擇後的數據
SelectKBest(lambda X,Y: array(map(lambda x:mic(x,Y),X.T)).T,k=2).fit_transform(data.data,data.target)

3.2 Wrapper

3.2.1 遞歸特徵消除法

使用一個基模型進行多輪訓練,每輪訓練後,消除若干權值係數的特徵,再基於新的特徵集進行下一輪訓練。

使用feature_selection庫的RFE類來選擇特徵的代碼如下:

#wrapper封裝
#遞歸特徵消除法
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#參數estimator為基模型
#參數n_features_to_select為選擇的特徵個數
RFE(estimator=LogisticRegression(),n_features_to_select=2).fit_transform(data.data,data.target)

3.3 Embedded

3.3.1 基於懲罰項的特徵選擇法

使用帶懲罰項的基模型,除了篩選特徵外,同時也進行了降維。

使用feature_selection庫的SelectFromModel類結合L1懲罰項的邏輯回歸模型。

#Embedded 集成
#基於懲罰項的特徵選擇法
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
SelectFromModel(LogisticRegression(penalty="l1",C=0.1)).fit_transform(data.data,data.target)

L1懲罰項降維的原理是保留多個對目標值具有同等相關性的特徵中的一個,所以沒選到的特徵不代表不重要,所以結合L2懲罰項進行優化,具體操作為:若一個特徵在L1中的權值為1,選擇在L2中權值差距不大且在L1中權值為0的特徵構成同類集合。將這一集合中的特徵評分L1中的權值。故構建一個新的邏輯回歸模型:

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):

#權值相近的閾值
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)
#使用同樣的參數創建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):
#訓練L1邏輯回歸
super(LR, self).fit(X, y, sample_weight=sample_weight)
self.coef_old_ = self.coef_.copy()
#訓練L2邏輯回歸
self.l2.fit(X, y, sample_weight=sample_weight)

cntOfRow, cntOfCol = self.coef_.shape
#權值係數矩陣的行數對應目標值的種類數目
for i in range(cntOfRow):
for j in range(cntOfCol):
coef = self.coef_[i][j]
#L1邏輯回歸的權值係數不為0
if coef != 0:
idx = [j]
#對應在L2邏輯回歸中的權值係數
coef1 = self.l2.coef_[i][j]
for k in range(cntOfCol):
coef2 = self.l2.coef_[i][k]
#在L2邏輯回歸中,權值係數之差小於設定的閾值,且在L1中對應的權值為0
if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:
idx.append(k)
#計算這一類特徵的權值係數均值
mean = coef / len(idx)
self.coef_[i][idx] = mean
return self

使用feature-selection庫的SelectFromModel類結合帶L1以及L2懲罰項的邏輯回歸模型。

from sklearn.feature_selection import SelectFromModel
#帶L1與L2懲罰項的邏輯回歸作為基模型的特徵選擇
#參數threshold為權值係數之差的閾值
SelectFromModel(LR(threshold=0.5,C=0.1)).fit_transform(data.data,data.target)

3.3.2 基於樹模型的特徵選擇法

樹模型GBDT也可以作為基模型進行特徵選擇,使用feature_selection 庫的SelectFromModel類結合GBDT模型。

#基於樹模型GBDT的特徵選擇法
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作為基模型的特徵選擇
SelectFromModel(GradientBoostingClassifier()).fit_transform(data.data,data.target)

4、降維

特徵選擇完之後,可以直接訓練模型,但是由於特徵矩陣過大,導致計算量大,訓練時間長。所以降低矩陣維度必不可少。常見的降維方法:

  • 基於L1懲罰項的模型
  • 主成分分析法PCA 映射後的樣本具有更大發散性--無監督
  • 線性判別分析LDA 讓映射後的樣本有更好的分類性能--有監督

將原始的樣本映射到維度更低的樣本空間。

4.1 主成分分析法(PCA)

使用decomposition庫的PCA類選擇特徵的代碼如下:

from sklearn.decomposition import PCA
#主成分分析法,返回降維後的數據
#參數n_components為主成分數目
PCA(n_components=2).fit_transform(data.data)

4.2 線性辨別分析法(LDA)

使用lda庫的LDA類選擇特徵。

from sklearn.lda import LDA
#線性判別分析法,返回降維後的數據
#參數n_components為降維後的維數
LDA(n_components=2).fit_transform(data.data, data.target)

一般來說,如果我們的數據是有類別標籤的,那麼優先選擇LDA去嘗試降維;當然也可以使用PCA做很小幅度的降維去消去雜訊,然後再使用LDA降維。如果沒有類別標籤,那麼肯定PCA是最先考慮的一個選擇了。

5、總結

本文主要參考以下文章:

機器學習之特徵工程

使用sklearn做單機特徵工程 - jasonfreak - 博客園

ahmedbesbes.com/how-to-

API Reference - scikit-learn 0.20.0 documentation


推薦閱讀:
相關文章