機(jī)器學(xué)習(xí)中的特征工程(三)---- 序數(shù)和類別特征處理方法

簡(jiǎn)介

本文主要說明特征工程中關(guān)于序數(shù)特征和類別特征的常用處理方法。主要包含LabelEncoder、One-Hot編碼、DummyCoding询吴、FeatureHasher以及要重點(diǎn)介紹的WOE編碼。

序數(shù)特征處理

序數(shù)特征指的是有序但無尺度的特征亮元。比如表示‘學(xué)歷’的特征猛计,'高中'、'本科'爆捞、'碩士'奉瘤,這些特征彼此之間是有順序關(guān)系的,但是特征本身無尺度煮甥,并且也可能不是數(shù)值類型毛好。在實(shí)際應(yīng)用中望艺,一般是字符類型居多,為了將其轉(zhuǎn)換成模型能處理的形式肌访,通常需要先進(jìn)行編碼找默,比如LabelEncoding。如果序數(shù)特征本身就是數(shù)值類型變量吼驶,則可不進(jìn)行該步驟惩激。下面依次介紹序數(shù)特征相關(guān)的處理方式。

Label Encoding

首先介紹Label Encoding編碼方式蟹演,該方式默認(rèn)從0開始风钻,按照變量字符順序排序,例子如下:

from sklearn.preprocessing import LabelEncoder

x = ['a', 'b', 'a', 'c', 'b']

encoder = LabelEncoder()
x1 = encoder.fit_transform(x)
x1
編碼結(jié)果

可以看到酒请,原始特征一共被分為了3類骡技,'a'、'b'羞反、'c'編碼后分別為'0'布朦、'1'、'2'昼窗。
如果你的數(shù)據(jù)是用pandas表示的是趴,pandas中也有類似的處理方式,通過類別編碼的方式得到的結(jié)果是一樣的澄惊。

import pandas as pd

x2 = pd.Series(x).astype('category')
x2.cat.codes.values
編碼結(jié)果

因子化

除此之外唆途,pandas中還有一種編碼方式,叫做'因子化'掸驱。不過它并不是按照特征的字符順序來排序的肛搬,而是按照特征變量出現(xiàn)的先后順序來編碼的,結(jié)果本質(zhì)上沒有區(qū)別毕贼。對(duì)比例子如下:

x = ['a', 'b', 'a', 'c', 'b']
# 調(diào)換了第一個(gè)a和第四個(gè)c的位置
x1 = ['c', 'b', 'a', 'a', 'b']

x2, uniques = pd.factorize(x)
x3, uniques = pd.factorize(x1)
print("x2: ", x2)
print("x3: ", x3)
編碼結(jié)果

二值化

序數(shù)特征還可以進(jìn)行二值化操作滚婉,小于或者大于閾值的時(shí)候分別為0和1。實(shí)例如下:

x = ['a', 'b', 'a', 'c', 'b']
x4 = pd.Series(x)
x4 = (x4 >= 'b').astype(int) #令大于等于'b'的都為1
x4.values
二值化結(jié)果

類別特征處理

類別特征由于沒有順序也沒有尺度帅刀,因此處理較為麻煩,但是在CTR等領(lǐng)域卻是非常常見的特征远剩。比如商品的類型扣溺,顏色,用戶的職業(yè)瓜晤,興趣等等锥余。類別變量編碼方法中最常使用的就是One-Hot編碼,接下來結(jié)合具體實(shí)例來介紹痢掠。

One-Hot編碼

One-Hot編碼驱犹,又稱為'獨(dú)熱編碼'嘲恍,其變換后的單列特征值只有一位是1。如下例所示雄驹,一個(gè)特征中包含3個(gè)不同的特征值(a,b,c)佃牛,編碼轉(zhuǎn)換后變成3個(gè)子特征,其中每個(gè)特征值中只有一位是有效位1医舆。

from sklearn.preprocessing import LabelEncoder, OneHotEncoder

one_feature = ['b', 'a', 'c']
label_encoder = LabelEncoder()
feature = label_encoder.fit_transform(one_feature)
onehot_encoder = OneHotEncoder(sparse=False)
onehot_encoder.fit_transform(feature.reshape(-1, 1))
one-hot編碼結(jié)果

這里要注意的是俘侠,因?yàn)樵继卣魇亲址愋停@里使用上一節(jié)的LabelEncoder先將其轉(zhuǎn)換成數(shù)值類型蔬将。但是實(shí)際上這一步也不需要爷速,OneHotEncoder可以直接處理字符串類型。

LabelBinarizer

