【机器学习基础】机器学习中类别变量的编码方法总结
?機器學習
Author:louwill
Machine Learning Lab
? ? ?在做結構化數(shù)據(jù)訓練時,類別特征是一個非常常見的變量類型。機器學習中有多種類別變量編碼方式,各種編碼方法都有各自的適用場景和特點。本文就對機器學習中常見的類別編碼方式做一個簡單的總結。
硬編碼:Label Encoding
? ? ?所謂硬編碼,即直接對類別特征進行數(shù)值映射,有多少類別取值就映射多少數(shù)值。這種硬編碼方式簡單粗暴,方便快捷。但其僅在類別特征內(nèi)部取值是有序的情況才好使用,即類別特征取值存在明顯的順序性,比如說學歷特征取值為高中、本科、碩士和博士,各學歷之間存在明顯的順序關系。
? ? ?Sklearn提供了Label Encoding的實現(xiàn)方式,示例代碼如下:
from sklearn import preprocessing le = preprocessing.LabelEncoder() le.fit(['undergraduate', 'master', 'PhD', 'Postdoc']) le.transform(['undergraduate', 'master', 'PhD', 'Postdoc']) array([3, 2, 0, 1], dtype=int64)獨熱編碼:One-hot Encoding
? ? ?One-hot編碼應該是應用最廣泛的類別特征編碼方式了。假設一個類別特征有m個類別取值,通過One-hot編碼我們可以將其轉換為m個二元特征,每個特征對應該取值類別。
? ? ?對于類別特征內(nèi)部取值不存在明顯的內(nèi)在順序時,即直接的硬編碼不適用時,One-hot編碼的作用就凸顯出來了。但當類別特征取值過多時,One-hot編碼很容易造成維度災難,特別是對于文本類的特征,如果使用One-hot編碼對其進行編碼,基本上都是茫茫零海。所以,在類別特征取值無序,且特征取值數(shù)量少于5個時,可使用One-hot方法進行類別編碼。有朋友可能會問,一定得是5個嗎,6個行不行,當然也可以,這里并沒有固定標準,但差不多就是這個數(shù)據(jù)左右。數(shù)量再多就不建議使用One-hot了。
? ? ?Pandas和Sklearn都提供了One-hot編碼的實現(xiàn)方式,示例代碼如下。
import pandas as pd df = pd.DataFrame({'f1':['A','B','C'], 'f2':['Male','Female','Male']}) df = pd.get_dummies(df, columns=['f1', 'f2']) df from sklearn.preprocessing import OneHotEncoder enc = OneHotEncoder(handle_unknown='ignore') X = [['Male', 1], ['Female', 3], ['Female', 2]] enc.fit(X) enc.transform([['Female', 1], ['Male', 4]]).toarray() array([[1., 0., 1., 0., 0.], [0., 1., 0., 0., 0.]])目標變量編碼:Target Encoding
? ? ?Target Encoding就是用目標變量的類別均值來給類別特征做編碼。CatBoost中就大量使用目標變量統(tǒng)計的方法來對類別特征編碼。但在實際操作時,直接用類別均值替換類別特征的話,會造成一定程度的標簽信息泄露的情況,主流方法是使用兩層的交叉驗證來計算目標均值。Target Encoding一般適用于類別特征無序且類別取值數(shù)量大于5個的情形。
? ? ?參考代碼如下:
### 該代碼來自知乎專欄: ### https://zhuanlan.zhihu.com/p/40231966 from sklearn.model_selection import KFold n_folds = 20 n_inner_folds = 10 likelihood_encoded = pd.Series() likelihood_coding_map = {} # global prior mean oof_default_mean = train[target].mean() kf = KFold(n_splits=n_folds, shuffle=True) oof_mean_cv = pd.DataFrame() split = 0 for infold, oof in kf.split(train[feature]): print ('==============level 1 encoding..., fold %s ============' % split) inner_kf = KFold(n_splits=n_inner_folds, shuffle=True) inner_oof_default_mean = train.iloc[infold][target].mean() inner_split = 0 inner_oof_mean_cv = pd.DataFrame() likelihood_encoded_cv = pd.Series() for inner_infold, inner_oof in inner_kf.split(train.iloc[infold]): print ('==============level 2 encoding..., inner fold %s ============' % inner_split)# inner out of fold mean oof_mean = train.iloc[inner_infold].groupby(by=feature)[target].mean()# assign oof_mean to the infold likelihood_encoded_cv = likelihood_encoded_cv.append(train.iloc[infold].apply( lambda x : oof_mean[x[feature]] if x[feature] in oof_mean.index else inner_oof_default_mean, axis = 1)) inner_oof_mean_cv = inner_oof_mean_cv.join(pd.DataFrame(oof_mean), rsuffix=inner_split, how='outer') inner_oof_mean_cv.fillna(inner_oof_default_mean, inplace=True) inner_split += 1 oof_mean_cv = oof_mean_cv.join(pd.DataFrame(inner_oof_mean_cv), rsuffix=split, how='outer') oof_mean_cv.fillna(value=oof_default_mean, inplace=True) split += 1 print ('============final mapping...===========') likelihood_encoded = likelihood_encoded.append(train.iloc[oof].apply( lambda x: np.mean(inner_oof_mean_cv.loc[x[feature]].values) if x[feature] in inner_oof_mean_cv.index else?oof_default_mean,?axis=1))模型自動編碼
? ? ?在LightGBM和CatBoost等算法中,模型可以直接對類別特征進行編碼,實際使用時直接將類別特征標記后傳入對應的api即可。一個示例代碼如下:
lgb_train = lgb.Dataset(train2[features], train2['total_cost'], categorical_feature=['sex'])總結
根據(jù)本文的梳理,可總結機器學習中類別特征的編碼方式如下:
Label Encoding
類別特征內(nèi)部有序
One-hot Encoding
類別特征內(nèi)部無序
類別數(shù)值<5
Target Encoding
類別特征內(nèi)部無序
類別數(shù)值>5
模型自動編碼
LightGBM
CatBoost
總結
以上是生活随笔為你收集整理的【机器学习基础】机器学习中类别变量的编码方法总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python基础】Python画王者荣
- 下一篇: 我所认识的数据产品经理(文末有彩蛋)