sklearn中多种编码方式——category_encoders(one-hot多种用法)
文章目錄
- 1 Ordinal Encoding 序數(shù)編碼
- 2 One-hot Encoding 獨熱編碼
- 3 Target Encoding 目標(biāo)編碼
- 4 BinaryEncoder 編碼
- 5 CatBoostEncoder編碼
- 6 WOEEncoder編碼
- 9 效果對比與使用心得
- 額外:10 用pandas的get_dummies進(jìn)行one-hot
- 額外:11 文本one_hot的方式
離散型編碼的Python庫,里面封裝了十幾種(包括文中的所有方法)對于離散型特征的編碼方法,接口接近于Sklearn通用接口,非常實用
可以使用多種不同的編碼技術(shù)把類別變量轉(zhuǎn)換為數(shù)值型變量,并且符合sklearn模式的轉(zhuǎn)換。
- 官方github:https://github.com/scikit-learn-contrib/category_encoders
- 官方文檔:http://contrib.scikit-learn.org/category_encoders/#
這個庫的作者將類別編碼分為兩類,無監(jiān)督和有監(jiān)督(指用target)
Unsupervised:
Backward Difference Contrast BaseN Binary Count Hashing Helmert Contrast Ordinal One-Hot Polynomial Contrast Sum ContrastSupervised:
CatBoost James-Stein Estimator LeaveOneOut M-estimator Target Encoding Weight of Evidence無監(jiān)督中有很大一部分是線性模型/回歸模型用的對比編碼,有監(jiān)督主要是目標(biāo)編碼和WOE(Weight of Evidence)
利用標(biāo)簽進(jìn)行特征編碼是存在特征穿越的風(fēng)險的,只不過很多時候影響并不大,不會出現(xiàn)極端的情況,利用標(biāo)簽進(jìn)行特征編碼例如target encoding、woe encoding或者是catboost encoding本質(zhì)上都是利用類別和標(biāo)簽之間的某種統(tǒng)計特征來代替原始的類別,從而使得無法直接處理類別的模型可以在編碼后的結(jié)果上正常運行。
woe編碼的穿越問題
文章目錄
- 1 Ordinal Encoding 序數(shù)編碼
- 2 One-hot Encoding 獨熱編碼
- 3 Target Encoding 目標(biāo)編碼
- 4 BinaryEncoder 編碼
- 5 CatBoostEncoder編碼
- 6 WOEEncoder編碼
- 9 效果對比與使用心得
- 額外:10 用pandas的get_dummies進(jìn)行one-hot
- 額外:11 文本one_hot的方式
1 Ordinal Encoding 序數(shù)編碼
專欄 | 基于 Jupyter 的特征工程手冊:數(shù)據(jù)預(yù)處理(二)
feature-engineering-handbook/中文版/
這個編碼方式非常容易理解,就是把所有的相同類別的特征編碼成同一個值,例如女=0,男=1,狗狗=2,所以最后編碼的特征值是在[0, n-1]之間的整數(shù)。
這個編碼的缺點在于它隨機(jī)的給特征排序了,會給這個特征增加不存在的順序關(guān)系,也就是增加了噪聲。假設(shè)預(yù)測的目標(biāo)是購買力,那么真實Label的排序顯然是 女 > 狗狗 > 男,與我們編碼后特征的順序不存在相關(guān)性。
import numpy as np import pandas as pd from category_encoders import OrdinalEncoder # category_encoders 直接支持dataframe# 隨機(jī)生成一些訓(xùn)練集 train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type']) train_y = np.array([False, True, True, False, False])# 隨機(jī)生成一些測試集, 并有意讓其包含未在訓(xùn)練集出現(xiàn)過的類別與缺失值 test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type']) test_set.loc[4,'Type'] = np.nanencoder = OrdinalEncoder(cols = ['Sex', 'Type'], handle_unknown = 'value', handle_missing = 'value').fit(train_set,train_y) # 在訓(xùn)練集上訓(xùn)練 # 將 handle_unknown設(shè)為‘value’,即測試集中的未知特征值將被標(biāo)記為-1 # 將 handle_missing設(shè)為‘value’,即測試集中的缺失值將被標(biāo)記為-2 # 其他的選擇為:‘error’:即報錯;‘return_nan’:即未知值/缺失之被標(biāo)記為nan encoded_train = encoder.transform(train_set) # 轉(zhuǎn)換訓(xùn)練集 encoded_test = encoder.transform(test_set) # 轉(zhuǎn)換測試集# 以測試集結(jié)果為例 encoded_test# 在序數(shù)編碼中:# 變量Sex中: 'male' => 1.0, 'female' => 2.0, 未知 => -1.0, 缺失值 => -2.0 # (事實上,測試集中完全有可能出現(xiàn)未知與缺失情況) # 在我們的例子中, Sex這一變量中的'other' 類別從未在訓(xùn)練集中出現(xiàn)過# 變量 Type 中: 10 => 1.0, 20 => 2.0, 15 => 3.0, 未知 => -1.0, 缺失值 => -2.0
變成序列化:
2 One-hot Encoding 獨熱編碼
專欄 | 基于 Jupyter 的特征工程手冊:數(shù)據(jù)預(yù)處理(二)
feature-engineering-handbook/中文版/
大家熟知的OneHot方法就避免了對特征排序的缺點。對于一列有N種取值的特征,Onehot方法會創(chuàng)建出對應(yīng)的N列特征,其中每列代表該樣本是否為該特征的某一種取值。因為生成的每一列有值的都是1,所以這個方法起名為Onehot特征。Dummy特征也是一樣,只是少了一列,因為第N列可以看做是前N-1列的線性組合。但是在離散特征的特征值過多的時候不宜使用,因為會導(dǎo)致生成特征的數(shù)量太多且過于稀疏。
Scikit-learn中也提供來獨熱編碼函數(shù),其可以將具有n_categories個可能值的一個分類特征轉(zhuǎn)換為n_categories個二進(jìn)制特征,其中一個為1,所有其他為0在category_encoders中,它包含了附加功能,即指示缺失或未知的值。在這里,我們繼續(xù)使用category_encoders
import numpy as np import pandas as pd from category_encoders import OneHotEncoder # category_encoders 直接支持dataframe# 隨機(jī)生成一些訓(xùn)練集 train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type']) train_y = np.array([False, True, True, False, False])# 隨機(jī)生成一些測試集, 并有意讓其包含未在訓(xùn)練集出現(xiàn)過的類別與缺失值 test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type']) test_set.loc[4,'Type'] = np.nanencoder = OneHotEncoder(cols=['Sex', 'Type'], handle_unknown='indicator', handle_missing='indicator', use_cat_names=True).fit(train_set,train_y) # 在訓(xùn)練集上訓(xùn)練 encoded_train = encoder.transform(train_set) # 轉(zhuǎn)換訓(xùn)練集 encoded_test = encoder.transform(test_set) # 轉(zhuǎn)換測試集 # 將 handle_unknown設(shè)為‘indicator’,即會新增一列指示未知特征值 # 將 handle_missing設(shè)為‘indicator’,即會新增一列指示缺失值 # 其他的handle_unknown/handle_missing 的選擇為: # ‘error’:即報錯; ‘return_nan’:即未知值/缺失之被標(biāo)記為nan; ‘value’:即未知值/缺失之被標(biāo)記為0# 以測試集結(jié)果為例 encoded_test# 在獨熱編碼中:# 變量 Sex => 變?yōu)榱?個新變量: 'male' => [1 ,0 ,0, 0]; # 'female' => [0 ,1 ,0, 0]; # 未知 => [0 ,0 ,0, 1]; # 缺失 => [0, 0, 1, 0];# 變量 Type => 變?yōu)榱?個新變量: 10 => [1, 0, 0, 0, 0]; # 20 => [0, 1, 0, 0, 0];, # 15 => [0, 0, 1, 0, 0]; # 未知 => [0, 0, 0, 0, 1]; # 缺失 => [0, 0, 0, 1, 0];
變成了:
3 Target Encoding 目標(biāo)編碼
專欄 | 基于 Jupyter 的特征工程手冊:數(shù)據(jù)預(yù)處理(二)
feature-engineering-handbook/中文版/
目標(biāo)編碼是一種不僅基于特征值本身,還基于相應(yīng)因變量的類別變量編碼方法。對于分類問題:將類別特征替換為給定某一特定類別值的因變量后驗概率與所有訓(xùn)練數(shù)據(jù)上因變量的先驗概率的組合。對于連續(xù)目標(biāo):將類別特征替換為給定某一特定類別值的因變量目標(biāo)期望值與所有訓(xùn)練數(shù)據(jù)上因變量的目標(biāo)期望值的組合。該方法嚴(yán)重依賴于因變量的分布,但這大大減少了生成編碼后特征的數(shù)量。
公式:
其中min_samples_leaf和smoothing是用戶定義的參數(shù);
min_samples_leaf:計算類別平均值時的最小樣本數(shù)(即若該類別出現(xiàn)次數(shù)少,則將被忽略),用以控制過擬合;
smoothing:平衡分類平均值與先驗平均值的平滑系數(shù)。其值越高,則正則化越強;
′ 是類別特征X中類別為k的編碼值;
Prior Prob:目標(biāo)變量的先驗概率/期望;
n:類別特征X中,類別為k的樣本數(shù);
+:不僅在類別特征X中具有類別k,而且具有正結(jié)果的樣本數(shù)(分類問題);
參考文獻(xiàn): Micci-Barreca, D. (2001). A preprocessing scheme for high-cardinality categorical attributes in classification and prediction problems. ACM SIGKDD Explorations Newsletter, 3(1), 27-32.
import numpy as np import pandas as pd from category_encoders.target_encoder import TargetEncoder # category_encoders 直接支持dataframe# 隨機(jī)生成一些訓(xùn)練集 train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], ['female',20],['female',15]]),columns = ['Sex','Type']) train_y = np.array([False, True, True, False, False])# 隨機(jī)生成一些測試集, 并有意讓其包含未在訓(xùn)練集出現(xiàn)過的類別與缺失值 test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], ['male',20],['female',40], ['male', 25]]),columns = ['Sex','Type']) test_set.loc[4,'Type'] = np.nanencoder = TargetEncoder(cols=['Sex','Type'], handle_unknown='value', handle_missing='value').fit(train_set,train_y) # 在訓(xùn)練集上訓(xùn)練 encoded_train = encoder.transform(train_set) # 轉(zhuǎn)換訓(xùn)練集 encoded_test = encoder.transform(test_set) # 轉(zhuǎn)換測試集# handle_unknown 和 handle_missing 被設(shè)定為 'value' # 在目標(biāo)編碼中,handle_unknown 和 handle_missing 僅接受 ‘error’, ‘return_nan’ 及 ‘value’ 設(shè)定 # 兩者的默認(rèn)值均為 ‘value’, 即對未知類別或缺失值填充訓(xùn)練集的因變量平均值encoded_test # 編碼后的變量數(shù)與原類別變量數(shù)一致
到了:
0.4731058578630005
4 BinaryEncoder 編碼
# 相關(guān)模塊加載 import pandas as pd import category_encoders as ce# 準(zhǔn)備數(shù)據(jù) df = pd.DataFrame({'ID':[1,2,3,4,5,6],'RATING':['G','B','G','B','B','G']})# 使用binary編碼的方式來編碼類別變量 encoder = ce.BinaryEncoder(cols=['RATING']).fit(df)# 轉(zhuǎn)換數(shù)據(jù) numeric_dataset = encoder.transform(df)df # 轉(zhuǎn)換前的數(shù)據(jù)
到:
5 CatBoostEncoder編碼
這個跟CatBoost一致,是Catboost中的encode方法,這個方法據(jù)說效果非常好,而且可以避免過擬合,可能有些復(fù)雜
import pandas as pd import numpy as np #from unittest import TestCase # or `from unittest import ...` if on Python 3.4+import category_encoders as encodersX = pd.DataFrame({'col1': ['A', 'B', 'B', 'C', 'A']}) y = pd.Series([1, 0, 1, 0, 1]) enc = encoders.CatBoostEncoder() obtained = enc.fit_transform(X, y) obtained# For testing set, use statistics calculated on all the training data. # See: CatBoost: unbiased boosting with categorical features, page 4. X_t = pd.DataFrame({'col1': ['B', 'B', 'A']}) obtained = enc.transform(X_t) obtained本來:
現(xiàn)在:
其他案例(github):
X = pd.DataFrame({'col1': ['fuzzy', 'soft', 'smooth', 'fuzzy', 'smooth', 'soft', 'smooth', 'smooth']}) y = pd.Series([4, 1, 4, 3, 6, 0, 7, 5]) enc = encoders.CatBoostEncoder() obtained = enc.fit_transform(X, y) prior = 30./86 WOEEncoder編碼
【數(shù)據(jù)建模 WOE編碼】WOE(weight of evidence, 證據(jù)權(quán)重)
一種有監(jiān)督的編碼方式,將預(yù)測類別的集中度的屬性作為編碼的數(shù)值
- 優(yōu)勢
將特征的值規(guī)范到相近的尺度上。
(經(jīng)驗上講,WOE的絕對值波動范圍在0.1~3之間)。
具有業(yè)務(wù)含義。 - 缺點
需要每箱中同時包含好、壞兩個類別。
當(dāng)然也會出現(xiàn)標(biāo)簽穿越的問題:woe編碼的穿越問題
X = ['a', 'a', 'b', 'b'] y = [1, 0, 0, 0] enc = encoders.WOEEncoder()result = enc.fit_transform(X, y) 從: (['a', 'a', 'b', 'b'], [1, 0, 0, 0])變成:0 0 0.510826 1 0.510826 2 -0.587787 3 -0.587787案例二:
cols = ['unique_str', 'underscore', 'extra', 'none', 'invariant', 321, 'categorical', 'na_categorical', 'categorical_int']# balanced label with balanced features X_balanced = pd.DataFrame(data=['1', '1', '1', '2', '2', '2'], columns=['col1']) y_balanced = [True, False, True, False, True, False] enc = encoders.WOEEncoder() enc.fit(X_balanced, y_balanced) X1 = enc.transform(X_balanced)9 效果對比與使用心得
11種離散型變量編碼方式及效果對比
語雀文檔
數(shù)據(jù)集使用了八個存在離散型變量的數(shù)據(jù)集,最后的結(jié)果加權(quán)如下:
不使用交叉驗證的情況:
HelmertEncoder 0.9517 SumEncoder 0.9434 FrequencyEncoder 0.9176 CatBoostEncoder 0.5728 TargetEncoder 0.5174 JamesSteinEncoder 0.5162 OrdinalEncoder 0.4964 WOEEncoder 0.4905 MEstimateEncoder 0.4501 BackwardDifferenceEncode0.4128 LeaveOneOutEncoder 0.0697使用交叉驗證的情況:
CatBoostEncoder 0.9726 OrdinalEncoder 0.9694 HelmertEncoder 0.9558 SumEncoder 0.9434 WOEEncoder 0.9326 FrequencyEncoder 0.9315 BackwardDifferenceEncode0.9108 TargetEncoder 0.8915 JamesSteinEncoder 0.8555 MEstimateEncoder 0.8189 LeaveOneOutEncoder 0.0729下面是Kaggle上大佬們給出的一些建議,具體原因尚未分析,希望有大神在評論區(qū)可以給出解釋。
對于無序的離散特征,實戰(zhàn)中使用 OneHot, Hashing, LeaveOneOut, and Target encoding 方法效果較好,但是使用OneHot時要避免高基類別的特征以及基于決策樹的模型,理由如下圖所示。
但是在實戰(zhàn)中,我發(fā)現(xiàn)使用Xgboost處理高維稀疏的問題效果并不會很差。例如在IJCAI-18商鋪中用戶定位比賽中,一個很好的baseline就是把高維稀疏的wifi信號向量直接當(dāng)做特征放到Xgboost里面,也可以獲得很好的預(yù)測結(jié)果。不知道是不是因為Xgboost對于稀疏特征的優(yōu)化導(dǎo)致。
- 對于有序離散特征,嘗試 Ordinal (Integer), Binary, OneHot, LeaveOneOut, and Target. Helmert, Sum, BackwardDifference and Polynomial 基本沒啥用,但是當(dāng)你有確切的原因或者對于業(yè)務(wù)的理解的話,可以進(jìn)行嘗試。
- 對于回歸問題而言,Target 與 LeaveOneOut 方法可能不會有比較好的效果。
LeaveOneOut、 WeightOfEvidence、 James-Stein、M-estimator 適合用來處理高基數(shù)特征。Helmert、 Sum、 Backward Difference、 Polynomial 在機(jī)器學(xué)習(xí)問題里的效果往往不是很好(過擬合的原因)
額外:10 用pandas的get_dummies進(jìn)行one-hot
參考:pandas.get_dummies 的用法
pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False)
get_dummies 前:
get_dummies 后:
上述執(zhí)行完以后再打印df 出來的還是get_dummies 前的圖,因為你沒有寫
df = pd.get_dummies(df)
可以對指定列進(jìn)行g(shù)et_dummies
pd.get_dummies(df.color)
額外:11 文本one_hot的方式
from sklearn.feature_extraction.text import CountVectorizer #from sklearn.feature_extraction.text import TfidfTransformer import pandas as pddef text_one_hot(tag_list,prefix = ''):'''Parameters----------tag_list : TYPE常規(guī)分詞,以空格隔開.[['格式','不一定'],['空格','隔開','常規(guī)']]prefix : TYPE, optional前綴. The default is ''.Returns-------data : TYPEdataframe,完整的TF的頻次.'''vectorizer = CountVectorizer() #將文本中的詞語轉(zhuǎn)換為詞頻矩陣 X = vectorizer.fit_transform(tag_list) #計算個詞語出現(xiàn)的次數(shù)data = pd.DataFrame(X.toarray(),columns = [prefix +'_'+ si for si in sorted(vectorizer.vocabulary_)])return datatag_list = ['青年 吃貨', '少年 游戲 叛逆', '少年 吃貨 足球'] data = text_one_hot(tag_list)返回的結(jié)果是:
_叛逆 _吃貨 _少年 _游戲 _足球 _青年 0 0 1 0 0 0 1 1 1 0 1 1 0 0 2 0 1 1 0 1 0總結(jié)
以上是生活随笔為你收集整理的sklearn中多种编码方式——category_encoders(one-hot多种用法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux基础:su命令使用方法介绍
- 下一篇: 1901~2100年节气表