OneHotEncoder獨熱編碼和 LabelEncoder標簽編碼
學習sklearn和kagggle時遇到的問題,什麽是獨熱編碼?為什麽要用獨熱編碼?什麽情況下可以用獨熱編碼?以及和其他幾種編碼方式的區別。
首先了解機器學習中的特征類別:連續型特征和離散型特征
拿到獲取的原始特征,必須對每一特征分別進行歸一化,比如,特征A的取值範圍是[-1000,1000],特征B的取值範圍是[-1,1].如果使用logistic回歸,w1*x1+w2*x2,因為x1的取值太大了,所以x2基本起不了作用。所以,必須進行特征的歸一化,每個特征都單獨進行歸一化。
對於連續性特征:
- Rescale bounded continuous features
- 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() 將轉換成連續的數值型變量。即是對不連續的數字或者文本進行編號例如:
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。所以目前還沒有發現標簽編碼的廣泛使用。
附:基本的機器學習過程
參考:
Quora:What are good ways to handle discrete and continuous inputs together?
數據預處理:獨熱編碼(One-Hot Encoding)
使用sklearn優雅地進行數據挖掘
數據挖掘比賽通用框架
Label Encoding vs One Hot Encoding
[scikit-learn] 特征二值化編碼函數的一些坑
OneHotEncoder獨熱編碼和 LabelEncoder標簽編碼