機器學習模型處理不了原始文本。無論是線性迴歸、XGBoost還是神經網絡,遇到

"red"

"medium"

"CA"

這類分類變量都沒法直接處理。所以必須把它們轉成數字這個過程就是分類編碼。

別隻會One-Hot了!20種分類編碼技巧讓你的特徵工程更專業_#python

大家入門時肯定都學過獨熱編碼或序數編碼,但編碼方法其實非常多。目標編碼、CatBoost編碼、James-Stein編碼這些高級技術,用對了能給模型帶來質的飛躍,尤其面對高基數特徵的時候。

編碼到底有多重要

"Toyota"

舉例,它本身沒有數值含義,但模型只認數字:

{"Toyota": 0, "Ford": 1, "Honda": 2}

或者寫成向量形式:

[0, 1, 0]

更高級的做法是直接編碼成目標相關的數值:

Toyota → +0.12 mean adjusted uplift in target

編碼方式選得好不好,直接影響模型準確率、可解釋性、過擬合程度、訓練速度、內存佔用,還有對稀有類別的處理能力。

示例代碼準備

後面所有例子都基於這個簡單數據集:

import pandas as pd  
from sklearn.model_selection import train_test_split  
import category_encoders as ce  
from sklearn.linear_model import LogisticRegression  

df = pd.DataFrame({  
    "color": ["red", "blue", "green", "green", "blue", "red"],  
    "city": ["NY", "LA", "NY", "SF", "LA", "NY"],  
    "target": [1, 0, 1, 0, 0, 1]  
})  
X = df.drop("target", axis=1)  
 y = df["target"]

1、序數編碼 Ordinal Encoding

最簡單粗暴的方法,給每個類別分配一個整數。red是0,blue是1,green是2。

XGBoost、LightGBM這類樹模型用這個就夠了。另外當類別本身有順序含義(比如small/medium/large)時也很合適。

encoder=ce.OrdinalEncoder(cols=["color"])  
 X_trans=encoder.fit_transform(X, y)

2、獨熱編碼 One-Hot Encoding

每個類別單獨開一列,是就標1,不是就標0。

別隻會One-Hot了!20種分類編碼技巧讓你的特徵工程更專業_#人工智能_02


線性迴歸、邏輯迴歸、神經網絡經常用這個。不過類別太多的話列數會爆炸,低基數特徵才適合。

encoder=ce.OneHotEncoder(cols=["color"], use_cat_names=True)  
 X_trans=encoder.fit_transform(X)

3、 二進制編碼 Binary Encoding

把類別索引轉成二進制。比如索引5變成101,拆成三列。

這個方法在類別數量中等偏多(50-500個)的時候很好使,既保持了稀疏性又比獨熱編碼省內存。

encoder=ce.BinaryEncoder(cols=["city"])  
 X_trans=encoder.fit_transform(X)

4、Base-N編碼

二進制編碼的泛化版本,可以用任意進制。base=3時,索引5就變成

"12"

。想精細控制輸出維度的話可以試試。

encoder=ce.BaseNEncoder(cols=["city"], base=3)  
 X_trans=encoder.fit_transform(X)

5、哈希編碼 Hashing Encoding

用哈希函數把類別映射到固定數量的列上。速度極快,輸出寬度固定,也不用存儲類別映射表。

缺點就是:會有哈希衝突而且結果不可解釋。

encoder=ce.HashingEncoder(cols=["city"], n_components=8)  
 X_trans=encoder.fit_transform(X)

6、Helmert編碼

正交對比編碼的一種,每個類別跟它後面所有類別的均值做比較。統計建模和分類對比迴歸分析會用到。

encoder=ce.HelmertEncoder(cols=["color"])  
 X_trans=encoder.fit_transform(X, y)

7、求和編碼 Sum Encoding

也叫偏差編碼。每個類別跟總體均值比較,而不是跟某個基準類別比。

encoder=ce.SumEncoder(cols=["color"])  
 X_trans=encoder.fit_transform(X, y)

8、多項式編碼 Polynomial Encoding

給有序類別生成線性、二次、三次對比項。如果懷疑類別對目標有非線性影響,可以考慮這個。

encoder=ce.PolynomialEncoder(cols=["color"])  
 X_trans=encoder.fit_transform(X, y)

