溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python機器學(xué)習(xí)類別特征的處理方法有哪些

發(fā)布時間:2022-09-05 09:30:28 來源:億速云 閱讀:170 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Python機器學(xué)習(xí)類別特征的處理方法有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Python機器學(xué)習(xí)類別特征的處理方法有哪些”吧!

類別型特征(categorical feature)主要是指職業(yè),血型等在有限類別內(nèi)取值的特征。它的原始輸入通常是字符串形式,大多數(shù)算法模型不接受數(shù)值型特征的輸入,針對數(shù)值型的類別特征會被當(dāng)成數(shù)值型特征,從而造成訓(xùn)練的模型產(chǎn)生錯誤。

Python機器學(xué)習(xí)類別特征的處理方法有哪些

Label encoding

Label Encoding是使用字典的方式,將每個類別標(biāo)簽與不斷增加的整數(shù)相關(guān)聯(lián),即生成一個名為class_的實例數(shù)組的索引。

Scikit-learn中的LabelEncoder是用來對分類型特征值進行編碼,即對不連續(xù)的數(shù)值或文本進行編碼。其中包含以下常用方法:

  • fit(y) :fit可看做一本空字典,y可看作要塞到字典中的詞。

  • fit_transform(y):相當(dāng)于先進行fit再進行transform,即把y塞到字典中去以后再進行transform得到索引值。

  • inverse_transform(y):根據(jù)索引值y獲得原始數(shù)據(jù)。

  • transform(y) :將y轉(zhuǎn)變成索引值。

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
city_list = ["paris", "paris", "tokyo", "amsterdam"]
le.fit(city_list)
print(le.classes_)  # 輸出為:['amsterdam' 'paris' 'tokyo']
city_list_le = le.transform(city_list)  # 進行Encode
print(city_list_le)  # 輸出為:[1 1 2 0]
city_list_new = le.inverse_transform(city_list_le)  # 進行decode
print(city_list_new) # 輸出為:['paris' 'paris' 'tokyo' 'amsterdam']

多列數(shù)據(jù)編碼方式:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
df = pd.DataFrame({
    'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
    'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
    'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
                 'New_York']
})
d = {}
le = LabelEncoder()
cols_to_encode = ['pets', 'owner', 'location']
for col in cols_to_encode:
    df_train[col] = le.fit_transform(df_train[col])
    d[col] = le.classes_

Pandas的factorize()可以將Series中的標(biāo)稱型數(shù)據(jù)映射稱為一組數(shù)字,相同的標(biāo)稱型映射為相同的數(shù)字。factorize函數(shù)的返回值是一個tuple(元組),元組中包含兩個元素。第一個元素是一個array,其中的元素是標(biāo)稱型元素映射為的數(shù)字;第二個元素是Index類型,其中的元素是所有標(biāo)稱型元素,沒有重復(fù)。

import numpy as np
import pandas as pd
df = pd.DataFrame(['green','bule','red','bule','green'],columns=['color'])
pd.factorize(df['color'])  #(array([0, 1, 2, 1, 0], dtype=int64),Index(['green', 'bule', 'red'], dtype='object'))
pd.factorize(df['color'])[0] #array([0, 1, 2, 1, 0], dtype=int64)
pd.factorize(df['color'])[1]  #Index(['green', 'bule', 'red'], dtype='object')

Label Encoding只是將文本轉(zhuǎn)化為數(shù)值,并沒有解決文本特征的問題:所有的標(biāo)簽都變成了數(shù)字,算法模型直接將根據(jù)其距離來考慮相似的數(shù)字,而不考慮標(biāo)簽的具體含義。使用該方法處理后的數(shù)據(jù)適合支持類別性質(zhì)的算法模型,如LightGBM。

序列編碼(Ordinal Encoding)