sklearn中的LabelBinarizer也具有同樣的作用霞怀,代碼如下:

from sklearn.preprocessing import LabelBinarizer
feature = np.array(['b', 'a', 'c'])
LabelBinarizer().fit_transform(feature)
LabelBinarizer轉(zhuǎn)換結(jié)果

虛擬編碼Dummy Coding

同樣惫东,pandas中也內(nèi)置了對(duì)應(yīng)的處理方式,使用起來比Sklearn更加方便。實(shí)例如下:

one_feature = ['b', 'a', 'c']
pd.get_dummies(one_feature, prefix='test') # 設(shè)置前綴test
get_dummies編碼

其實(shí)仔細(xì)觀察One-Hot編碼會(huì)發(fā)現(xiàn)毙石,具有n個(gè)類別值的單個(gè)特征將會(huì)編碼成n個(gè)子特征廉沮。但實(shí)際上有一維是冗余的。虛擬編碼(dummy coding)可以只產(chǎn)生n-1個(gè)特征胁黑,再使用一個(gè)全零的向量废封,實(shí)例如下:

one_feature = ['b', 'a', 'c']
pd.get_dummies(one_feature, prefix='test', drop_first=True) # 設(shè)置前綴test
虛擬編碼

可以看到這里只產(chǎn)生了2個(gè)子特征,剩余的一個(gè)特征由全零向量表示丧蘸。

特征哈希

按照上述編碼方式漂洋,如果某個(gè)特征具有100個(gè)類別值,那么經(jīng)過編碼后將產(chǎn)生100個(gè)或99個(gè)新特征力喷,這極大地增加了特征維度和特征的稀疏度刽漂,同時(shí)還可能會(huì)出現(xiàn)內(nèi)存不足的情況。sklearn中的FeatureHasher接口采用了hash的方法弟孟,將不同的值映射到用戶指定長(zhǎng)度的數(shù)組中贝咙,使得輸出特征的維度是固定的,該方法占用內(nèi)存少拂募,效率高庭猩,可以在多類別變量值中使用,但是由于采用了Hash函數(shù)的方式陈症,所以具有沖突的可能蔼水,即不同的類別值可能映射到同一個(gè)特征變量值中。
下面的例子中录肯,原始特征類別值共有10個(gè)不同的值趴腋,但是只采用了長(zhǎng)度為5的數(shù)組進(jìn)行編碼。

from sklearn.feature_extraction import FeatureHasher

h = FeatureHasher(n_features=5, input_type='string')
test_cat = ['a','b','c','d','e','f','g','h','i','j','a','b']
f = h.transform(test_cat)
f.toarray()
FeatureHasher

可以看到編碼后的特征值是有重復(fù)的,說明多個(gè)不同的原始特征類別值編碼后优炬,被映射到了同一個(gè)類別里颁井。

多類別值處理方式

當(dāng)類別值過多時(shí),One-Hot 編碼或者Dummy Coding都可能導(dǎo)致編碼出來的特征過于稀疏蠢护,其次也會(huì)占用過多內(nèi)存雅宾。如果使用FeatureHasher,n_features的設(shè)置不好把握糊余,可能會(huì)造成過多沖突秀又,造成信息損失。這里提供一種基于統(tǒng)計(jì)的編碼方法贬芥,包括基于特征值的統(tǒng)計(jì)或者基于標(biāo)簽值的統(tǒng)計(jì)——基于標(biāo)簽的編碼吐辙。

下面的代碼演示了使用特征值出現(xiàn)頻數(shù)的分組方法,小于指定閾值的特征將被編碼為同一個(gè)值蘸劈。

import seaborn as sns

test = ['a','b','c','d','e','a','a','c']
df = pd.DataFrame(test, columns=['alpha'])
sns.countplot(df['alpha'])
頻數(shù)劃分

首先我們將每個(gè)類別值出現(xiàn)的頻數(shù)計(jì)算出來昏苏,比如我們?cè)O(shè)置閾值為1,那么所有小于閾值1的類別值都會(huì)被編碼為同一類威沫,大于1的類別值會(huì)分別編碼贤惯,如果出現(xiàn)頻數(shù)一樣的類別值,既可以都統(tǒng)一分為一個(gè)類棒掠,也可以按照某種順序進(jìn)行編碼孵构,這個(gè)可以根據(jù)業(yè)務(wù)需要自行決定。那么根據(jù)上圖烟很,可以得到其編碼值為:


按照頻數(shù)編碼結(jié)果

即(a,c)分別編碼為一個(gè)不同的類別颈墅,(e,b,d)編碼為同一個(gè)類別。

