1. 程式人生 > >sklearn中的資料預處理

sklearn中的資料預處理

1.介紹

klearn.preprocessing提供了各種公共函式,來將raw feature vetor轉換成另外一種更適合評估器工作的格式。

2.標準化(Standardization)、平均移除法(mean removal)和方差歸一化(variance scaling)

資料集的標準化,在scikit中,對於眾多機器學習評估器來說是必須的;如果各獨立特徵不進行標準化,結果標準正態分佈資料差距很大:比如使用均值為0、方差為1的高斯分佈.

實際上,我們經常忽略分佈的形狀,只是簡單地通過移除每個feature的均值,將資料轉換成中間值,接著通過分割非常數項的feature進行歸一化。

例如,在機器學習的目標函式(objective function),比如SVM中的RBF或者線性模型中的L1和L2正則項,其中使用的元素,前提是所有的feature都是以0為中心,且方差的階(order)都一致。如果一個feature的方差,比其它feature的階(order)都大,那麼它將在目標函式中佔支配地位,從而使得estimator從其它feature上學習不到任何東西。

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_scaled.mean(axis=0)
array([ 0., 0., 0.])

>>> X_scaled.std(axis=0)
array([ 1., 1., 1.])

preprocessing模組提供了另一個工具類:StandardScaler,它實現了Transformer API,來計算在一個訓練集上的平均值和標準差(standard deviation),同樣需要在測試集上使用相同的轉換。該類也可以應用在sklearn.pipeline.Pipeline上。

>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)

>>> scaler.mean_
array([ 1. ..., 0. ..., 0.33...])

>>> scaler.scale_
array([ 0.81..., 0.81..., 1.24...])

>>> scaler.transform(X)
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])

scaler例項,可以用在新資料上,並可以以相同的方式在訓練集上轉換:

>>> scaler.transform([[-1.,  1., 0.]])                
array([[-2.44..., 1.22..., -0.26...]])

通過在StandardScaler的建構函式中設定with_mean=False 或者 with_std=False,可以禁止均值中心化(centering)和歸一化(scaling)。

2.1 將feature歸一化到一個範圍內

另一種標準化方式是,將feature歸一化到給定的最大、最小值範圍內,比如:[0,1]之間,這樣,每個feature的最大絕對值為1. 可以使用:MinMaxScaler或者MaxAbsScaler。

使用歸一化的動機是,阻止sparse中的0元素,讓含有小標準差的feature變得更健壯.

下例:歸一化至[0, 1]

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

可以通過檢視scaler的屬性,來看下訓練集上的轉換是否合理.

>>> min_max_scaler.scale_                             
array([ 0.5 , 0.5 , 0.33...])

>>> min_max_scaler.min_
array([ 0. , 0.5 , 0.33...])

如果MinMaxScaler給出了顯式的範圍:feature_range=(min, max)。那麼對應完整的公式為:

X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))

X_scaled = X_std / (max - min) + min

MaxAbsScaler以相類似的方式運作,它的歸一化會介於[-1, 1]之間,通過在每個feature上分隔最大值來實現。這意味著資料已經是以0為中心的,或者是稀疏資料。

這裡我們使用一個示例資料:

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

如果你不想創造物件,scale模組提供了另外的函式: minmax_scale 和 maxabs_scale。

2.2 歸一化sparse矩陣

如果對sparse資料進行中心化,會摧毀資料的稀疏性,十分敏感。我們可以對sparse資料進行特殊的歸一化,尤其各種feature以不同的歸一化方式進行。

MaxAbsScaler 和 maxabs_scale 是專門處理稀疏資料的,強烈推薦這種方式。然而,scale 和 StandardScaler 可以接受scipy.sparse的metrics作為輸入,只要在建構函式中顯示傳入with_centering=False。否則會丟擲ValueError,打破sparsity,並且在執行時由於分配大量記憶體而經常crash。 RobustScaler 不能對稀疏資料進行fit,但是你可以在稀疏資料輸入上使用transform方法。

