表述類目的變量通常,通常沒有次序概念,且取值范圍有限。例如性別行業信用卡類型。有些模型可以直接讀類別變量(例如決策樹)。有些模型不能識別類別變量(例如回歸模型,神經網絡,有距離的度量模型(svn,knn))。
當類別變量無法放入模型的時候,需要做編碼處理即以數值的形式替代原有的值:
- onehot編碼
- dummy
- 濃度編碼
- WOE編碼
我們主要用onehot編碼,dummy(啞變量)操作,通常會使得我們模型具有較強的非線性能力。
那么這兩種編碼方式是如何進行的呢?
它們之間是否有聯系?
又有什么樣的區別?
是如何提升模型的非線性能力的呢?
我們帶着這三個疑問進入特殊變量的主題:
1.為什么
這一個迷你數據集,為什么我們用1,2,3,4這樣的數據值不行呢,非要用00001,01000這樣的才可以?即為什么不直接提供標簽編碼給模型訓練就夠了?為什么需要one hot編碼?

標簽編碼的問題是它假定類別值越高,該類別更好。
讓我解釋一下:根據標簽編碼的類別值,我們的迷你數據集中VW > Acura > Honda。
比方說,假設模型內部計算平均值(神經網絡中有大量加權平均運算),那么1 + 3 = 4,4 / 2 = 2.
這意味着:VW和Honda平均一下是Acura。毫無疑問,這是一個糟糕的方案。該模型的預測會有大量誤差。
我們使用one hot編碼器對類別進行“二進制化”操作,然后將其作為模型訓練的特征,原因正在於此。
當然,如果我們在設計網絡的時候考慮到這點,對標簽編碼的類別值進行特別處理,那就沒問題。不過,在大多數情況下,使用one hot編碼是一個更簡單直接的方案。
如果原本的標簽編碼是有序的,那one hot編碼就不合適了——會丟失順序信息。
轉化成二進制編碼(如下圖所示):

2.怎么用
我們先不講各種編碼之間的差別,先講一個案例Demo,什么編碼轉化。
import pandas pd df = pd.DataFrame({'country': ['russia', 'germany', 'australia','korea','germany']}) pd.get_dummies(df,prefix=['country'])

一些機器學習技術要求,從表示中刪除一個維度,以避免變量之間的依賴性。使用“drop_first = True”來實現這一目標。
import pandas as pd # using the same example as above df = pd.DataFrame({'country': ['russia', 'germany', 'australia','korea','germany']}) pd.get_dummies(df,prefix=['country'], drop_first=True)

同時你也要修改測試集上的數據。要和訓練集保持一致才能測試的時候用。
import pandas as pd # say you want a column for "japan" too (it'll be always zero, of course) df["country"] = train_df["country"].astype('category',categories=["australia","germany","korea","russia","japan"]) # now call .get_dummies() as usual pd.get_dummies(df,prefix=['country'])
然后我們重新關注一下訓練集,我們剔除原來那一列被編碼的特征同時,把編碼特征concat回去。
df = pd.concat([df,pd.get_dummies(df['mycol'], prefix='mycol',dummy_na=True)],axis=1).drop(['mycol'],axis=1)
import pandas as pd # df now has two columns: name and country df = pd.DataFrame({ 'name': ['josef','michael','john','bawool','klaus'], 'country': ['russia', 'germany', 'australia','korea','germany'] }) # use pd.concat to join the new columns with your original dataframe df = pd.concat([df,pd.get_dummies(df['country'], prefix='country')],axis=1) # now drop the original 'country' column (you don't need it anymore) df.drop(['country'],axis=1, inplace=True)

同時我們也可以把數據缺失也作為一種特征
import pandas as pd import numpy as np df = pd.DataFrame({ 'country': ['germany',np.nan,'germany','united kingdom','america','united kingdom'] }) pd.get_dummies(df,dummy_na=True)