9、向後差分編碼 Backward Difference Encoding

每個類別跟前面所有類別的均值比較,跟Helmert正好相反。

encoder=ce.BackwardDifferenceEncoder(cols=["color"])  
 X_trans=encoder.fit_transform(X, y)

10、計數編碼 Count Encoding

直接用類別出現的次數替換類別值。

別隻會One-Hot了!20種分類編碼技巧讓你的特徵工程更專業_#數據挖掘_03


高基數特徵用這個效果不錯,計算快、結果穩定。只要在訓練集上fit就不會有數據泄露問題。

encoder=ce.CountEncoder(cols=["city"])  
 X_trans=encoder.fit_transform(X)

11. 目標編碼 Target Encoding

把每個類別替換成該類別下目標變量的均值。


威力很大但有個坑,就是容易造成目標泄露。必須配合平滑處理或者用交叉驗證的方式來做。

encoder = ce.TargetEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

12、CatBoost編碼

CatBoost編碼是目標編碼的改良版。編碼每一行時只用它前面的行來計算,這樣就大大降低了泄露風險。

這是目前最安全的目標編碼方案,高基數特徵、時序數據都能用,效果很穩。

encoder = ce.CatBoostEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

13、留一法編碼 Leave-One-Out Encoding

計算類別的目標均值時把當前行排除掉。既保留了目標編碼的效果,又減輕了泄露。

encoder = ce.LeaveOneOutEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

14、M估計編碼 M-Estimate Encoding

用貝葉斯思想對目標編碼做平滑。

別隻會One-Hot了!20種分類編碼技巧讓你的特徵工程更專業_#python_04


高基數和噪聲目標場景下表現不錯。

encoder = ce.MEstimateEncoder(cols=["city"], m=5)  
X_trans = encoder.fit_transform(X, y)

15、WOE證據權重編碼

這是信用評分領域的老朋友了。

別隻會One-Hot了!20種分類編碼技巧讓你的特徵工程更專業_#分類_05


邏輯迴歸配WOE是經典組合,可解釋性很強。

encoder = ce.WOEEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

16、James-Stein編碼

基於James-Stein估計的收縮編碼器。能有效降低方差,做分類變量回歸時效果很好。

encoder = ce.JamesSteinEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

17、GLMM編碼

用廣義線性混合模型來編碼。處理層次結構數據或者類別組很大的時候可以一試。

encoder = ce.GLMMEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X, y)

18、分位數編碼 Quantile Encoding

不用均值,用目標分佈的分位數來編碼。

encoder = ce.QuantileEncoder(cols=["city"], quantile=0.5)  
X_trans = encoder.fit_transform(X, y)

19、RankHot編碼

獨熱編碼的變體,列按類別頻率排序。對樹模型友好。

encoder = ce.RankHotEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X)

20、格雷編碼 Gray Encoding

用格雷碼錶示類別,相鄰編碼只差一位。

encoder = ce.GrayEncoder(cols=["city"])  
X_trans = encoder.fit_transform(X)

怎麼選編碼器

低基數(<10個類別):獨熱、二進制、序數都行。統計模型的話可以試試求和、Helmert、多項式編碼。

中等基數(10-100):二進制、BaseN、CatBoost、帶平滑的目標編碼。

高基數(100-50000):計數編碼、CatBoost編碼(首選)、留一法、M估計、帶交叉驗證的目標編碼,內存緊張就用哈希編碼。

常見的坑

目標編碼泄露:用CatBoost編碼、交叉驗證或留一法來規避。

樹模型誤讀序數整數:樹模型可能會把序數編碼的數字當連續變量處理,換成獨熱或目標編碼更穩妥。

獨熱編碼維度爆炸:類別太多就別用獨熱了,換二進制、BaseN或哈希。

稀有類別噪聲:M估計、James-Stein或目標平滑能緩解這個問題。

總結

分類編碼是特徵工程裏最容易被忽視卻又最能出效果的環節。scikit-learn自帶的編碼器只是冰山一角,

category_encoders

這個庫才是真正的百寶箱:統計編碼、貝葉斯編碼、哈希編碼、對比編碼應有盡有,用好了模型效果能上一個台階。

作者:Abish Pius