1. 程式人生 > >OneHotEncoder獨熱編碼和LabelEncoder標籤編碼

OneHotEncoder獨熱編碼和LabelEncoder標籤編碼

OneHotEncoder獨熱編碼

學習sklearn和kagggle時遇到的問題,什麼是獨熱編碼?為什麼要用獨熱編碼?什麼情況下可以用獨熱編碼?以及和其他幾種編碼方式的區別。     首先了解機器學習中的特徵類別:連續型特徵和離散型特徵。      拿到獲取的原始特徵,必須對每一特徵分別進行歸一化,比如,特徵A的取值範圍是[-1000,1000],特徵B的取值範圍是[-1,1].如果使用logistic迴歸,w1*x1+w2*x2,因為x1的取值太大了,所以x2基本起不了作用。所以,必須進行特徵的歸一化,每個特徵都單獨進行歸一化。     對於連續性特徵: Rescale bounded continuous features: All continuous input that are bounded, rescale them to [-1, 1] through x = (2x - max - min)/(max - min).    線性放縮到[-1,1] Standardize all continuous features: All continuous input should be standardized and by this I mean, for every continuous feature, compute its mean (u) and standard deviation (s) and do x = (x - u)/s.       放縮到均值為0,方差為1 Binarize categorical/discrete features: 對於離散的特徵基本就是按照one-hot(獨熱)編碼,該離散特徵有多少取值,就用多少維來表示該特徵。

一. 什麼是獨熱編碼?        

獨熱碼,在英文文獻中稱做 one-hot code, 直觀來說就是有多少個狀態就有多少位元,而且只有一個位元為1,其他全為0的一種碼制。舉例如下:     假如有三種顏色特徵:紅、黃、藍。 在利用機器學習的演算法時一般需要進行向量化或者數字化。那麼你可能想令 紅=1,黃=2,藍=3. 那麼這樣其實實現了標籤編碼,即給不同類別以標籤。然而這意味著機器可能會學習到“紅<黃<藍”,但這並不是我們的讓機器學習的本意,只是想讓機器區分它們,並無大小比較之意。所以這時標籤編碼是不夠的,需要進一步轉換。因為有三種顏色狀態,所以就有3個位元。

即紅色:1 0 0 ,黃色: 0 1 0,藍色:0 0 1 。如此一來每兩個向量之間的距離都是根號2,在向量空間距離都相等,所以這樣不會出現偏序性,基本不會影響基於向量空間度量演算法的效果。    

自然狀態碼為:000,001,010,011,100,101    

獨熱編碼為:000001,000010,000100,001000,010000,100000 

來一個sklearn的例子:

from sklearn import preprocessing
enc = preprocessing.OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])    # fit來學習編碼
enc.transform([[0, 1, 3]]).toarray()    # 進行編碼

 輸出:array([[ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  1.]])

資料矩陣是4*3,即4個數據,3個特徵維度。

0 0 3       觀察左邊的資料矩陣,第一列為第一個特徵維度,有兩種取值0\1. 所以對應編碼方式為10 、01

1 1 0       同理,第二列為第二個特徵維度,有三種取值0\1\2,所以對應編碼方式為100、010、001

0 2 1       同理,第三列為第三個特徵維度,有四中取值0\1\2\3,所以對應編碼方式為1000、0100、0010、0001

1 0 2    

再來看要進行編碼的引數[0 , 1,  3], 0作為第一個特徵編碼為10,  1作為第二個特徵編碼為010, 3作為第三個特徵編碼為0001.  故此編碼結果為 1 0 0     1 0 0      0 0 1 

二. 為什麼要獨熱編碼?      

 正如上文所言,獨熱編碼(啞變數 dummy variable)是因為大部分演算法是基於向量空間中的度量來進行計算的,為了使非偏序關係的變數取值不具有偏序性,並且到圓點是等距的。使用one-hot編碼,將離散特徵的取值擴充套件到了歐式空間,離散特徵的某個取值就對應歐式空間的某個點。將離散型特徵使用one-hot編碼,會讓特徵之間的距離計算更加合理離散特徵進行one-hot編碼後,編碼後的特徵,其實每一維度的特徵都可以看做是連續的特徵。就可以跟對連續型特徵的歸一化方法一樣,對每一維特徵進行歸一化。比如歸一化到[-1,1]或歸一化到均值為0,方差為1。         

  為什麼特徵向量要對映到歐式空間?    

將離散特徵通過one-hot編碼對映到歐式空間,是因為,在迴歸,分類,聚類等機器學習演算法中,特徵之間距離的計算或相似度的計算是非常重要的,而我們常用的距離或相似度的計算都是在歐式空間的相似度計算,計算餘弦相似性,基於的就是歐式空間。

三 .獨熱編碼優缺點

優點:獨熱編碼解決了分類器不好處理屬性資料的問題,在一定程度上也起到了擴充特徵的作用。它的值只有0和1,不同的型別儲存在垂直的空間。

