sklearn中多种编码方式——category_encoders(one-hot多种用法)
文章目錄
- 1 Ordinal Encoding 序數編碼
- 2 One-hot Encoding 獨熱編碼
- 3 Target Encoding 目標編碼
- 4 BinaryEncoder 編碼
- 5 CatBoostEncoder編碼
- 6 WOEEncoder編碼
- 9 效果對比與使用心得
- 額外:10 用pandas的get_dummies進行one-hot
- 額外:11 文本one_hot的方式
離散型編碼的Python庫,里面封裝了十幾種(包括文中的所有方法)對于離散型特征的編碼方法,接口接近于Sklearn通用接口,非常實用
可以使用多種不同的編碼技術把類別變量轉換為數值型變量,并且符合sklearn模式的轉換。
- 官方github:https://github.com/scikit-learn-contrib/category_encoders
- 官方文檔:http://contrib.scikit-learn.org/category_encoders/#
這個庫的作者將類別編碼分為兩類,無監督和有監督(指用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無監督中有很大一部分是線性模型/回歸模型用的對比編碼,有監督主要是目標編碼和WOE(Weight of Evidence)
利用標簽進行特征編碼是存在特征穿越的風險的,只不過很多時候影響并不大,不會出現極端的情況,利用標簽進行特征編碼例如target encoding、woe encoding或者是catboost encoding本質上都是利用類別和標簽之間的某種統計特征來代替原始的類別,從而使得無法直接處理類別的模型可以在編碼后的結果上正常運行。
woe編碼的穿越問題
文章目錄
- 1 Ordinal Encoding 序數編碼
- 2 One-hot Encoding 獨熱編碼
- 3 Target Encoding 目標編碼
- 4 BinaryEncoder 編碼
- 5 CatBoostEncoder編碼
- 6 WOEEncoder編碼
- 9 效果對比與使用心得
- 額外:10 用pandas的get_dummies進行one-hot
- 額外:11 文本one_hot的方式
1 Ordinal Encoding 序數編碼
專欄 | 基于 Jupyter 的特征工程手冊:數據預處理(二)
feature-engineering-handbook/中文版/
這個編碼方式非常容易理解,就是把所有的相同類別的特征編碼成同一個值,例如女=0,男=1,狗狗=2,所以最后編碼的特征值是在[0, n-1]之間的整數。
這個編碼的缺點在于它隨機的給特征排序了,會給這個特征增加不存在的順序關系,也就是增加了噪聲。假設預測的目標是購買力,那么真實Label的排序顯然是 女 > 狗狗 > 男,與我們編碼后特征的順序不存在相關性。
import numpy as np import pandas as pd from category_encoders import OrdinalEncoder # category_encoders 直接支持dataframe# 隨機生成一些訓練集 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])# 隨機生成一些測試集, 并有意讓其包含未在訓練集出現過的類別與缺失值 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) # 在訓練集上訓練 # 將 handle_unknown設為‘value’,即測試集中的未知特征值將被標記為-1 # 將 handle_missing設為‘value’,即測試集中的缺失值將被標記為-2 # 其他的選擇為:‘error’:即報錯;‘return_nan’:即未知值/缺失之被標記為nan encoded_train = encoder.transform(train_set) # 轉換訓練集 encoded_test = encoder.transform(test_set) # 轉換測試集# 以測試集結果為例 encoded_test# 在序數編碼中:# 變量Sex中: 'male' => 1.0, 'female' => 2.0, 未知 => -1.0, 缺失值 => -2.0 # (事實上,測試集中完全有可能出現未知與缺失情況) # 在我們的例子中, Sex這一變量中的'other' 類別從未在訓練集中出現過# 變量 Type 中: 10 => 1.0, 20 => 2.0, 15 => 3.0, 未知 => -1.0, 缺失值 => -2.0
變成序列化:
2 One-hot Encoding 獨熱編碼
專欄 | 基于 Jupyter 的特征工程手冊:數據預處理(二)
feature-engineering-handbook/中文版/
大家熟知的OneHot方法就避免了對特征排序的缺點。對于一列有N種取值的特征,Onehot方法會創建出對應的N列特征,其中每列代表該樣本是否為該特征的某一種取值。因為生成的每一列有值的都是1,所以這個方法起名為Onehot特征。Dummy特征也是一樣,只是少了一列,因為第N列可以看做是前N-1列的線性組合。但是在離散特征的特征值過多的時候不宜使用,因為會導致生成特征的數量太多且過于稀疏。
Scikit-learn中也提供來獨熱編碼函數,其可以將具有n_categories個可能值的一個分類特征轉換為n_categories個二進制特征,其中一個為1,所有其他為0在category_encoders中,它包含了附加功能,即指示缺失或未知的值。在這里,我們繼續使用category_encoders
import numpy as np import pandas as pd from category_encoders import OneHotEncoder # category_encoders 直接支持dataframe# 隨機生成一些訓練集 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])# 隨機生成一些測試集, 并有意讓其包含未在訓練集出現過的類別與缺失值 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) # 在訓練集上訓練 encoded_train = encoder.transform(train_set) # 轉換訓練集 encoded_test = encoder.transform(test_set) # 轉換測試集 # 將 handle_unknown設為‘indicator’,即會新增一列指示未知特征值 # 將 handle_missing設為‘indicator’,即會新增一列指示缺失值 # 其他的handle_unknown/handle_missing 的選擇為: # ‘error’:即報錯; ‘return_nan’:即未知值/缺失之被標記為nan; ‘value’:即未知值/缺失之被標記為0# 以測試集結果為例 encoded_test# 在獨熱編碼中:# 變量 Sex => 變為了4個新變量: 'male' => [1 ,0 ,0, 0]; # 'female' => [0 ,1 ,0, 0]; # 未知 => [0 ,0 ,0, 1]; # 缺失 => [0, 0, 1, 0];# 變量 Type => 變為了5個新變量: 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 目標編碼
專欄 | 基于 Jupyter 的特征工程手冊:數據預處理(二)
feature-engineering-handbook/中文版/
目標編碼是一種不僅基于特征值本身,還基于相應因變量的類別變量編碼方法。對于分類問題:將類別特征替換為給定某一特定類別值的因變量后驗概率與所有訓練數據上因變量的先驗概率的組合。對于連續目標:將類別特征替換為給定某一特定類別值的因變量目標期望值與所有訓練數據上因變量的目標期望值的組合。該方法嚴重依賴于因變量的分布,但這大大減少了生成編碼后特征的數量。
公式:
其中min_samples_leaf和smoothing是用戶定義的參數;
min_samples_leaf:計算類別平均值時的最小樣本數(即若該類別出現次數少,則將被忽略),用以控制過擬合;
smoothing:平衡分類平均值與先驗平均值的平滑系數。其值越高,則正則化越強;
′ 是類別特征X中類別為k的編碼值;
Prior Prob:目標變量的先驗概率/期望;
n:類別特征X中,類別為k的樣本數;
+:不僅在類別特征X中具有類別k,而且具有正結果的樣本數(分類問題);
參考文獻: 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# 隨機生成一些訓練集 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])# 隨機生成一些測試集, 并有意讓其包含未在訓練集出現過的類別與缺失值 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) # 在訓練集上訓練 encoded_train = encoder.transform(train_set) # 轉換訓練集 encoded_test = encoder.transform(test_set) # 轉換測試集# handle_unknown 和 handle_missing 被設定為 'value' # 在目標編碼中,handle_unknown 和 handle_missing 僅接受 ‘error’, ‘return_nan’ 及 ‘value’ 設定 # 兩者的默認值均為 ‘value’, 即對未知類別或缺失值填充訓練集的因變量平均值encoded_test # 編碼后的變量數與原類別變量數一致
到了:
0.4731058578630005
4 BinaryEncoder 編碼
# 相關模塊加載 import pandas as pd import category_encoders as ce# 準備數據 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)# 轉換數據 numeric_dataset = encoder.transform(df)df # 轉換前的數據
到:
5 CatBoostEncoder編碼
這個跟CatBoost一致,是Catboost中的encode方法,這個方法據說效果非常好,而且可以避免過擬合,可能有些復雜
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本來:
現在:
其他案例(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編碼
【數據建模 WOE編碼】WOE(weight of evidence, 證據權重)
一種有監督的編碼方式,將預測類別的集中度的屬性作為編碼的數值
- 優勢
將特征的值規范到相近的尺度上。
(經驗上講,WOE的絕對值波動范圍在0.1~3之間)。
具有業務含義。 - 缺點
需要每箱中同時包含好、壞兩個類別。
當然也會出現標簽穿越的問題: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種離散型變量編碼方式及效果對比
語雀文檔
數據集使用了八個存在離散型變量的數據集,最后的結果加權如下:
不使用交叉驗證的情況:
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上大佬們給出的一些建議,具體原因尚未分析,希望有大神在評論區可以給出解釋。
對于無序的離散特征,實戰中使用 OneHot, Hashing, LeaveOneOut, and Target encoding 方法效果較好,但是使用OneHot時要避免高基類別的特征以及基于決策樹的模型,理由如下圖所示。
但是在實戰中,我發現使用Xgboost處理高維稀疏的問題效果并不會很差。例如在IJCAI-18商鋪中用戶定位比賽中,一個很好的baseline就是把高維稀疏的wifi信號向量直接當做特征放到Xgboost里面,也可以獲得很好的預測結果。不知道是不是因為Xgboost對于稀疏特征的優化導致。
- 對于有序離散特征,嘗試 Ordinal (Integer), Binary, OneHot, LeaveOneOut, and Target. Helmert, Sum, BackwardDifference and Polynomial 基本沒啥用,但是當你有確切的原因或者對于業務的理解的話,可以進行嘗試。
- 對于回歸問題而言,Target 與 LeaveOneOut 方法可能不會有比較好的效果。
LeaveOneOut、 WeightOfEvidence、 James-Stein、M-estimator 適合用來處理高基數特征。Helmert、 Sum、 Backward Difference、 Polynomial 在機器學習問題里的效果往往不是很好(過擬合的原因)
額外:10 用pandas的get_dummies進行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 后:
上述執行完以后再打印df 出來的還是get_dummies 前的圖,因為你沒有寫
df = pd.get_dummies(df)
可以對指定列進行get_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常規分詞,以空格隔開.[['格式','不一定'],['空格','隔開','常規']]prefix : TYPE, optional前綴. The default is ''.Returns-------data : TYPEdataframe,完整的TF的頻次.'''vectorizer = CountVectorizer() #將文本中的詞語轉換為詞頻矩陣 X = vectorizer.fit_transform(tag_list) #計算個詞語出現的次數data = pd.DataFrame(X.toarray(),columns = [prefix +'_'+ si for si in sorted(vectorizer.vocabulary_)])return datatag_list = ['青年 吃貨', '少年 游戲 叛逆', '少年 吃貨 足球'] data = text_one_hot(tag_list)返回的結果是:
_叛逆 _吃貨 _少年 _游戲 _足球 _青年 0 0 1 0 0 0 1 1 1 0 1 1 0 0 2 0 1 1 0 1 0總結
以上是生活随笔為你收集整理的sklearn中多种编码方式——category_encoders(one-hot多种用法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux基础:su命令使用方法介绍
- 下一篇: php原生检测用户,php代码在线测试_