Ordinal Encoding即最為簡單的一種思路,對于一個具有m個category的Feature,我們將其對應(yīng)地映射到 [0,m-1] 的整數(shù)。當(dāng)然 Ordinal Encoding 更適用于 Ordinal Feature,即各個特征有內(nèi)在的順序。例如對于”學(xué)歷”這樣的類別,”學(xué)士”、”碩士”、”博士” 可以很自然地編碼成 [0,2],因為它們內(nèi)在就含有這樣的邏輯順序。但如果對于“顏色”這樣的類別,“藍色”、“綠色”、“紅色”分別編碼成[0,2]是不合理的,因為我們并沒有理由認為“藍色”和“綠色”的差距比“藍色”和“紅色”的差距對于特征的影響是不同的。

ord_map = {'Gen 1': 1, 'Gen 2': 2, 'Gen 3': 3, 'Gen 4': 4, 'Gen 5': 5, 'Gen 6': 6}
df['GenerationLabel'] = df['Generation'].map(gord_map)

獨熱編碼(One-Hot Encoding)

在實際的機器學(xué)習(xí)的應(yīng)用任務(wù)中,特征有時候并不總是連續(xù)值,有可能是一些分類值,如性別可分為male和female。在機器學(xué)習(xí)任務(wù)中,對于這樣的特征,通常我們需要對其進行特征數(shù)字化,比如有如下三個特征屬性:

  • 性別:[“male”,”female”]

  • 地區(qū):[“Europe”,”US”,”Asia”]

  • 瀏覽器:[“Firefox”,”Chrome”,”Safari”,”Internet Explorer”]

對于某一個樣本,如[“male”,”US”,”Internet Explorer”],我們需要將這個分類值的特征數(shù)字化,最直接的方法,我們可以采用序列化的方式:[0,1,3]。但是,即使轉(zhuǎn)化為數(shù)字表示后,上述數(shù)據(jù)也不能直接用在我們的分類器中。因為,分類器往往默認數(shù)據(jù)是連續(xù)的,并且是有序的。按照上述的表示,數(shù)字并不是有序的,而是隨機分配的。這樣的特征處理并不能直接放入機器學(xué)習(xí)算法中。

為了解決上述問題,其中一種可能的解決方法是采用獨熱編碼(One-Hot Encoding)。獨熱編碼,又稱為一位有效編碼。其方法是使用N位狀態(tài)寄存器來對N個狀態(tài)進行編碼,每個狀態(tài)都由他獨立的寄存器位,并且在任意時候,其中只有一位有效??梢赃@樣理解,對于每一個特征,如果它有m個可能值,那么經(jīng)過獨熱編碼后,就變成了m個二元特征。并且,這些特征互斥,每次只有一個激活。因此,數(shù)據(jù)會變成稀疏的。

對于上述的問題,性別的屬性是二維的,同理,地區(qū)是三維的,瀏覽器則是四維的,這樣,我們可以采用One-Hot編碼的方式對上述的樣本[“male”,”US”,”Internet Explorer”]編碼,male則對應(yīng)著[1,0],同理US對應(yīng)著[0,1,0],Internet Explorer對應(yīng)著[0,0,0,1]。則完整的特征數(shù)字化的結(jié)果為:[1,0,0,1,0,0,0,0,1]。

Python機器學(xué)習(xí)類別特征的處理方法有哪些

為什么能使用One-Hot Encoding?

使用one-hot編碼,將離散特征的取值擴展到了歐式空間,離散特征的某個取值就對應(yīng)歐式空間的某個點。在回歸,分類,聚類等機器學(xué)習(xí)算法中,特征之間距離的計算或相似度的計算是非常重要的,而我們常用的距離或相似度的計算都是在歐式空間的相似度計算,計算余弦相似性,也是基于的歐式空間。

將離散型特征使用one-hot編碼,可以會讓特征之間的距離計算更加合理。比如,有一個離散型特征,代表工作類型,該離散型特征,共有三個取值,不使用one-hot編碼,計算出來的特征的距離是不合理。那如果使用one-hot編碼,顯得更合理。

獨熱編碼優(yōu)缺點

優(yōu)點:獨熱編碼解決了分類器不好處理屬性數(shù)據(jù)的問題,在一定程度上也起到了擴充特征的作用。它的值只有0和1,不同的類型存儲在垂直的空間。

缺點:當(dāng)類別的數(shù)量很多時,特征空間會變得非常大。在這種情況下,一般可以用PCA(主成分分析)來減少維度。而且One-Hot Encoding+PCA這種組合在實際中也非常有用。

One-Hot Encoding的使用場景

獨熱編碼用來解決類別型數(shù)據(jù)的離散值問題。將離散型特征進行one-hot編碼的作用,是為了讓距離計算更合理,但如果特征是離散的,并且不用one-hot編碼就可以很合理的計算出距離,那么就沒必要進行one-hot編碼,比如,該離散特征共有1000個取值,我們分成兩組,分別是400和600,兩個小組之間的距離有合適的定義,組內(nèi)的距離也有合適的定義,那就沒必要用one-hot 編碼。

基于樹的方法是不需要進行特征的歸一化,例如隨機森林,bagging 和 boosting等。對于決策樹來說,one-hot的本質(zhì)是增加樹的深度,決策樹是沒有特征大小的概念的,只有特征處于他分布的哪一部分的概念。

基于Scikit-learn 的one hot encoding

LabelBinarizer:將對應(yīng)的數(shù)據(jù)轉(zhuǎn)換為二進制型,類似于onehot編碼,這里有幾點不同:

  • 可以處理數(shù)值型和類別型數(shù)據(jù)

  • 輸入必須為1D數(shù)組

  • 可以自己設(shè)置正類和父類的表示方式

from sklearn.preprocessing import LabelBinarizer
 
lb = LabelBinarizer()
 
city_list = ["paris", "paris", "tokyo", "amsterdam"]
 
lb.fit(city_list)
print(lb.classes_)  # 輸出為:['amsterdam' 'paris' 'tokyo']
 
city_list_le = lb.transform(city_list)  # 進行Encode
print(city_list_le)  # 輸出為:
# [[0 1 0]
#  [0 1 0]
#  [0 0 1]
#  [1 0 0]]
 
city_list_new = lb.inverse_transform(city_list_le)  # 進行decode
print(city_list_new)  # 輸出為:['paris' 'paris' 'tokyo' 'amsterdam']

OneHotEncoder只能對數(shù)值型數(shù)據(jù)進行處理,需要先將文本轉(zhuǎn)化為數(shù)值(Label encoding)后才能使用,只接受2D數(shù)組:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
def LabelOneHotEncoder(data, categorical_features):
    d_num = np.array([])
    for f in data.columns:
        if f in categorical_features:
            le, ohe = LabelEncoder(), OneHotEncoder()
            data[f] = le.fit_transform(data[f])
            if len(d_num) == 0:
                d_num = np.array(ohe.fit_transform(data[[f]]))
            else:
                d_num = np.hstack((d_num, ohe.fit_transform(data[[f]]).A))
        else:
            if len(d_num) == 0:
                d_num = np.array(data[[f]])
            else:
                d_num = np.hstack((d_num, data[[f]]))
    return d_num
df = pd.DataFrame([
    ['green', 'Chevrolet', 2017],
    ['blue', 'BMW', 2015],
    ['yellow', 'Lexus', 2018],
])
df.columns = ['color', 'make', 'year']
df_new = LabelOneHotEncoder(df, ['color', 'make', 'year'])

基于Pandas的one hot encoding

其實如果我們跳出 scikit-learn, 在 pandas 中可以很好地解決這個問題,用 pandas 自帶的get_dummies函數(shù)即可

import pandas as pd
 
df = pd.DataFrame([
    ['green', 'Chevrolet', 2017],
    ['blue', 'BMW', 2015],
    ['yellow', 'Lexus', 2018],
])
df.columns = ['color', 'make', 'year']
df_processed = pd.get_dummies(df, prefix_sep="_", columns=df.columns[:-1])
print(df_processed)

get_dummies的優(yōu)勢在于:

  • 本身就是 pandas 的模塊,所以對 DataFrame 類型兼容很好

  • 不管你列是數(shù)值型還是字符串型,都可以進行二值化編碼

  • 能夠根據(jù)指令,自動生成二值化編碼后的變量名

get_dummies雖然有這么多優(yōu)點,但畢竟不是 sklearn 里的transformer類型,所以得到的結(jié)果得手動輸入到 sklearn 里的相應(yīng)模塊,也無法像 sklearn 的transformer一樣可以輸入到pipeline中進行流程化地機器學(xué)習(xí)過程。

頻數(shù)編碼(Frequency Encoding/Count Encoding)

將類別特征替換為訓(xùn)練集中的計數(shù)(一般是根據(jù)訓(xùn)練集來進行計數(shù),屬于統(tǒng)計編碼的一種,統(tǒng)計編碼,就是用類別的統(tǒng)計特征來代替原始類別,比如類別A在訓(xùn)練集中出現(xiàn)了100次則編碼為100)。這個方法對離群值很敏感,所以結(jié)果可以歸一化或者轉(zhuǎn)換一下(例如使用對數(shù)變換)。未知類別可以替換為1。

頻數(shù)編碼使用頻次替換類別。有些變量的頻次可能是一樣的,這將導(dǎo)致碰撞。盡管可能性不是非常大,沒法說這是否會導(dǎo)致模型退化,不過原則上我們不希望出現(xiàn)這種情況。

import pandas as pd
data_count = data.groupby('城市')['城市'].agg({'頻數(shù)':'size'}).reset_index()
data = pd.merge(data, data_count, on = '城市', how = 'left')

目標(biāo)編碼(Target Encoding/Mean Encoding)

目標(biāo)編碼(target encoding),亦稱均值編碼(mean encoding)、似然編碼(likelihood encoding)、效應(yīng)編碼(impact encoding),是一種能夠?qū)Ω呋鶖?shù)(high cardinality)自變量進行編碼的方法 (Micci-Barreca 2001) 。

如果某一個特征是定性的(categorical),而這個特征的可能值非常多(高基數(shù)),那么目標(biāo)編碼(Target encoding)是一種高效的編碼方式。在實際應(yīng)用中,這類特征工程能極大提升模型的性能。

一般情況下,針對定性特征,我們只需要使用sklearn的OneHotEncoder或LabelEncoder進行編碼。

LabelEncoder能夠接收不規(guī)則的特征列,并將其轉(zhuǎn)化為從0到n-1的整數(shù)值(假設(shè)一共有n種不同的類別);OneHotEncoder則能通過啞編碼,制作出一個m*n的稀疏矩陣(假設(shè)數(shù)據(jù)一共有m行,具體的輸出矩陣格式是否稀疏可以由sparse參數(shù)控制)。

定性特征的基數(shù)(cardinality)指的是這個定性特征所有可能的不同值的數(shù)量。在高基數(shù)(high cardinality)的定性特征面前,這些數(shù)據(jù)預(yù)處理的方法往往得不到令人滿意的結(jié)果。

高基數(shù)定性特征的例子:IP地址、電子郵件域名、城市名、家庭住址、街道、產(chǎn)品號碼。

主要原因:

  • LabelEncoder編碼高基數(shù)定性特征,雖然只需要一列,但是每個自然數(shù)都具有不同的重要意義,對于y而言線性不可分。使用簡單模型,容易欠擬合(underfit),無法完全捕獲不同類別之間的區(qū)別;使用復(fù)雜模型,容易在其他地方過擬合(overfit)。

  • OneHotEncoder編碼高基數(shù)定性特征,必然產(chǎn)生上萬列的稀疏矩陣,易消耗大量內(nèi)存和訓(xùn)練時間,除非算法本身有相關(guān)優(yōu)化(例:SVM)。