注意:scaler接受壓縮式稀疏資料行(Compressed Sparse Rows),以及壓縮式稀疏資料列(Compressed Sparse Columns),分別參見:scipy.sparse.csr_matrix 和 scipy.sparse.csc_matrix。其它稀疏輸入可以轉換成CSR表示。為了避免不必要的記憶體拷貝,推薦你使用CSR或者CSC表示法

最後,如果該中心化後的資料如預期般足夠小,可以通過sparse matricses的toarray方法轉成一個數組。

2.3 歸一化異常資料

如果你的資料包含許多異常項(outliers),使用均值和方差的效果不會很好。在這種情況下,我們可以使用robust_scale 和 RobustScaler作為替代。它可以在你給定的中心或者範圍內給出健壯的估計。

Scaling vs Whitening

對於獨自進行中心化和歸一化來說有時並不夠好。因為下游的模型可能會基於feature的線性獨立性做出一些假設。

你可以使用 sklearn.decomposition.PCA 或 sklearn.decomposition.RandomizedPCA,並設定whiten=True以便移除feature之間的線性相關性。

2.4 kernel matrics的中心化

如果你有一個kernel為K的kernel矩陣,通過定義函式phi計算在特徵空間內的內積(點乘),KernelCenterer可以對kernel矩陣進行轉換,以便它在移除空間的均值後,能包含通過phi函式定義的特徵空間的內積。

3.正態分佈化(Normalization)

Normalization用來將各個樣本歸一化為norm為1的正態分佈。如果你要使用二項式形式(比如點乘、或者其它kernel來確定樣本相似性)

該假設是向量空間模型(VSM)的基礎,經常用於文字分類和內容聚類。

函式 normalize 提供了一個簡單的方法來操作類似陣列的資料集,使用l1或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...]])

preprocessing模組提供了一個工具類: Normalizer。

>>> normalizer = preprocessing.Normalizer().fit(X)  # fit does nothing
>>> normalizer
Normalizer(copy=True, norm='l2')

normalizer例項可以作為轉換器被用在樣本向量上:

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

對於稀疏矩陣輸入來說:

normalize和 Normalizer同時接受dense array、或者scipy.sparse輸入。

對於sparse來說,資料被轉換成CSR形式(scipy.sparse.csr_matrix)。

4.二值化(Binarization)

Feature二值化可以將數值形(numerical)的feature進行閥值化得到boolean型資料。這對於下游的概率估計來說可能很有用(比如:資料分佈為Bernoulli分佈時)。例如,sklearn.neural_network.BernoulliRBM的case也是。

在文字處理社群中,使用二值feature也很常用(可以簡化概率模型),如果歸一化的count(比如:詞頻TF)或者TF-IDF值feature經常很有用。

對於 Normalizer來說,工具類 Binarizer可以在sklearn.pipeline.Pipeline的早期使用。

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

我們有可能調整binarizer的threshold:

>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 0., 0.]])

對於StandardScaler 或 Normalizer來說,preprocessing模組提供了另一個函式binarize。

5.將類別特徵進行編碼

經常,有些特徵並不是連續的,可能是類別化的。比如:

  • 性別:[“male”, “female”]
  • 國家:[“from Europe”, “from US”, “from Asia”]
  • 使用的瀏覽器:[“uses Firefox”, “uses Chrome”, “uses Safari”, “uses Internet Explorer”]

這樣的feature可以用整型表示,例如:

  • [“male”, “from US”, “uses Internet Explorer”]表示為:[0, 1, 3]
  • [“female”, “from Asia”, “uses Chrome”]表示為:[1, 2, 1]

一些整型表示可以被直接用在sklearn的評估器上,當成連續輸入,或者解釋成類別。

將類別feature轉換成sklearn評估器可用的feature的一種方式為:使用one-of-K,或者one-hot編碼,它可以用 OneHotEncoder來實現。該評估器將m個可能的feature類別值轉換成m個二元feature。

