標籤:

機器學習基礎與實踐(二)----數據轉換

------------------------------------本博客所有內容以學習、研究和分享為主,如需轉載,請聯繫本人,標明作者和出處,並且是非商業用途,謝謝!--------------------------------

系列目錄:

本文目錄:

一.標準化的原因

二.適用情況

三.三種數據變換方法的含義與應用

四.具體方法及代碼

一)標準化

  1.1 scale----零均值單位方差

1.2 StandardScaler

二)歸一化

2.1 MinMaxScaler(最小最大值標準化)

2.2 MaxAbsScaler(絕對值最大標準化)

2.3 對稀疏數據進行標準化

2.4 對離群點進行標準化

三)正則化

  3.1 L1、L2正則化

四)二值化

  4.1特徵二值化

五)對類別特徵進行編碼

六)缺失值的插補

七)生成多項式特徵

八)自定義轉換

本文目錄:

一.標準化的原因

二.適用情況

三.三種數據變換方法的含義與應用

四.具體方法及代碼

一)標準化

  1.1 scale----零均值單位方差

1.2 StandardScaler

二)歸一化

2.1 MinMaxScaler(最小最大值標準化)

2.2 MaxAbsScaler(絕對值最大標準化)

2.3 對稀疏數據進行標準化

2.4 對離群點進行標準化

三)正則化

  3.1 L1、L2正則化

四)二值化

  4.1特徵二值化

五)對類別特徵進行編碼

六)缺失值的插補

七)生成多項式特徵

八)自定義轉換

正文:

一.標準化的原因

通常情況下是為了消除量綱的影響。譬如一個百分制的變數與一個5分值的變數在一起怎麼比較?只有通過數據標準化,都把它們標準到同一個標準時才具有可比性,一般標準化採用的是Z標準化,即均值為0,方差為1,當然也有其他標準化,比如0--1標準化等等,可根據自己的數據分布情況和模型來選擇

二.適用情況

  看模型是否具有伸縮不變性。

不是所有的模型都一定需要標準化,有些模型對量綱不同的數據比較敏感,譬如SVM等。當各個維度進行不均勻伸縮後,最優解與原來不等價,這樣的模型,除非原始數據的分布範圍本來就不叫接近,否則必須進行標準化,以免模型參數被分布範圍較大或較小的數據主導。但是如果模型在各個維度進行不均勻伸縮後,最優解與原來等價,例如logistic regression等,對於這樣的模型,是否標準化理論上不會改變最優解。但是,由於實際求解往往使用迭代演算法,如果目標函數的形狀太「扁」,迭代演算法可能收斂得很慢甚至不收斂。所以對於具有伸縮不變性的模型,最好也進行數據標準化。

三.三種數據變換方法的含義與應用

  Rescaling(重縮放/歸一化):通常是指增加或者減少一個常數,然後乘以/除以一個常數,來改變數據的衡量單位。例如:將溫度的衡量單位從攝氏度轉化為華氏溫度。

  Normalizing(正則化):通常是指除以向量的範數。例如:將一個向量的歐氏長度等價於1 。在神經網路中,「正則化」通常是指將向量的範圍重縮放至最小化或者一定範圍,使所有的元素都在[0,1]範圍內。通常用於文本分類或者文本聚類中。

  Standardizing(標準化):通常是為了消除不同屬性或樣方間的不齊性,使同一樣方內的不同屬性間或同一屬性在不同樣方內的方差減小。例如:如果一個向量包含高斯分布的隨機值,你可能會通過除以標準偏差來減少均值,然後獲得零均值單位方差的「標準正態」隨機變數。

  那麼問題是,當我們在訓練模型的時候,一定要對數據進行變換嗎?這得視情況而定。很多人對多層感知機有個誤解,認為輸入的數據必須在[0,1]這個範圍內。雖然標準化後在訓練模型效果會更好,但實際上並沒有這個要求。但是最好使輸入數據中心集中在0周圍,所以把數據縮放到[0,1]其實並不是一個好的選擇。

  如果你的輸出激活函數的範圍是[0,1](sigmoid函數的值域),那你必須保證你的目標值也在這個範圍內。但通常請款下,我們會使輸出激活函數的範圍適應目標函數的分布,而不是讓你的數據來適應激活函數的範圍。

  當我們使用激活函數的範圍為[0,1]時,有些人可能更喜歡把目標函數縮放到[0.1,0.9]這個範圍。我懷疑這種小技巧的之所以流行起來是因為反向傳播的標準化太慢了導致的。但用這種方法可能會使輸出的後驗概率值不對。如果你使用一個有效的訓練演算法的話,完全不需要用這種小技巧,也沒有必要去避免溢出(overflow)

四.具體方法及代碼

一)標準化

  1.1 scale----零均值單位方差

 1.2 StandardScaler----計算訓練集的平均值和標準差,以便測試數據集使用相同的變換