如果某個類別型特征基數(shù)比較低(low-cardinality features),即該特征的所有值去重后構(gòu)成的集合元素個數(shù)比較少,一般利用One-hot編碼方法將特征轉(zhuǎn)為數(shù)值型。One-hot編碼可以在數(shù)據(jù)預(yù)處理時完成,也可以在模型訓(xùn)練的時候完成,從訓(xùn)練時間的角度,后一種方法的實現(xiàn)更為高效,CatBoost對于基數(shù)較低的類別型特征也是采用后一種實現(xiàn)。

顯然,在高基數(shù)類別型特征(high cardinality features) 當(dāng)中,比如 user ID,這種編碼方式會產(chǎn)生大量新的特征,造成維度災(zāi)難。一種折中的辦法是可以將類別分組成有限個的群體再進行One-hot編碼。一種常被使用的方法是根據(jù)目標(biāo)變量統(tǒng)計(Target Statistics,以下簡稱TS)進行分組,目標(biāo)變量統(tǒng)計用于估算每個類別的目標(biāo)變量期望值。甚至有人直接用TS作為一個新的數(shù)值型變量來代替原來的類別型變量。重要的是,可以通過對TS數(shù)值型特征的閾值設(shè)置,基于對數(shù)損失、基尼系數(shù)或者均方差,得到一個對于訓(xùn)練集而言將類別一分為二的所有可能劃分當(dāng)中最優(yōu)的那個。在LightGBM當(dāng)中,類別型特征用每一步梯度提升時的梯度統(tǒng)計(Gradient Statistics,以下簡稱GS)來表示。雖然為建樹提供了重要的信息,但是這種方法有以下兩個缺點:

  • 增加計算時間,因為需要對每一個類別型特征,在迭代的每一步,都需要對GS進行計算

  • 增加存儲需求,對于一個類別型變量,需要存儲每一次分離每個節(jié)點的類別

為了克服這些缺點,LightGBM以損失部分信息為代價將所有的長尾類別歸為一類,作者聲稱這樣處理高基數(shù)類別型特征時比One-hot編碼還是好不少。不過如果采用TS特征,那么對于每個類別只需要計算和存儲一個數(shù)字。因此,采用TS作為一個新的數(shù)值型特征是最有效、信息損失最小的處理類別型特征的方法。TS也被廣泛應(yīng)用在點擊預(yù)測任務(wù)當(dāng)中,這個場景當(dāng)中的類別型特征有用戶、地區(qū)、廣告、廣告發(fā)布者等。接下來我們著重討論TS,暫時將One-hot編碼和GS放一邊。

以下是計算公式:

其中 n 代表的是該某個特征取值的個數(shù),

代表某個特征取值下正Label的個數(shù),mdl為一個最小閾值,樣本數(shù)量小于此值的特征類別將被忽略,prior是Label的均值。注意,如果是處理回歸問題的話,可以處理成相應(yīng)該特征下label取值的average/max。對于k分類問題,會生成對應(yīng)的k-1個特征。

此方法同樣容易引起過擬合,以下方法用于防止過擬合:

  • 增加正則項a的大小

  • 在訓(xùn)練集該列中添加噪聲

  • 使用交叉驗證

目標(biāo)編碼屬于有監(jiān)督的編碼方式,如果運用得當(dāng)則能夠有效地提高預(yù)測模型的準(zhǔn)確性 (Pargent, Bischl, and Thomas 2019) ;而這其中的關(guān)鍵,就是在編碼的過程中引入正則化,避免過擬合問題。

