<style></style> <style></style> <style></style> <style></style>
1 引言¶
預處理操作是機器學習整個周期中必不可少的一個程序,也是最能快速改善模型性能的一個程序,往往稍微轉換一下特征屬性的形態,就能得到性能的極大提升,當然,資料預處理絕對也是耗時最長的一個程序,這一程序不僅要求洞悉整個資料集結構分布,還要探查每一個特征屬性細節情況,并作出應對處理,使資料以最適合的狀態傳輸給模型,
針對預處理操作,sklearn中提供了許多模塊工具,靈活使用工具可以讓資料預處理輕松很多,
本文簡要介紹資料預處理中的一些主要方法,并結合sklearn中提供的模塊進行實踐,
2 無量綱化¶
對于大部分機器學習任務而言,對原始資料進行無量綱化是是建模前的必不可少的一個環節,通過無量綱化,可以消除量綱不一致對模型造成的不良影響,標準化和歸一化是最為常見的兩種無量綱化方法,下面分別展開介紹這兩種方法,
2.1 標準化¶
標準化對資料的分布的進行轉換,使其符合某種分布(一般指正態分布)的一種特征變換,一般而言,標準化都是指通過z-score的方法將資料轉換為服從均值為0,標準差為1的標準正態分布資料,通過如下公式進行轉換: $$x' = \frac{{x - \mu }}{\sigma }$$ 式中,$\mu$和$\sigma$是指$x$所在特征屬性集的均值和標準差,
(1)sklearn.preprocessing.scale方法實作標準化
In [1]:from sklearn import preprocessing import numpy as npIn [2]:
X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) X_scaled = preprocessing.scale(X_train)
再次查看X_train各列,我們會發現,均值和方差都已經標準化:
In [4]:X_train.mean(axis=0)Out[4]:
array([1. , 0. , 0.33333333])In [5]:
X_scaled.std(axis=0)Out[5]:
array([1., 1., 1.])
(2)sklearn.preprocessing.StandardScaler類實作歸一化
除了scale方法外,在sklearn.preprocessing模塊中還提供有一個專門的類用于實作標準化:StandardScaler,StandardScaler類會自動計算實體化類時傳入的訓練集的均值、標準差,并將這些資訊保留,這也就意味著,對訓練集的標準化方式可以復用,例如對測驗集和預測樣本進行同樣的標準化,所以,一般來說,更加建議使用StandardScaler類來實作標準化,
In [9]:# 傳入一個訓練集,實體化StandarScaler類 scaler = preprocessing.StandardScaler()In [34]:
scaler.fit(X_train) # 收集標準化資訊,均值,標準差Out[34]:
StandardScaler(copy=True, with_mean=True, with_std=True)In [35]:
scaler.mean_ # 查看均值Out[35]:
array([1. , 0. , 0.33333333])In [36]:
scaler.scale_ # 查看標準差Out[36]:
array([0.81649658, 0.81649658, 1.24721913])
創建StandarScaler類實體后,需要通過類中的transform方法對X-train進行標準化:
In [16]:scaler.transform(X_train)Out[16]:
array([[ 0. , -1.22474487, 1.33630621],
[ 1.22474487, 0. , -0.26726124],
[-1.22474487, 1.22474487, -1.06904497]])
StandardScaler類中還提供有一個fit_transform方法,這個方法合并了fit和transform兩個方法的功能,同時根據傳入的資料集收集標準化資訊,并將標準化方案應用于傳入的訓練集:
In [26]:scaler = preprocessing.StandardScaler()In [29]:
x_train = scaler.fit_transform(X_train)In [30]:
x_train
Out[30]:
array([[ 0. , -1.22474487, 1.33630621],
[ 1.22474487, 0. , -0.26726124],
[-1.22474487, 1.22474487, -1.06904497]])
假設現在有一個測驗樣本,那么,也可以通過transform方法將標準化方案應用于測驗樣本上:
In [17]:X_test = [[-1., 1., 0.]] scaler.transform(X_test)Out[17]:
array([[-2.44948974, 1.22474487, -0.26726124]])
2.2 歸一化¶
歸一化是指對資料的數值范圍進行特定縮放,但不改變其資料分布的一種線性特征變換,大多數場景下,歸一化都是將資料縮放到[0,1]區間范圍內,計算公式如下: $$x' = \frac{{x - \min }}{{\max - \min }}$$ 式中,$min$和$max$是$x$所屬特征集合的最小值和最大值,可見,這種歸一化方式的最終結果只受極值的影響,
(1)sklearn.preprocessing.minmax_scale方法實作歸一化,
In [46]:X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) X_train = preprocessing.minmax_scale(X_train) X_trainOut[46]:
array([[0.5 , 0. , 1. ],
[1. , 0.5 , 0.33333333],
[0. , 1. , 0. ]])
(2)sklearn.preprocessing.MinMaxScaler類實作歸一化,
In [37]:X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) min_max_scaler = preprocessing.MinMaxScaler() X_train_minmax = min_max_scaler.fit_transform(X_train) X_train_minmaxOut[37]:
array([[0.5 , 0. , 1. ],
[1. , 0.5 , 0.33333333],
[0. , 1. , 0. ]])
使用訓練好的min_max_scaler對新的測驗樣本進行歸一化:
In [38]:X_test = np.array([[-3., -1., 4.]]) X_test_minmax = min_max_scaler.transform(X_test) X_test_minmaxOut[38]:
array([[-1.5 , 0. , 1.66666667]])
我們知道,歸一化是將特征屬性值縮放到[0,1]范圍,但在某些特殊的場景下,我們需要將特征屬性縮放到其他范圍,MinMaxScaler類通過feature_range引數也提供了這一功能,feature_range引數接受一個元組作為引數,默認值為(0,1),
In [40]:X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) min_max_scaler = preprocessing.MinMaxScaler(feature_range=(10,20)) X_train_minmax = min_max_scaler.fit_transform(X_train) X_train_minmaxOut[40]:
array([[15. , 10. , 20. ],
[20. , 15. , 13.33333333],
[10. , 20. , 10. ]])
(3)sklearn.preprocessing.MaxAbsScaler類實作歸一化
MaxAbsScaler是專門為稀疏資料做歸一化設計的,通過特征值除以整個特征集合最大絕對值實作,最終將資料投影到[-1, 1]范圍內,對原來取值為0的資料并不會做出變換,所以不會影響資料的稀疏性,
最后來總結一下標準化和歸一化,
標準化是依照特征矩陣的列處理資料,其通過求z-score的方法,轉換為標準正態分布,和整體樣本分布相關,每個樣本點都能對標準化產生影響,而歸一化是將樣本的特征值轉換到同一量綱下把資料映射到指定區間內,僅由變數的極值決定,所以對例外值較為敏感,標準化和歸一化都是一種線性變換,都是對向量x按照比例壓縮再進行平移,無論是標準化還是歸一化,都可以將資料無量綱化,消除不同量綱對結果的影響,同時都可以加過模型的收斂速度,
標準化與歸一化之間如何選擇呢?
大多數機器學習演算法中,會選擇StandardScaler來進行特征縮放,因為MinMaxScaler對例外值非常敏感,在PCA,聚類,邏輯回歸,支持向量機,神經網路這些演算法中,StandardScaler往往是最好的選擇,
MinMaxScaler在不涉及距離度量、梯度、協方差計算以及資料需要被壓縮到特定區間時使用廣泛,比如數字影像處理中量化像素強度時,都會使用MinMaxScaler將資料壓縮于[0,1]區間之中,若是歸一化時需要保留資料的稀疏性,則可以使用MaxAbscaler歸一化,
在大多數情況下,建議先試試看StandardScaler,效果不好換MinMaxScaler,
另外,這里再提一下正則化(Normalization),很多資料把正則化與歸一化、標準化放到一起討論,雖然正則化也是資料預處理方法的一種,但我并不認為正則化是無量綱化方法,正則化通過某個特征值除以整個樣本所有特征值的范數計算,使得整個樣本范數為1,通常在文本分類和聚類中使用較多,sklearn中提供preprocessing.normalize方法和preprocessing.Normalizer類實作:
In [49]:X_train = np.array([[ 1., -2., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) max_abs_scaler = preprocessing.MaxAbsScaler() X_train_max_abs = max_abs_scaler.fit_transform(X_train) X_train_max_absOut[49]:
array([[ 0.5, -1. , 1. ],
[ 1. , 0. , 0. ],
[ 0. , 0.5, -0.5]])
In [53]:
X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) nor = preprocessing.Normalizer() X_train_nor = nor.fit_transform(X_train) X_train_norOut[53]:
array([[ 0.40824829, -0.40824829, 0.81649658],
[ 1. , 0. , 0. ],
[ 0. , 0.70710678, -0.70710678]])
3 缺失值處理¶
由于各種各樣的原因,我們所面對的資料經常是有所缺失的,然而sklearn中實作的各個演算法都假設資料沒有缺失為前提,如果直接用缺失資料跑演算法影響最終結果不說,也容易產生各種例外,所以在資料預處理階段,對缺失值進行處理是很有必要的,對于缺失值處理,直接洗掉包含缺失值的特征屬性或者樣本是最簡單的方法,但是這種方法卻也將其他部分資訊拋棄,在很多情況下,特別是資料樣本不多、資料價值大時,未免得不償失,在sklearn中,提供了諸多其他處理缺失值的方案,例如以均值、中位數、眾數亦或者是指定值填充缺失值等,這些方案都在sklearn.impute模塊中提供的SimpleImputer類中實作,SimpleImputer類引數如下:
import numpy as np from sklearn.impute import SimpleImputer imp = SimpleImputer(missing_values=np.nan, strategy='mean') # 指定缺失值為nan,以均值填充 imp.fit([[1, 2], [np.nan, 3], [7, 6]]) X = [[np.nan, 2], [6, np.nan], [7, 6]] imp.transform(X)Out[99]:
array([[4. , 2. ],
[6. , 3.66666667],
[7. , 6. ]])
In [107]:
imp = SimpleImputer(missing_values=0, strategy='constant', fill_value=1) # 指定缺失值為0,指定以常數1填充 imp.fit([[5, 2], [4, 0], [7, 6]]) X = [[0, 2], [6, 0], [7, 6]] imp.transform(X)Out[107]:
array([[1, 2],
[6, 1],
[7, 6]])
4 離散型特征屬性處理¶
很多時候,我們所要處理的特征屬性未必是連續型的,也可能是離散型,以衣服為例,款式(男款、女款),大小(X、XL、XXL),顏色(綠色、紅色、白色),都是離散型特征屬性,對于這類離散型特征屬性,需要編碼之后才能用來建模,離散型特征屬性值可以分為兩種:
(1)數字編碼
整數編碼是指對離散型屬性以整數來標識,例如色澤這一特征中,以整數“0”標識“男款”,整數“1”標識“女款”,sklearn中提供了LabelEncoder和OrdinalEncoder兩個類用以實作對資料的不同取值以數字標識,LabelEncoder和OrdinalEncoder會自動根據提供的訓練資料進行統計,分別對每個特征屬性從0開始編碼,不同的是,LabelEncoder類一次只能對一個一維陣列(一個特征屬性)編碼,而OrdinalEncoder能同時對各個特征屬性編碼:
enc = preprocessing.LabelEncoder() # 只能接受一個一維陣列 X = ['紅色', '白色', '綠色'] enc.fit(X) X_ = enc.transform(X) X_Out[89]:
array([1, 0, 2])In [83]:
enc = preprocessing.OrdinalEncoder() # 可以同時多通過特征屬性編碼 X = [['女款', 'X', '綠色'], ['女款', 'XL', '紅色'], ['男款', 'XXL', '白色']] enc.fit(X) X_ = enc.transform(X) X_Out[83]:
array([[0., 0., 2.],
[0., 1., 1.],
[1., 2., 0.]])
In [84]:
enc.inverse_transform(X_) # 可以使用inverse_transform逆轉Out[84]:
array([['女款', 'X', '綠色'],
['女款', 'XL', '紅色'],
['男款', 'XXL', '白色']], dtype=object)
但在很多模型中,使用整數編碼并不合理,特別是在聚類這類需要計算空間距離的演算法模型,仔細觀察上面編碼,顏色這一屬性有三種取值(綠色、紅色、白色),分別以(2,1,0)表示,顏色之間是沒有大小意義的,但以三個數字表示后,就賦予了三種屬性值大小上的意義,且在演算法計算距離時,綠色(2)到白色(0)的距離比紅色(1)到白色(0)大,這是不合理的,
對于這類取值沒有大小意義的離散型特征屬性,有一種更加合適的編碼方式:獨熱編碼,
(2)獨熱編碼
獨熱編碼即 One-Hot 編碼,其方法是使用N位狀態暫存器來對N個狀態進行編碼,每個狀態都由他獨立的暫存器位,并且在任意時候,其中只有一位有效,sklearn中提供了OneHotEncoder類用以實作對資料的獨熱編碼:
In [74]:enc = preprocessing.OneHotEncoder() X = [['女款', 'X', '綠色'], ['女款', 'XL', '紅色'], ['男款', 'XXL', '白色']] enc.fit(X) enc.transform([['男款', 'XL', '綠色']]).toarray()Out[74]:
array([[0., 1., 0., 1., 0., 0., 0., 1.]])
在上述輸出結果中,特征屬性有多少種取值經過獨熱編碼后就擴展為多少個維度,以款式為例,經過獨熱編碼后,擴展為兩個維度,第一維中1表示是女款,0表示非女款,
在實體化OneHotEncoder類時,可以通過categories引數指定各特征屬性的所有類別,這樣即使存在訓練資料中沒有出現的類別,在后續出現時也能正確編碼:
style = ['女款', '男款'] size = [ 'X','XL','XXL'] color = ['綠色','紅色','白色'] enc = preprocessing.OneHotEncoder(categories=[style, size, color]) X = [['女款', 'X', '綠色'], ['女款', 'XL', '紅色']] enc.fit(X) enc.transform(X).toarray()Out[76]:
array([[1., 0., 1., 0., 0., 1., 0., 0.],
[1., 0., 0., 1., 0., 0., 1., 0.]])
In [78]:
enc.transform([['男款', 'XXL', '白色']]).toarray() # 男款,XXL,白色三個屬性值均為在X中出現,但是可以正確編碼Out[78]:
array([[0., 1., 0., 0., 1., 0., 0., 1.]])
創建好OneHotEncoder類實體并通過訓練資料后,就可以對后續的資料進行獨熱編碼,但是,有時候卻不可避免地出現categories和訓練資料集中都未出現過的取值,這時候繼續編碼就會拋出例外,為了防止這一情況發生,我們可以在創建OneHotEncoder實體時,傳入引數handle_unknown='ignore',這樣的話,如果出現某一特征屬性值未在categories和訓練資料集中出現過,通過熱獨編碼時,該特征屬性多對應的維度都會以0來填充,
In [82]:style = ['女款', '男款'] size = [ 'X','XL'] color = ['綠色','紅色'] enc = preprocessing.OneHotEncoder(categories=[style, size, color],handle_unknown='ignore') X = [['女款', 'X', '綠色'], ['女款', 'XL', '紅色']] enc.fit(X) enc.transform([['男款', 'XXL', '白色']]).toarray() # XXL, 白色在categories和X中都為出現過Out[82]:
array([[0., 1., 0., 0., 0., 0.]])
獨熱編碼解決了離散型屬性難以有效刻畫的問,在一定程度上也起到了擴充特征的作用,它的值只有0和1,不同的型別存盤在垂直的空間,當類別的數量很多時,特征空間會變得非常大,在這種情況下,一般可以用PCA來減少維度,而且one hot encoding+PCA這種組合在實際中也非常有用,
5 連續型特征屬性離散化¶
有時候,將連續型特征屬性離散化能夠顯著提高模型的表現力,連續型特征屬性離散化包括二值化和分段等方法,
(1)二值化
二值化是指通過一個閾值對屬性值進行劃分,當小于這個閾值時,將值映射為0,大于閾值時映射為1,二值化是對文本計數資料的常見操作,分析人員可以決定僅考慮某種現象的存在與否,它還可以用作考慮布爾隨機變數的估計器的預處理步驟(例如,使用貝葉斯設定中的伯努利分布建模),
sklearn中提供了Binarizer實作二值化,默認閾值為0,也就是將非正數映射為0,將正數映射為1,也可以在實體化時通過引數threshold,設定其他閾值,
X = [[ 1., -1., 2.], [ 2., -4., 0.], [ 3., 2., -1.]] binarizer = preprocessing.Binarizer().fit(X) binarizerOut[90]:
Binarizer(copy=True, threshold=0.0)In [91]:
binarizer.transform(X)Out[91]:
array([[1., 0., 1.],
[1., 0., 0.],
[1., 1., 0.]])
In [92]:
binarizer = preprocessing.Binarizer(threshold=1.5).fit(X) binarizer.transform(X)Out[92]:
array([[0., 0., 1.],
[1., 0., 0.],
[1., 1., 0.]])
(2)分段
二值化只能將資料映射為兩個值,分段可以對資料進行排序后分為多個部分然后進行編碼,在sklearn中,分段操作通過KBinsDiscretizer類進行,KBinsDiscretizer類有三個重要引數,必須了解一下:
X = [[-2, 1, -4, -1], [-1, 2, -3, -0.5], [ 0, 3, -2, 0.5], [ 1, 4, -1, 2]] est = preprocessing.KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform').fit(X) est.transform(X)Out[97]:
array([[0., 0., 0., 0.],
[1., 1., 1., 0.],
[2., 2., 2., 1.],
[2., 2., 2., 2.]])
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/37823.html
標籤:大數據