缺點:當類別的數量很多時,特徵空間會變得非常大。在這種情況下,一般可以用PCA來減少維度。而且one hot encoding+PCA這種組合在實際中也非常有用。

四. 什麼情況下(不)用獨熱編碼?

用:獨熱編碼用來解決類別型資料的離散值問題,

不用:將離散型特徵進行one-hot編碼的作用,是為了讓距離計算更合理,但如果特徵是離散的,並且不用one-hot編碼就可以很合理的計算出距離,那麼就沒必要進行one-hot編碼。 有些基於樹的演算法在處理變數時,並不是基於向量空間度量,數值只是個類別符號,即沒有偏序關係,所以不用進行獨熱編碼。  Tree Model不太需要one-hot編碼: 對於決策樹來說,one-hot的本質是增加樹的深度。

總的來說,要是one hot encoding的類別數目不太多,建議優先考慮。 

五.  什麼情況下(不)需要歸一化?

需要: 基於引數的模型或基於距離的模型,都是要進行特徵的歸一化。

不需要:基於樹的方法是不需要進行特徵的歸一化,例如隨機森林,bagging 和 boosting等。

六.  標籤編碼LabelEncoder 作用:

利用LabelEncoder() 將轉換成連續的數值型變數。即是對不連續的數字或者文字進行編號例如:

# coding:utf-8
from sklearn import preprocessing
 
le = preprocessing.LabelEncoder()
le.fit(["Japan", "china", "Japan", "Korea","china"])
print('標籤個數:%s' % le.classes_)
print('標籤值標準化:%s' % le.transform(["Japan", "china", "Japan", "Korea","china"]))
print('標準化標籤值反轉:%s' % le.inverse_transform([0, 2 ,0 ,1 ,2]))
 
# 標籤個數:['Japan' 'Korea' 'china']
# 標籤值標準化:[0 2 0 1 2]
# 標準化標籤值反轉:['Japan' 'china' 'Japan' 'Korea' 'china']
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit([1,5,67,100])
le.transform([1,1,100,67,5])

 輸出: array([0,0,3,2,1]) 

>>> le = preprocessing.LabelEncoder()
>>> le.fit(["paris", "paris", "tokyo", "amsterdam"])
LabelEncoder()
>>> list(le.classes_)
['amsterdam', 'paris', 'tokyo']     # 三個類別分別為0 1 2
>>> le.transform(["tokyo", "tokyo", "paris"]) 
array([2, 2, 1]...)    
>>> list(le.inverse_transform([2, 2, 1]))   # 逆過程
['tokyo', 'tokyo', 'paris']

限制:上文顏色的例子已經提到標籤編碼了。Label encoding在某些情況下很有用,但是場景限制很多。再舉一例:比如有[dog,cat,dog,mouse,cat],我們把其轉換為[1,2,1,3,2]。這裡就產生了一個奇怪的現象:dog和mouse的平均值是cat。所以目前還沒有發現標籤編碼的廣泛使用

下面不是很懂,以後再完善:

基本的機器學習過程

我們使用sklearn進行虛線框內的工作(sklearn也可以進行文字特徵提取)。通過分析sklearn原始碼,我們可以看到除訓練,預測和評估以外,處理其他工作的類都實現了3個方法:fit、transform和fit_transform。從命名中可以看到,fit_transform方法是先呼叫fit然後呼叫transform,我們只需要關注fit方法和transform方法即可。  

  transform方法主要用來對特徵進行轉換。從可利用資訊的角度來說,轉換分為無資訊轉換和有資訊轉換。無資訊轉換是指不利用任何其他資訊進行轉換,比如指數、對數函式轉換等。有資訊轉換從是否利用目標值向量又可分為無監督轉換和有監督轉換。無監督轉換指只利用特徵的統計資訊的轉換,統計資訊包括均值、標準差、邊界等等,比如標準化、PCA法降維等。有監督轉換指既利用了特徵資訊又利用了目標值資訊的轉換,比如通過模型選擇特徵、LDA法降維等。通過總結常用的轉換類,我們得到下表:

 不難看到,只有有資訊的轉換類的fit方法才實際有用,顯然fit方法的主要工作是獲取特徵資訊和目標值資訊,在這點上,fit方法和模型訓練時的fit方法就能夠聯絡在一起了:都是通過分析特徵和目標值,提取有價值的資訊,對於轉換類來說是某些統計量,對於模型來說可能是特徵的權值係數等。另外,只有有監督的轉換類的fit和transform方法才需要特徵和目標值兩個引數。fit方法無用不代表其沒實現,而是除合法性校驗以外,其並沒有對特徵和目標值進行任何處理,Normalizer的fit方法實現如下

def fit(self, X, y=None):
        """Do nothing and return the estimator unchanged
        This method is just there to implement the usual API and hence
        work in pipelines.
        """
        X = check_array(X, accept_sparse='csr')
        return self