例如:

>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
OneHotEncoder(categorical_features='all', dtype=<... 'float'>,
handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 1, 3]]).toarray()
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])

預設的,每個feature可以取多少值可以從資料集中自動判斷。通過使用n_values引數可以顯示指定。在我們的資料集中有兩個性別(gender),三個可能的大洲(continents),還有4種瀏覽器(web browser)。我們去擬合該estimator,並進行資料轉換。在結果中,頭兩個數表示性別的編碼,接下去的3個數表示大洲的編碼,最後4個則用於瀏覽器。

6.補充缺失值

出於其他原因,現實世界中,有許多資料集中包含著缺失值(missing values),經常編碼成空格,NaN或者其它佔位符。這樣的資料集對於sklearn來說是不相容的,它認為的輸入資料必須是全是數值型的。一個基本策略是,使用不完整的資料(拋棄掉那些帶缺失值的行)。然而,缺失的資料中也有可能含有有價值的資訊(儘管不完整)。另一個更好地策略是,插入缺失值,比如:從已經資料中去模擬它們。

Imputer類提供了基本策略來補充缺失值,或者使用均值、中值、或者行中最常用的值、或者缺失值所在列中最常用的值。該類提供了不同的缺失值補充策略。

下面的程式碼段演示瞭如何使用np.nan替換缺失值,使用了包含了缺失值的列(axis 0)的均值:

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

Imputer類提支援稀疏策略:

>>> import scipy.sparse as sp
>>> X = sp.csc_matrix([[1, 2], [0, 3], [7, 6]])
>>> imp = Imputer(missing_values=0, strategy='mean', axis=0)
>>> imp.fit(X)
Imputer(axis=0, copy=True, missing_values=0, strategy='mean', verbose=0)
>>> X_test = sp.csc_matrix([[0, 2], [6, 0], [7, 6]])
>>> print(imp.transform(X_test))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]

注意,缺失值用0編碼,並被顯式地存於矩陣中。如果缺失值的數目比觀測值還要多時,這種格式很合適。

7.生成多項式特徵(polynomial features)

通常,由於考慮到輸入資料的非線性feature的存在,你的模型變複雜。一個簡單的方法是,使用多項式feature,它可以給出feature的高階表示以及交叉項(interaction terms)。通過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.]])

X的feature可以通過(X1, X2) 轉換成

在一些情況下,只有feature間的交叉項是必須的(忽略高階項),可以通過interaction_only=True來實現:

>>> X = np.arange(9).reshape(3, 3)
>>> X
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> poly = PolynomialFeatures(degree=3, interaction_only=True)
>>> poly.fit_transform(X)
array([[ 1., 0., 1., 2., 0., 0., 2., 0.],
[ 1., 3., 4., 5., 12., 15., 20., 60.],
[ 1., 6., 7., 8., 42., 48., 56., 336.]])

X的feature可以從(X1,X2,X3)轉換成

注意:多項式feature只能顯示地用在核方法(比如: sklearn.svm.SVC, sklearn.decomposition.KernelPCA)上的多項式核函式(polynomial Kernel functions)上。

Ridge regression的多項式內插(Polynomial interpolation)用它來建立多項式feature。

8.定製轉換器

通常,你需要將一個存在的python函式轉換成一個transformer來進行資料清洗和處理。你可以使用一個專用函式來實現一個轉換器: FunctionTransformer。例如,我們可以在一個pipeline上使用一個log函式來進行轉換:

 >>> import numpy as np
>>> from sklearn.preprocessing import FunctionTransformer
>>> transformer = FunctionTransformer(np.log1p)
>>> X = np.array([[0, 1], [2, 3]])
>>> transformer.transform(X)
array([[ 0. , 0.69314718],
[ 1.09861229, 1.38629436]])

詳見原文.

參考: