數據預處理是進行機器學習的必要環節,對原始數據進行加工,比如標準化、歸一化、二進制化、特征編碼、插補缺失值、生成多項式特征等。
scikit-learn 是 Python 下的機器學習工具包,集成了預處理、降維、聚類、分類等方法。我們用此工具來介紹數據預處理。
主要應用的是 preprocessing 類。
標準化 Standardization
常用的標準化方法為 z-score 法,目的是將傳入的矩陣變為每列均值為0、方差為1的標準型,因為機器學習中的函數許多是以0為中心的,例如 sigmoid 函數,方差為1可以使數據分布均勻,防止某個特征數據過大影響模型的訓練。
我們用 sklearn 中的 preprocessing 類中的 scale 方法簡單進行標準化。
>>> from sklearn import preprocessing
>>> import numpy as np
>>> X = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
>>> X_scaled = preprocessing.scale(X)
>>> X_scaled
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
或者可以將計算均值和方差與轉換的步驟分開。
>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.transform(X)
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
fit 是計算過程,transform 是轉換過程。transform 的一個好處是可以繼續使用 fit 的數據,例如 transform 訓練數據之后之后可以直接 transform 測試數據。
有時標準化時要求把數據縮放到某一個范圍中,preprocessing 類也提供了 MinMaxScaler 方法,設置 MinMaxScaler 的參數 feature_range=(min, max) 。
當然最常用的就是(0,1)范圍。
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
...
>>> min_max_scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[ 0.5 , 0. , 1. ],
[ 1. , 0.5 , 0.33333333],
[ 0. , 1. , 0. ]])
歸一化 Normalization
歸一化是將每個樣本縮放到單位范數(可以粗略地理解為向量的函數)的過程。如果后面要使用如二次型(點積)或者其它核方法計算兩個樣本之間的相似性這個方法會很有用。歸一化的計算方法是 1除以p-范數。歸一化之后的樣本的 p-范數等于1。
preprocessing 類下的 normalize 方法可以直接歸一化,并可以選擇 l1 范數與 l2 范數,默認是 l2 范數。
>>> X = [[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')
>>> X_normalized
array([[ 0.40..., -0.40..., 0.81...],
[ 1. ..., 0. ..., 0. ...],
[ 0. ..., 0.70..., -0.70...]])
normalize 也同樣有 fit 方法與 transform 方法。
>>> normalizer = preprocessing.Normalizer().fit(X) # fit does nothing
>>> normalizer
Normalizer(copy=True, norm='l2')
>>> normalizer.transform(X)
array([[ 0.40..., -0.40..., 0.81...],
[ 1. ..., 0. ..., 0. ...],
[ 0. ..., 0.70..., -0.70...]])
.
>>> normalizer.transform([[-1., 1., 0.]])
array([[-0.70..., 0.70..., 0. ...]])
二進制化 Binarization
二進制化的方法是設定一個閾值,樣本值比閾值大的為1,小的為0。
文本處理領域愿意使用二進制化,雖然歸一化和 TF-IDF 加工的特征表現得更好,但使用二進制化來簡化數據更為普遍(可能簡化概率推理)。
>>> X = [[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]]
>>> binarizer = preprocessing.Binarizer().fit(X) # fit does nothing
>>> binarizer
Binarizer(copy=True, threshold=0.0)
>>> binarizer.transform(X)
array([[ 1., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.]])
閾值調整需要設置 threshold 參數,下面代碼是設置閾值1.1的情況。
>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 0., 0.]])
類別特征編碼 Encoding categorical features
比如現在有特征 ["male", "female"] ["from Europe", "from US", "from Asia"],
["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"],
平常我們將特征進行整數編碼.
["male", "from US", "uses Internet Explorer"] 編碼應該是 [0, 1, 3]。
["female", "from Asia", "uses Chrome"]的編碼應該是[1,2,1]。
但是 scikit-learn 估計器不能直接使用這種整數型的編碼,它的輸入最好是連續型的,估計器也可能把整數編碼特征特征誤解為有序的數據,這會有害于模型訓練。
類別特征編碼用的是 OneHotEncoder 方法,占第幾位的特征值就是1,其余為0。例如 ["male", "female"] 有兩個特征,male 占第1個位置,剩下的0,male 就是 [1,0],female 就是 [0,1]; ["from Europe", "from US", "from Asia"]有3個特征,"from Europe"就是 [1,0,0],"from US" 就是 [0,1,0],"from Asia"就是 [0,0,1],以此類推。
["male", "from US", "uses Internet Explorer"]的整數編碼[0,1,3]的二進制編碼就是
[1,0, 0,1,0, 0,0,0,1]。
代碼實現用的是 preprocessing 類下的 OneHotEncoder 方法。
>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
OneHotEncoder(categorical_features='all', dtype=<... 'numpy.float64'>,
handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 1, 3]]).toarray()
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
插補缺失值 Imputation of missing values
以往對于數據中有丟失值的情況,做法是把該數據所在行和列都刪掉,這樣的后果是容易丟失重要的數據。
imputer 的方法利用平均值、中位數或出現頻率最高的數據對缺失的數據進行填補。代碼如下,NaN 即位丟失的值。
>>> import numpy as np
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
strategy 告訴了本代碼用 mean 平均值找補,fit 是用它括號里的數據計算平均值,transform 是應用變換。
生成多項式特征 Generating polynomial features
生成多項式的預處理方式是為了給輸入數據增加復雜性。處理后的特征會獲得高階的數據和交叉的數據。
用到的是 preprocessing 下的 PolynomialFeatures 方法。
>>> import numpy as np
>>> from sklearn.preprocessing import PolynomialFeatures
>>> X = np.arange(6).reshape(3, 2)
>>> X
array([[0, 1],
[2, 3],
[4, 5]])
>>> poly = PolynomialFeatures(2)
>>> poly.fit_transform(X)
array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])
PolynomialFeatures(2) 指的是最多生成二次項。
X的特征值由(X1,X2)變成了(1,X1,X2,X12,X1X2,X22)。