註:1)若設置with_mean=False 或者 with_std=False,則不做centering 或者scaling處理。

  2)scale和StandardScaler可以用於回歸模型中的目標值處理。

二)歸一化----將數據特徵縮放至某一範圍(scalingfeatures to a range)

  另外一種標準化方法是將數據縮放至給定的最小值與最大值之間,通常是0與1之間,可用MinMaxScaler實現。或者將最大的絕對值縮放至單位大小,可用MaxAbsScaler實現。

使用這種標準化方法的原因是,有時數據集的標準差非常非常小,有時數據中有很多很多零(稀疏數據)需要保存住0元素。

2.1 MinMaxScaler(最小最大值標準化)

  公式:X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) ;

     X_scaler = X_std/ (max - min) + min

2.2 MaxAbsScaler(絕對值最大標準化)

  與上述標準化方法相似,但是它通過除以最大值將訓練集縮放至[-1,1]。這意味著數據已經以0為中心或者是含有非常非常多0的稀疏數據。

其實在scale模塊里,也提供了這兩種方法: minmax_scalemaxabs_scale

2.3 對稀疏數據進行標準化

  對稀疏數據進行中心化會破壞稀疏數據的結構,這樣做沒什麼意義。但是我們可以對稀疏數據的輸入進行標準化,尤其是特徵在不同的標準時。MaxAbsScalermaxabs_scale是專門為稀疏數據設計的,也是常用的方法。但是scaleStandardScaler只接受scipy.sparse的矩陣作為輸入,並且必須設置with_centering=False。否則會出現 ValueError且破壞稀疏性,而且還會無意中分配更多的內存導致內存崩潰。RobustScaler不適用於稀疏數據的輸入,但是你可以用 transform 方法。

  scalers接受壓縮的稀疏行(Compressed Sparse Rows)和壓縮的稀疏列(Compressed Sparse Columns)的格式(具體參考scipy.sparse.csr_matrix 和scipy.sparse.csc_matrix)。其他的稀疏格式會被轉化成壓縮的稀疏行(Compressed Sparse Rows)格式。為了避免這種不必要的內存拷貝,推薦使用CSR或者CSC的格式。如果數據很小,可以在稀疏矩陣上運用toarray 方法。

2.4 對離群點進行標準化

  如果你的數據有離群點(上一篇我們提到過),對數據進行均差和方差的標準化效果並不好。這種情況你可以使用robust_scaleRobustScaler 作為替代。它們有對數據中心化和數據的縮放魯棒性更強的參數。

三)正則化

  3.1 L1、L2正則化

註:稀疏數據輸入:

normalizeNormalizer 既接受稠密數據(dense array-like),也接受稀疏矩陣(from scipy.sparse)作為輸入

稀疏數據需要轉換成壓縮的稀疏行(Compressed Sparse Rows)格式(詳見scipy.sparse.csr_matrix),為了避免不必要的內存拷貝,推薦使用CSR。

四)二值化

  4.1特徵二值化

特徵二值化是把數值特徵轉化成布爾值的過程。這個方法對符合多變數伯努利分布的輸入數據進行預測概率參數很有效。詳細可以見這個例子sklearn.neural_network.BernoulliRBM.

此外,在文本處理中也經常會遇到二值特徵值(很可能是為了簡化概率推理),即使在實際中正則化後的詞頻或者TF-IDF的值通常只比未正則化的效果好一點點。

對於 NormalizerBinarizer工具類通常是在Pipeline階段(sklearn.pipeline.Pipeline)的前期過程會用到。下面舉一個具體的例子:

註:稀疏數據輸入:

binarizeBinarizer 既接受稠密數據(dense array-like),也接受稀疏矩陣(from scipy.sparse)作為輸入

稀疏數據需要轉換成壓縮的稀疏行(Compressed Sparse Rows)格式(詳見scipy.sparse.csr_matrix),為了避免不必要的內存拷貝,推薦使用CSR。

五)對類別特徵進行編碼

  我們經常會遇到一些類別特徵,這些特徵不是離散型的數值,而是這樣的:["男性","女性"],["來自歐洲","來自美國","來自亞洲"],["使用Firefox瀏覽器","使用Chrome瀏覽器","使用Safari瀏覽器","使用IE瀏覽器"]等等。這種類型的特徵可以被編碼為整型(int),如["男性","來自美國","使用IE瀏覽器"]可以表示成[0,1,3],["女性","來自亞洲","使用Chrome瀏覽器"]可以表示成[1,2,1]。這些整數式的表示不能直接作為sklearn的參數,因為我們需要的是連續型的輸入,而且我們通常是有序的翻譯這些特徵,而不是所有的特徵都是有序化的(譬如瀏覽器就是按人工排的序列)。

  將這些類別特徵轉化成sklearn參數中可以使用的方法是:使用one-of-K或者one-hot編碼(獨熱編碼OneHotEncoder)。它可以把每一個有m種類別的特徵轉化成m中二值特徵。舉例如下:

默認情況下,特徵的類別數量是從數據集里自動判斷出來的。當然,你也可以用n_values這個參數。我們剛剛舉的例子中有兩種性別,三種地名和四種瀏覽器,當我們fit之後就可以將我們的數據轉化為數值了。從結果中來看,第一個數字代表性別([0,1]代表男性,女性),第二個數字代表地名([0,1,2]代表歐洲、美國、亞洲),最後一個數字代表瀏覽器([3,0,1,2]代表四種瀏覽器)

  此外,字典格式也可以編碼: Loading features from dicts

  OneHotEncoder參數:class sklearn.preprocessing.OneHotEncoder(n_values=auto, categorical_features=all, dtype=<class float>, sparse=True, handle_unknown=error)github.com/scikit-learn

n_values : 『auto』, int or array of ints

每個特徵的數量

    • 『auto』 : 從訓練數據的範圍中得到
    • int : 所有特徵的最大值(number)
    • array : 每個特徵的最大值(number)

categorical_features: 「all」 or array of indices or mask :

確定哪些特徵是類別特徵

    • 『all』 (默認): 所有特徵都是類別特徵,意味著所有特徵都要進行OneHot編碼
    • array of indices: 類別特徵的數組索引
    • mask: n_features 長度的數組,切dtype = bool

  非類別型特徵通常會放到矩陣的右邊

dtype : number type, default=np.float

  輸出數據的類型

sparse : boolean, default=True

  設置True會返回稀疏矩陣,否則返回數組

handle_unknown : str, 『error』 or 『ignore』

  當一個不明類別特徵出現在變換中時,報錯還是忽略

六)缺失值的插補

  上篇我們講了五種方法來解決缺失值的問題,其實sklearn里也有一個工具Imputer可以對缺失值進行插補。Imputer類可以對缺失值進行均值插補、中位數插補或者某行/列出現的頻率最高的值進行插補,也可以對不同的缺失值進行編碼。並且支持稀疏矩陣。

在稀疏矩陣中,缺失值被編碼為0存儲為矩陣中,這種格式是適合於缺失值比非缺失值多得多的情況。此外,Imputer類也可以用於Pipeline中

  Imputor類的參數:class sklearn.preprocessing.Imputer(missing_values=NaN, strategy=mean, axis=0, verbose=0, copy=True)github.com/scikit-learn

missing_values : int或"NaN",默認NaN(String類型)

strategy : string, 默認為mean,可選則mean、median、most_frequent

axis :int, 默認為0(axis = 0,對列進行插值;axis= 1,對行進行插值)

verbose : int, 默認為0

copy : boolean, 默認為True

  True:會創建一個X的副本

  False:在任何合適的地方都會進行插值。

  但是以下四種情況,計算設置的copy = Fasle,也會創建一個副本:

  1.X不是浮點型數組

  2.X是稀疏矩陣,而且miss_value = 0

  3.axis= 0,X被編碼為CSR矩陣

       4.axis= 1,X被編碼為CSC矩陣

  舉個實例(在用隨機森林演算法之前先用Imputer類進行處理):

結果:

七)生成多項式特徵

  在輸入數據中增加非線性特徵可以有效的提高模型的複雜度。簡單且常用的方法就是使用多項式特徵(polynomial features),可以得到特徵的高階交叉項:

 然而有時候我們只需要特徵的交叉項,可以設置interaction_only=True來得到:

這個方法可能大家在工作中比較少見,但世界上它經常用於核方法中,如選擇多項式核時 ( sklearn.svm.SVC, sklearn.decomposition.KernelPCA)

八)自定義轉換

  如果以上的方法覺得都不夠,譬如你想用對數據取對數,可以自己用 FunctionTransformer自定義一個轉化器,並且可以在Pipeline中使用

告訴你怎麼用:

  如果你在做一個分類任務時,發現第一主成分與這個不相關,你可以用FunctionTransformer把第一列除去,剩下的列用PCA:

結果:

  寫到這裡基本上關於數據轉化的方法已經介紹的差不多了,周四寫第三篇--數據降維。寫的比較倉促,有錯誤的歡迎提出來~

作者:胡曉曼 Python愛好者社區專欄作者,請勿轉載,謝謝。

博客專欄:CharlotteDataMining的博客專欄

配套視頻教程:三個月教你從零入門深度學習!| 深度學習精華實踐課程

公眾號:Python愛好者社區(微信ID:python_shequ),關注,查看更多連載內容。

推薦閱讀:

十分種讀懂KNN
一文弄懂神經網路中的反向傳播法——BackPropagation
機器學習入門之邏輯回歸分類
如何六個月內學會深度學習

TAG:機器學習 |