例如類別A對應(yīng)的標(biāo)簽1有200個,標(biāo)簽2有300個,標(biāo)簽3有500個,則可以編碼為:2/10,3/10,3/6。中間最重要的是如何避免過擬合(原始的target encoding直接對全部的訓(xùn)練集數(shù)據(jù)和標(biāo)簽進行編碼,會導(dǎo)致得到的編碼結(jié)果太過依賴與訓(xùn)練集),常用的解決方法是使用2 levels of cross-validation求出target mean,思路如下:

  • 把train data劃分為20-folds (舉例:infold: fold #2-20, out of fold: fold #1)

  • 計算 10-folds的 inner out of folds值 (舉例:使用inner_infold #2-10 的target的均值,來作為inner_oof #1的預(yù)測值)

  • 對10個inner out of folds 值取平均,得到 inner_oof_mean

  • 將每一個 infold (fold #2-20) 再次劃分為10-folds (舉例:inner_infold: fold #2-10, Inner_oof: fold #1)

  • 計算oof_mean (舉例:使用 infold #2-20的inner_oof_mean 來預(yù)測 out of fold #1的oof_mean

  • 將train data 的 oof_mean 映射到test data完成編碼

比如劃分為10折,每次對9折進行標(biāo)簽編碼然后用得到的標(biāo)簽編碼模型預(yù)測第10折的特征得到結(jié)果,其實就是常說的均值編碼。

目標(biāo)編碼嘗試對分類特征中每個級別的目標(biāo)總體平均值進行測量。這意味著,當(dāng)每個級別的數(shù)據(jù)更少時,估計的均值將與“真實”均值相距更遠,方差更大。

from category_encoders import TargetEncoder
import pandas as pd
from sklearn.datasets import load_boston
# prepare some data
bunch = load_boston()
y_train = bunch.target[0:250]
y_test = bunch.target[250:506]
X_train = pd.DataFrame(bunch.data[0:250], columns=bunch.feature_names)
X_test = pd.DataFrame(bunch.data[250:506], columns=bunch.feature_names)
# use target encoding to encode two categorical features
enc = TargetEncoder(cols=['CHAS', 'RAD'])
# transform the datasets
training_numeric_dataset = enc.fit_transform(X_train, y_train)
testing_numeric_dataset = enc.transform(X_test)

Beta Target Encoding

Kaggle競賽Avito Demand Prediction Challenge 第14名的solution分享:14th Place Solution: The Almost Golden Defenders。和target encoding 一樣,beta target encoding 也采用 target mean value (among each category) 來給categorical feature做編碼。不同之處在于,為了進一步減少target variable leak,beta target encoding發(fā)生在在5-fold CV內(nèi)部,而不是在5-fold CV之前:

  • 把train data劃分為5-folds (5-fold cross validation)

  • target encoding based on infold data

  • train model

  • get out of fold prediction

同時beta target encoding 加入了smoothing term,用 bayesian mean 來代替mean。Bayesian mean (Bayesian average) 的思路:某一個category如果數(shù)據(jù)量較少(<N_min),noise就會比較大,需要補足數(shù)據(jù),達到smoothing 的效果。補足數(shù)據(jù)值 = prior mean。N_min 是一個regularization term,N_min 越大,regularization效果越強。

另外,對于target encoding和beta target encoding,不一定要用target mean (or bayesian mean),也可以用其他的統(tǒng)計值包括 medium, frqequency, mode, variance, skewness, and kurtosis &mdash; 或任何與target有correlation的統(tǒng)計值。

# train -> training dataframe
# test -> test dataframe
# N_min -> smoothing term, minimum sample size, if sample size is less than N_min, add up to N_min 
# target_col -> target column
# cat_cols -> categorical colums
# Step 1: fill NA in train and test dataframe
# Step 2: 5-fold CV (beta target encoding within each fold)
kf = KFold(n_splits=5, shuffle=True, random_state=0)
for i, (dev_index, val_index) in enumerate(kf.split(train.index.values)):
    # split data into dev set and validation set
    dev = train.loc[dev_index].reset_index(drop=True) 
    val = train.loc[val_index].reset_index(drop=True)
        
    feature_cols = []    
    for var_name in cat_cols:
        feature_name = f'{var_name}_mean'
        feature_cols.append(feature_name)
        
        prior_mean = np.mean(dev[target_col])
        stats = dev[[target_col, var_name]].groupby(var_name).agg(['sum', 'count'])[target_col].reset_index()           
   
        ### beta target encoding by Bayesian average for dev set 
        df_stats = pd.merge(dev[[var_name]], stats, how='left')
        df_stats['sum'].fillna(value = prior_mean, inplace = True)
        df_stats['count'].fillna(value = 1.0, inplace = True)
        N_prior = np.maximum(N_min - df_stats['count'].values, 0)   # prior parameters
        dev[feature_name] = (prior_mean * N_prior + df_stats['sum']) / (N_prior + df_stats['count']) # Bayesian mean
        ### beta target encoding by Bayesian average for val set
        df_stats = pd.merge(val[[var_name]], stats, how='left')
        df_stats['sum'].fillna(value = prior_mean, inplace = True)
        df_stats['count'].fillna(value = 1.0, inplace = True)
        N_prior = np.maximum(N_min - df_stats['count'].values, 0)   # prior parameters
        val[feature_name] = (prior_mean * N_prior + df_stats['sum']) / (N_prior + df_stats['count']) # Bayesian mean
        
        ### beta target encoding by Bayesian average for test set
        df_stats = pd.merge(test[[var_name]], stats, how='left')
        df_stats['sum'].fillna(value = prior_mean, inplace = True)
        df_stats['count'].fillna(value = 1.0, inplace = True)
        N_prior = np.maximum(N_min - df_stats['count'].values, 0)   # prior parameters
        test[feature_name] = (prior_mean * N_prior + df_stats['sum']) / (N_prior + df_stats['count']) # Bayesian mean
        
        # Bayesian mean is equivalent to adding N_prior data points of value prior_mean to the data set.
        del df_stats, stats
    # Step 3: train model (K-fold CV), get oof predictio

M-Estimate Encoding

M-Estimate Encoding 相當(dāng)于 一個簡化版的Target Encoding:

其中????+代表所有正Label的個數(shù),m是一個調(diào)參的參數(shù),m越大過擬合的程度就會越小,同樣的在處理連續(xù)值時????+可以換成label的求和,????+換成所有l(wèi)abel的求和。

James-Stein Encoding

James-Stein Encoding 同樣是基于target的一種算法。算法的思想很簡單,對于特征的每個取值 k 可以根據(jù)下面的公式獲得:

其中B由以下公式估計:

但是它有一個要求是target必須符合正態(tài)分布,這對于分類問題是不可能的,因此可以把y先轉(zhuǎn)化成概率的形式?;蛘咴趯嶋H操作中,使用grid search的方法選擇一個比較好的B值。

Weight of Evidence Encoder

Weight Of Evidence 同樣是基于target的方法。

使用WOE作為變量,第i類的WOE等于:

WOE特別合適邏輯回歸,因為Logit=log(odds)。WOE編碼的變量被編碼為統(tǒng)一的維度(是一個被標(biāo)準(zhǔn)化過的值),變量之間直接比較系數(shù)即可。

Leave-one-out Encoder (LOO or LOOE)

這個方法類似于SUM的方法,只是在計算訓(xùn)練集每個樣本的特征值轉(zhuǎn)換時都要把該樣本排除(消除特征某取值下樣本太少導(dǎo)致的嚴重過擬合),在計算測試集每個樣本特征值轉(zhuǎn)換時與SUM相同??梢娨韵鹿剑?/p>

Binary Encoding

把每一類的序號用二進制進行編碼,使用log2N維向量來編碼N類。例如:(0,0)代表第一類,(0,1)代表第二類,(1,0)代表第三類,(1,1)代表第四類

Hashing Encoding

類似于One-hot encoding,但是通過hash函數(shù)映射到一個低維空間,并且使得兩個類對應(yīng)向量的空間距離基本保持一致。使用低維空間來降低了表示向量的維度。

特征哈希可能會導(dǎo)致要素之間發(fā)生沖突。但哈希編碼的優(yōu)點是它不需要制定和維護原變量與新變量之間的映射關(guān)系。因此,哈希編碼器的大小及復(fù)雜程度不隨數(shù)據(jù)類別的增多而增多。

Probability Ratio Encoding

和WOE相似,只是去掉了log,即:

Sum Encoder (Deviation Encoder, Effect Encoder)

求和編碼通過比較某一特征取值下對應(yīng)標(biāo)簽(或其他相關(guān)變量)的均值與標(biāo)簽的均值之間的差別來對特征進行編碼。如果做不好細節(jié),這個方法非常容易出現(xiàn)過擬合,所以需要配合留一法或者五折交叉驗證進行特征的編碼。還有根據(jù)方差加入懲罰項防止過擬合的方法。

Helmert Encoding

Helmert編碼通常在計量經(jīng)濟學(xué)中使用。在Helmert編碼(分類特征中的每個值對應(yīng)于Helmert矩陣中的一行)之后,線性模型中編碼后的變量系數(shù)可以反映在給定該類別變量某一類別值的情形下因變量的平均值與給定該類別其他類別值的情形下因變量的平均值的差值。

Helmet編碼是僅次于One-Hot Encoding和Sum Encoder使用最廣泛的編碼方法,與Sum Encoder不同的是,它比較的是某一特征取值下對應(yīng)標(biāo)簽(或其他相關(guān)變量)的均值與他之前特征的均值之間的差異,而不是和所有特征的均值比較。這個特征同樣容易出現(xiàn)過擬合的情況。

CatBoost Encoding

對于可取值的數(shù)量比獨熱最大量還要大的分類變量,CatBoost 使用了一個非常有效的編碼方法,這種方法和均值編碼類似,但可以降低過擬合情況。它的具體實現(xiàn)方法如下:

  • 將輸入樣本集隨機排序,并生成多組隨機排列的情況。

  • 將浮點型或?qū)傩灾禈?biāo)記轉(zhuǎn)化為整數(shù)。

  • 將所有的分類特征值結(jié)果都根據(jù)以下公式,轉(zhuǎn)化為數(shù)值結(jié)果。

其中 CountInClass 表示在當(dāng)前分類特征值中,有多少樣本的標(biāo)記值是1;Prior 是分子的初始值,根據(jù)初始參數(shù)確定。TotalCount 是在所有樣本中(包含當(dāng)前樣本),和當(dāng)前樣本具有相同的分類特征值的樣本數(shù)量。

CatBoost處理Categorical features總結(jié):

首先,他們會計算一些數(shù)據(jù)的statistics。計算某個category出現(xiàn)的頻率,加上超參數(shù),生成新的numerical features。這一策略要求同一標(biāo)簽數(shù)據(jù)不能排列在一起(即先全是0之后全是1這種方式),訓(xùn)練之前需要打亂數(shù)據(jù)集。

第二,使用數(shù)據(jù)的不同排列(實際上是4個)。在每一輪建立樹之前,先扔一輪骰子,決定使用哪個排列來生成樹。

第三,考慮使用categorical features的不同組合。例如顏色和種類組合起來,可以構(gòu)成類似于blue dog這樣的feature。當(dāng)需要組合的categorical features變多時,catboost只考慮一部分combinations。在選擇第一個節(jié)點時,只考慮選擇一個feature,例如A。在生成第二個節(jié)點時,考慮A和任意一個categorical feature的組合,選擇其中最好的。就這樣使用貪心算法生成combinations。

第四,除非向gender這種維數(shù)很小的情況,不建議自己生成one-hot vectors,最好交給算法來處理。

感謝各位的閱讀,以上就是“Python機器學(xué)習(xí)類別特征的處理方法有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Python機器學(xué)習(xí)類別特征的處理方法有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI