機器學習筆記:利用scikit-learn進行數據預處理

為什麼要對數據進行預處理?

真實世界的數據是非常原始的。通常來說,這些數據中會有很多的缺失值;數據中包含了噪音,如outlier;數據中很多地方互相矛盾等。如果我們不對數據進行預處理,就會出現Garbage in, garbage out的尷尬局面。本文是我整理搬運參考資料並結合我所學知識而得。

特徵縮放

在機器學習問題中,如果我們選擇的訓練特徵之間的數值相差特別巨大(比如某人一年乘飛機飛行的公里數和他的年齡),那麼使用像kNN和RBF支持向量機之類的演算法訓練模型,模型就會偏向於學習數值較大的特徵二忽略其他特徵,這樣訓練出來的模型顯然是不準確的。所以我們就要把特徵縮放,讓他們所處的範圍基本相似。常見的特徵縮放有標準化(Standardization):

X_{new} = frac{X - ar X}{sigma}

其中X為特徵,ar X為該特徵均值,sigma為標準差。上述方法會把特徵值縮放到0附近。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...]])

還有一個方法就是將特徵縮放到固定的範圍。比如歸一化就可以把特徵縮放到[0,1]中:

X_{new} = frac{X - X_{min}}{X_{max} - X_{min}}

可以使用sklearn中的preprocessing.MinMaxScaler

>>> 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_minmaxarray([[ 0.5 , 0. , 1. ], [ 1. , 0.5 , 0.33333333], [ 0. , 1. , 0. ]])

使用preprocessing.MaxAbsScaler則可以將數據縮放到[-1,1]中:

>>> X_train = np.array([[ 1., -1., 2.],... [ 2., 0., 0.],... [ 0., 1., -1.]])...>>> max_abs_scaler = preprocessing.MaxAbsScaler()>>> X_train_maxabs = max_abs_scaler.fit_transform(X_train)>>> X_train_maxabs # doctest +NORMALIZE_WHITESPACE^array([[ 0.5, -1. , 1. ], [ 1. , 0. , 0. ], [ 0. , 1. , -0.5]])>>> X_test = np.array([[ -3., -1., 4.]])>>> X_test_maxabs = max_abs_scaler.transform(X_test)>>> X_test_maxabs array([[-1.5, -1. , 2. ]])>>> max_abs_scaler.scale_ array([ 2., 1., 2.])

Outlier檢測

最簡單粗暴的檢測outlier的方法可能就是通過boxplot了。但是sklearn給我們提供了三大outlier檢測利器:One-class SVM、Elliptic Envelope和Isolation Forest。以下是sklearn官網給出的三種檢測演算法的對比:

代碼篇幅較長,詳情參見Novelty and Outlier Detection。

二值化

在訓練任務中,我們常常需要將部分輸入特徵或者輸出二值化,比如將人的身高根據threshold劃分為兩類,高的或者矮的,這樣的過程就是二值化(Binarization):

X_{new}=   egin{cases}   0 & mbox{if $ Xleq threshold$} \  1 &mbox{if $X > threshold$}   end{cases}

通過二值化輸入,我們可以很輕易地將一個回歸問題轉化為二分類問題。sklearn提供了preprocessing.Binarizer()來對數據進行二值化:

>>> X = [[ 1., -1., 2.],... [ 2., 0., 0.],... [ 0., 1., -1.]]>>> binarizer = preprocessing.Binarizer().fit(X) # fit does nothing>>> binarizerBinarizer(copy=True, threshold=0.0)>>> binarizer.transform(X)array([[ 1., 0., 1.], [ 1., 0., 0.], [ 0., 1., 0.]])

One Hot Encoder

某些特徵可能會是很小範圍內的離散值,比如某數據含有特徵「物種」,取值範圍是[青蛙, 蛤蟆],最簡單的方法就是直接把「青蛙」轉換為0,把「蛤蟆」轉化為1。但是由於分類器默認輸入是連續的,這樣處理就會有諸多問題。那麼這種分類特徵(categorical features)就可以用One hot encoder處理:比如現在有一數據的「物種」被標記為「青蛙」,那麼它就會被轉化為[1,0],其中第一位1對應「青蛙」,第二位0對應「蛤蟆」;同理,若數據的「物種」被標記為「蛤蟆」,那麼這個特徵值就會被轉化為[0,1]。sklearn中的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.]])

缺失值處理

對於數據中的缺失值,最暴力的方法就是直接刪除包含缺失值得數據樣本,但是這樣這樣的做的話往往會刪除過多的數據,所以除此之外,通常還可以用平均數(mean)、中位數(median)、眾數(most_frequent)等來替換缺失值。具體可以使用preprocessing.Imputer來實現。下列代碼是用平均數來填充缺失值,通過改變strategy的值可以實現其他填充方法(中位數用median、眾數用most_frequent):

>>> 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. ]]

如果你嫌棄這種古老笨拙的方法,那麼可以使用機器學習來預測缺失值,這兒給出一個例子,也求各位大佬給出更佳方法:How to Handle Missing Data with Python, 這篇文章使用LDA來預測缺失值。

本筆記代碼摘自scikit-learn文檔,請參見Preprocessing data

推薦閱讀:

科技巨頭都愛的Data Pipeline,如何自動化你的數據工作?

TAG:機器學習 | 數據處理 |