WOE編碼

WOE(Weight of Evidence雾袱,證據(jù)權(quán)重)編碼利用了標(biāo)簽信息恤筛,屬于有監(jiān)督的編碼方式。該方式廣泛用于金融領(lǐng)域信用風(fēng)險(xiǎn)模型中芹橡,是該領(lǐng)域的經(jīng)驗(yàn)做法毒坛。下面先給出WOE的計(jì)算公式:
WOE_i = ln\lbrace \frac {P_{y1}}{P_{y0}} \rbrace = ln\lbrace \frac {B_i / B}{G_i/G} \rbrace
WOE_i值可解釋為第i類別中好壞樣本分布比值的對(duì)數(shù)。其中各個(gè)分量的解釋如下:

  • P_{y1}表示該類別中壞樣本的分布
  • P_{y0}表示該類別中好樣本的分布
  • B_i/B表示該類別中壞樣本的數(shù)量在總體壞樣本中的占比
  • G_i/G表示該類別中好樣本的數(shù)量在總體好樣本中的占比

很明顯林说,如果整個(gè)分?jǐn)?shù)的值大于1煎殷,那么WOE值為正,否則為負(fù)腿箩,所以WOE值的取值范圍為正負(fù)無窮豪直。
WOE值直觀上表示的實(shí)際上是“當(dāng)前分組中壞客戶占所有壞客戶的比例”和“當(dāng)前分組中好客戶占所有壞客戶的比例”的差異。轉(zhuǎn)化公式以后度秘,也可以理解為:當(dāng)前這個(gè)組中壞客戶和好客戶的比值,和所有樣本中這個(gè)比值的差異。這個(gè)差異為這兩個(gè)比值的比值剑梳,再取對(duì)數(shù)來表示的唆貌。
WOE越大,這種差異越大垢乙,這個(gè)分組里的樣本壞樣本可能性就越大锨咙,WOE越小,差異越小追逮,這個(gè)分組里的壞樣本可能性就越小酪刀。

下面結(jié)合一個(gè)例子來說明WOE的計(jì)算:

np.random.seed(0)
# 隨機(jī)生成1000行數(shù)據(jù)
df = pd.DataFrame({
    'x': np.random.choice(['R','G','B'], 1000),
    'y': np.random.randint(2, size=1000)
})
df.head()
隨機(jī)生成的數(shù)據(jù)

其中x代表特征,包含3個(gè)類別(R钮孵,G骂倘,B),y表示標(biāo)簽巴席,取值范圍為0历涝、1,分別代表好漾唉、壞標(biāo)簽荧库。
分別統(tǒng)計(jì)該特征中各個(gè)類別的占比,代碼如下:

pd.crosstab(df['y'], df['x'], margins=True)

各類別占比
以類別R為例赵刑,我們來計(jì)算一下它的WOE值分衫。在該類別中,好樣本占153般此,壞樣本占184蚪战,所以其WOE編碼值為:
WOE_R = ln \lbrace \frac {184 / 519}{153/481} = 0.108461
同理可得WOE_G = -0.046184, WOE_B = -0.063841
由WOE值的定義推斷,相鄰類別的絕對(duì)值差異越大元咙,說明組之間差異越大既们,越具備區(qū)分性,預(yù)測(cè)性能越好概漱。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市喜喂,隨后出現(xiàn)的幾起案子瓤摧,更是在濱河造成了極大的恐慌,老刑警劉巖玉吁,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件照弥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡进副,警方通過查閱死者的電腦和手機(jī)这揣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門悔常,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人给赞,你說我怎么就攤上這事机打。” “怎么了片迅?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵残邀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我柑蛇,道長(zhǎng)芥挣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任耻台,我火速辦了婚禮空免,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粘我。我一直安慰自己鼓蜒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布征字。 她就那樣靜靜地躺著都弹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匙姜。 梳的紋絲不亂的頭發(fā)上畅厢,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音氮昧,去河邊找鬼框杜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袖肥,可吹牛的內(nèi)容都是我干的咪辱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼椎组,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼油狂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寸癌,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤专筷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蒸苇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磷蛹,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年溪烤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了味咳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庇勃。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖槽驶,靈堂內(nèi)的尸體忽然破棺而出匪凉,到底是詐尸還是另有隱情,我是刑警寧澤捺檬,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贸铜,受9級(jí)特大地震影響堡纬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒿秦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一烤镐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棍鳖,春花似錦炮叶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至医瘫,卻和暖如春侣肄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醇份。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工稼锅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僚纷。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓矩距,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怖竭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锥债,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容