3.whatone-hot encoding
接下來我們詳細的講一下onehot編碼和dummy之間的區別。
二者都可以對Categorical Variable做處理,轉換為定量特征,轉換為定量特征其實就是將原來每個特征的類別拿出來作為一個新的特征(Dummy Variable)了,
如性別——男,女,定量特征即將男作為一個特征,女作為一個特征,如果數據中的Categorical Variable很多,且每個Variable種類比較多,那么轉換后的數據可能會非常稀疏。
二者本身存在差別。
Difference:一個定性特征或者成為Categorical Variable,其有n個值,
Dummy Encoding 會將這個Categorical Variable轉換為n-1個特征變量,而OneHot Encoding會轉換為n個特征變量。
其中,這種轉換在經濟學或者回歸模型中會存在一個Dummy Variable Trap的問題,使用Dummy Encoder可以避免這個問題,由於我這里面對的是分類問題,沒有過多的調研。
如果你還不理解我借鑒一下某個博客的例子
one-hot的基本思想:將離散型特征的每一種取值都看成一種狀態,若你的這一特征中有N個不相同的取值,那么我們就可以將該特征抽象成N種不同的狀態,one-hot編碼保證了每一個取值只會使得一種狀態處於“激活態”,
也就是說這N種狀態中只有一個狀態位值為1,其他狀態位都是0。舉個例子,假設我們以學歷為例,我們想要研究的類別為小學、中學、大學、碩士、博士五種類別,我們使用one-hot對其編碼就會得到:
dummy encoding
啞變量編碼直觀的解釋就是任意的將一個狀態位去除。還是拿上面的例子來說,我們用4個狀態位就足夠反應上述5個類別的信息,也就是我們僅僅使用前四個狀態位 [0,0,0,0] 就可以表達博士了。只是因為對於一個我們研究的樣本,他已不是小學生、也不是中學生、也不是大學生、又不是研究生,那么我們就可以默認他是博士。所以,我們用啞變量編碼可以將上述5類表示成:

啞變量編碼去除了one-hot編碼內部線性相關的一個。這種簡化不能說到底好不好,這要看使用的場景。下面我們以一個例子來說明:
假設我們現在獲得了一個模型
,這里自變量滿足![]()
(因為特征是one-hot獲得的,所有只有一個狀態位為1,其他都為了0,所以它們加和總是等於1),
故我們可以用
表示第三個特征,將其帶入模型中,得到:

這時,我們就驚奇的發現
和
這兩個參數是等價的!那么我們模型的穩定性就成了一個待解決的問題。這個問題這么解決呢?有三種方法:
(1)使用
正則化手段,將參數的選擇上加一個限制,就是選擇參數元素值小的那個作為最終參數,這樣我們得到的參數就唯一了,模型也就穩定了。
(2)把偏置項
去掉,這時我們發現也可以解決同一個模型參數等價的問題。

因為有了bias項,所以和我們去掉bias項的模型是完全不同的模型,不存在參數等價的問題。
(3)再加上bias項的前提下,使用啞變量編碼代替one-hot編碼,這時去除了
,也就不存在之前一種特征可以用其他特征表示的問題了。
總結:我們使用one-hot編碼時,通常我們的模型不加bias項 或者 加上bias項然后使用
正則化手段去約束參數;當我們使用啞變量編碼時,通常我們的模型都會加bias項,因為不加bias項會導致固有屬性的丟失。
選擇建議:最好是選擇正則化 + one-hot編碼;啞變量編碼也可以使用,不過最好選擇前者。雖然啞變量可以去除one-hot編碼的冗余信息,但是因為每個離散型特征各個取值的地位都是對等的,隨意取舍未免來的太隨意。
連續值的離散化為什么會提升模型的非線性能力?
簡單的說,使用連續變量的LR模型,模型表示為公式(1),而使用了one-hot或啞變量編碼后的模型表示為公式(2)

式中
表示連續型特征,
、
、
分別是離散化后在使用one-hot或啞變量編碼后的若干個特征表示。這時我們發現使用連續值的LR模型用一個權值去管理該特征,而one-hot后有三個權值管理了這個特征,這樣使得參數管理的更加精細,所以這樣拓展了LR模型的非線性能力。
這樣做除了增強了模型的非線性能力外,還有什么好處呢?這樣做了我們至少不用再去對變量進行歸一化,也可以加速參數的更新速度;再者使得一個很大權值管理一個特征,拆分成了許多小的權值管理這個特征多個表示,這樣做降低了特征值擾動對模型為穩定性影響,也降低了異常數據對模型的影響,進而使得模型具有更好的魯棒性。

