技術(shù)頻道

娓娓工業(yè)
您現(xiàn)在的位置: 中國(guó)傳動(dòng)網(wǎng) > 技術(shù)頻道 > 技術(shù)百科 > 以KaggleDays數(shù)據(jù)集為例,編碼方法介紹

以KaggleDays數(shù)據(jù)集為例,編碼方法介紹

時(shí)間:2018-11-22 10:43:22來源:網(wǎng)絡(luò)轉(zhuǎn)載

導(dǎo)語(yǔ):?這是特征工程方法系列的第一篇。在機(jī)器學(xué)習(xí)的實(shí)踐中,特征工程是最重要而定義最松散的方面之一。它可以被視為藝術(shù),沒有嚴(yán)格的規(guī)則,創(chuàng)造性是其關(guān)鍵。

編者按:華沙大學(xué)機(jī)器學(xué)習(xí)科學(xué)家WojciechRosinski介紹了類別編碼的主要方法。

介紹

這是特征工程方法系列的第一篇。在機(jī)器學(xué)習(xí)的實(shí)踐中,特征工程是最重要而定義最松散的方面之一。它可以被視為藝術(shù),沒有嚴(yán)格的規(guī)則,創(chuàng)造性是其關(guān)鍵。

特征工程是要為機(jī)器學(xué)習(xí)模型創(chuàng)建更好的信息表示。即便使用非線性算法,如果使用原始數(shù)據(jù),我們也無法建模數(shù)據(jù)集的變量之間的所有交互(關(guān)系)。因此,我們需要手工探查、處理數(shù)據(jù)。

這就帶來了一個(gè)問題——深度學(xué)習(xí)怎么講?深度學(xué)習(xí)是為了最小化手工處理數(shù)據(jù)的需求,使模型能夠自行學(xué)習(xí)恰當(dāng)?shù)臄?shù)據(jù)表示。在圖像、語(yǔ)音、文本之類沒有給定其他“元數(shù)據(jù)”的數(shù)據(jù)上,深度學(xué)習(xí)會(huì)表現(xiàn)得更好。而在表格式數(shù)據(jù)上,沒有什么可以戰(zhàn)勝梯度提升樹方法,例如XGBoost或LightGBM。機(jī)器學(xué)習(xí)競(jìng)賽證明了這一點(diǎn)——幾乎所有表格式數(shù)據(jù)的獲勝方案中,基于決策樹的模型是最佳的,而深度學(xué)習(xí)模型通常沒法達(dá)到這么好的結(jié)果(但混合基于決策樹的模型時(shí)效果非常好;-))

特征工程的偏差是領(lǐng)域知識(shí)。取決于需要解決的問題,每個(gè)數(shù)據(jù)集應(yīng)該使用不同的特征工程方法,原因正在于此。不過,仍有一些廣泛使用的方法,至少值得嘗試下能否提升模型表現(xiàn)。HJvavVeen的講演中提到了大量的實(shí)用信息。下面的一些方法正是根據(jù)講演的描述實(shí)現(xiàn)的。

本文以KaggleDays數(shù)據(jù)集為例,編碼方法介紹參考了上面的講演。

數(shù)據(jù)集

數(shù)據(jù)來自reddit,包含問題和回答。目標(biāo)是預(yù)測(cè)回答的贊數(shù)。之所以用這個(gè)數(shù)據(jù)集為例,是因?yàn)樗谋竞蜆?biāo)準(zhǔn)特征。

引入需要用到的庫(kù):

importgc

importnumpyasnp

importpandasaspd

加載數(shù)據(jù):

X=pd.read_csv('../input/train.csv',sep="\t",index_col='id')

列:

['question_id',

'subreddit',

'question_utc',

'question_text',

'question_score',

'answer_utc',

'answer_text',

'answer_score']

每個(gè)question_id對(duì)應(yīng)一個(gè)具體問題(見question_text)。每個(gè)question_id可能出現(xiàn)多次,因?yàn)槊恳恍邪瑢?duì)這一問題的一個(gè)不同回答(見answer_text)。問題和回答的時(shí)間日期由_utc列提供。另外還包括問題發(fā)布的subreddit(版塊)的信息。question_score是問題的贊數(shù),而answer_score是回答的贊數(shù)。answer_score是目標(biāo)變量。

數(shù)據(jù)需要根據(jù)question_id分為訓(xùn)練子集和驗(yàn)證子集,仿效Kaggle分訓(xùn)練集和測(cè)試集的做法。

question_ids=X.question_id.unique()

question_ids_train=set(pd.Series(question_ids).sample(frac=0.8))

question_ids_valid=set(question_ids).difference(question_ids_train)

X_train=X[X.question_id.isin(question_ids_train)]

X_valid=X[X.question_id.isin(question_ids_valid)]

類別特征和數(shù)值特征

機(jī)器學(xué)習(xí)模型只能處理數(shù)字。數(shù)值(連續(xù)、定量)變量是可以在有限或無限區(qū)間內(nèi)取任何值的變量,它們可以很自然地用數(shù)字表示,所以可以在模型中直接使用。原始類別變量通常以字符串的形式存在,在傳入模型之前需要變換。

subreddit是類別變量的一個(gè)好例子,其中包含41個(gè)不同的類別,例如:

['AskReddit','Jokes','politics','explainlikeimfive','gaming']

讓我們看下最流行的類別(X.subreddit.value_counts()[:5]):

AskReddit275667

politics123003

news42271

worldnews40016

gaming32117

Name:subreddit,dtype:int64

數(shù)值變量的一個(gè)例子是question_score,可以通過X.question_score.describe()瀏覽信息:

mean770.891169

std3094.752794

min1.000000

25%2.000000

50%11.000000

75%112.000000

max48834.000000

Name:question_score,dtype:float64

類別特征編碼

類別編碼的兩個(gè)基本方法是獨(dú)熱編碼(onehotencoding)和標(biāo)簽編碼(labelencoding)。獨(dú)熱編碼可以通過pandas.get_dummies完成。具備K個(gè)類別的變量的編碼結(jié)果是一個(gè)K列的二值矩陣,其中第i列的值為1意味著這項(xiàng)觀測(cè)屬于第i類。

標(biāo)簽編碼直接將類別轉(zhuǎn)換為數(shù)字。pandas.factorize提供了這一功能,或者,pandas中category類型的列提供了cat.codes。使用標(biāo)簽編碼能夠保持原本的維度。

還有一些不那么標(biāo)準(zhǔn)的編碼方法也值得一試,它們可能可以提升模型的表現(xiàn)。這里將介紹三種方法:

頻數(shù)編碼(countencoding)

labelcount編碼

目標(biāo)編碼(targetencoding)

頻數(shù)編碼

頻數(shù)編碼使用頻次替換類別,頻次根據(jù)訓(xùn)練集計(jì)算。這個(gè)方法對(duì)離群值很敏感,所以結(jié)果可以歸一化或者轉(zhuǎn)換一下(例如使用對(duì)數(shù)變換)。未知類別可以替換為1。

盡管可能性不是非常大,有些變量的頻次可能是一樣的,這將導(dǎo)致碰撞——兩個(gè)類別編碼為相同的值。沒法說這是否會(huì)導(dǎo)致模型退化或者改善,不過原則上我們不希望出現(xiàn)這種情況。

defcount_encode(X,categorical_features,normalize=False):

print('Countencoding:{}'.format(categorical_features))

X_=pd.DataFrame()

forcat_featureincategorical_features:

X_[cat_feature]=X[cat_feature].astype(

'object').map(X[cat_feature].value_counts())

ifnormalize:

X_[cat_feature]=X_[cat_feature]/np.max(X_[cat_feature])

X_=X_.add_suffix('_count_encoded')

ifnormalize:

X_=X_.astype(np.float32)

X_=X_.add_suffix('_normalized')

else:

X_=X_.astype(np.uint32)

returnX_

讓我們編碼下subreddit列:

train_count_subreddit=count_encode(X_train,['subreddit'])

并查看結(jié)果。最流行的5個(gè)subreddit:

AskReddit221941

politics98233

news33559

worldnews32010

gaming25567

Name:subreddit,dtype:int64

編碼為:

221941221941

9823398233

3355933559

3201032010

2556725567

Name:subreddit_count_encoded,dtype:int64

基本上,這用頻次替換了subreddit類別。我們也可以除以最頻繁出現(xiàn)的類別的頻次,以得到歸一化的值:

1.000000221941

0.44260998233

0.15120733559

0.14422832010

0.11519725567

Name:subreddit_count_encoded_normalized,dtype:int64

LabelCount編碼

我們下面將描述的方法稱為L(zhǎng)abelCount編碼,它根據(jù)類別在訓(xùn)練集中的頻次排序類別(升序或降序)。相比標(biāo)準(zhǔn)的頻次編碼,LabelCount具有特定的優(yōu)勢(shì)——對(duì)離群值不敏感,也不會(huì)對(duì)不同的值給出同樣的編碼。

deflabelcount_encode(X,categorical_features,ascending=False):

print('LabelCountencoding:{}'.format(categorical_features))

X_=pd.DataFrame()

forcat_featureincategorical_features:

cat_feature_value_counts=X[cat_feature].value_counts()

value_counts_list=cat_feature_value_counts.index.tolist()

ifascending:

#升序

value_counts_range=list(

reversed(range(len(cat_feature_value_counts))))

else:

#降序

value_counts_range=list(range(len(cat_feature_value_counts)))

labelcount_dict=dict(zip(value_counts_list,value_counts_range))

X_[cat_feature]=X[cat_feature].map(

labelcount_dict)

X_=X_.add_suffix('_labelcount_encoded')

ifascending:

X_=X_.add_suffix('_ascending')

else:

X_=X_.add_suffix('_descending')

X_=X_.astype(np.uint32)

returnX_

編碼:

train_lc_subreddit=labelcount_encode(X_train,['subreddit'])

這里默認(rèn)使用降序,subreddit列最流行的5個(gè)類別是:

0221941

198233

233559

332010

425567

Name:subreddit_labelcount_encoded_descending,dtype:int64

AskReddit是最頻繁的類別,因此被轉(zhuǎn)換為0,也就是第一位。

使用升序的話,同樣這5個(gè)類別編碼如下:

40221941

3998233

3833559

3732010

3625567

Name:subreddit_labelcount_encoded_ascending,dtype:int64

目標(biāo)編碼

最后是最有技巧性的方法——目標(biāo)編碼。它使用目標(biāo)變量的均值編碼類別變量。我們?yōu)橛?xùn)練集中的每個(gè)分組計(jì)算目標(biāo)變量的統(tǒng)計(jì)量(這里是均值),之后會(huì)合并驗(yàn)證集、測(cè)試集以捕捉分組和目標(biāo)之間的關(guān)系。

舉一個(gè)更明確的例子,我們可以在每個(gè)subreddit上計(jì)算answer_score的均值,這樣,在特定subreddit發(fā)帖可以期望得到多少贊,我們可以有個(gè)大概的估計(jì)。

使用目標(biāo)變量時(shí),非常重要的一點(diǎn)是不要泄露任何驗(yàn)證集的信息。所有基于目標(biāo)編碼的特征都應(yīng)該在訓(xùn)練集上計(jì)算,接著僅僅合并或連接驗(yàn)證集和測(cè)試集。即使驗(yàn)證集中有目標(biāo)變量,它不能用于任何編碼計(jì)算,否則會(huì)給出過于樂觀的驗(yàn)證誤差估計(jì)。

如果使用K折交叉驗(yàn)證,基于目標(biāo)的特征應(yīng)該在折內(nèi)計(jì)算。如果僅僅進(jìn)行單次分割,那么目標(biāo)編碼應(yīng)該在分開訓(xùn)練集和驗(yàn)證集之后進(jìn)行。

此外,我們可以通過平滑避免將特定類別編碼為0.另一種方法是通過增加隨機(jī)噪聲避免可能的過擬合。

處置妥當(dāng)?shù)那闆r下,無論是線性模型,還是非線性模型,目標(biāo)編碼都是最佳的編碼方式。

deftarget_encode(X,X_valid,categorical_features,X_test=None,

target_feature='target'):

print('TargetEncoding:{}'.format(categorical_features))

X_=pd.DataFrame()

X_valid_=pd.DataFrame()

ifX_testisnotNone:

X_test_=pd.DataFrame()

forcat_featureincategorical_features:

group_target_mean=X.groupby([cat_feature])[target_feature].mean()

X_[cat_feature]=X[cat_feature].map(group_target_mean)

X_valid_[cat_feature]=X_valid[cat_feature].map(group_target_mean)

X_=X_.astype(np.float32)

X_=X_.add_suffix('_target_encoded')

X_valid_=X_valid_.astype(np.float32)

X_valid_=X_valid_.add_suffix('_target_encoded')

ifX_testisnotNone:

X_test_[cat_feature]=X_test[cat_feature].map(group_target_mean)

X_test_=X_test_.astype(np.float32)

X_test_=X_test_.add_suffix('_target_encoded')

returnX_,X_valid_,X_test_

returnX_,X_valid_

編碼:

train_tm_subreddit,valid_tm_subreddit=target_encode(

X_train,X_valid,categorical_features=['subreddit'],

target_feature='answer_score')

如果我們查看下編碼后的值,就會(huì)發(fā)現(xiàn)不同reddit的平均贊數(shù)有明顯的差別:

23.406061220014

13.08269998176

19.02084533916

17.52188731869

18.23542425520

21.53547724692

18.64028220416

23.68889020009

3.15940118695

Name:subreddit_target_encoded,dtype:int64

AskReddit220014

politics98176

news33916

worldnews31869

gaming25520

todayilearned24692

funny20416

videos20009

teenagers18695

Name:subreddit,dtype:int64

AskReddit中的回答平均能有23.4個(gè)贊,而politics和teenagers中的回答分別只有13.1個(gè)贊。這樣的特征可能非常強(qiáng)大,因?yàn)樗屛覀兛梢栽谔卣骷忻鞔_編碼一些目標(biāo)信息。

獲取類別的編碼值

無需修改編碼函數(shù),我們可以通過如下方式在驗(yàn)證集或測(cè)試集上合并取得的值:

encoded=train_lc_subreddit.subreddit_labelcount_encoded_descending.value_counts().index.values

raw=X_train.subreddit.value_counts().index.values

encoding_dict=dict(zip(raw,encoded))

X_valid['subreddit_labelcount_encoded_descending']=X_valid.loc[:,

'subreddit'].map(

encoding_dict)

標(biāo)簽:

點(diǎn)贊

分享到:

上一篇:探討系統(tǒng)架構(gòu)選擇對(duì)電源和控...

下一篇:淺析射頻放大器的3大分類

中國(guó)傳動(dòng)網(wǎng)版權(quán)與免責(zé)聲明:凡本網(wǎng)注明[來源:中國(guó)傳動(dòng)網(wǎng)]的所有文字、圖片、音視和視頻文件,版權(quán)均為中國(guó)傳動(dòng)網(wǎng)(m.u63ivq3.com)獨(dú)家所有。如需轉(zhuǎn)載請(qǐng)與0755-82949061聯(lián)系。任何媒體、網(wǎng)站或個(gè)人轉(zhuǎn)載使用時(shí)須注明來源“中國(guó)傳動(dòng)網(wǎng)”,違反者本網(wǎng)將追究其法律責(zé)任。

本網(wǎng)轉(zhuǎn)載并注明其他來源的稿件,均來自互聯(lián)網(wǎng)或業(yè)內(nèi)投稿人士,版權(quán)屬于原版權(quán)人。轉(zhuǎn)載請(qǐng)保留稿件來源及作者,禁止擅自篡改,違者自負(fù)版權(quán)法律責(zé)任。

網(wǎng)站簡(jiǎn)介|會(huì)員服務(wù)|聯(lián)系方式|幫助信息|版權(quán)信息|網(wǎng)站地圖|友情鏈接|法律支持|意見反饋|sitemap

傳動(dòng)網(wǎng)-工業(yè)自動(dòng)化與智能制造的全媒體“互聯(lián)網(wǎng)+”創(chuàng)新服務(wù)平臺(tái)

網(wǎng)站客服服務(wù)咨詢采購(gòu)咨詢媒體合作

Chuandong.com Copyright ?2005 - 2024 ,All Rights Reserved 深圳市奧美大唐廣告有限公司 版權(quán)所有
粵ICP備 14004826號(hào) | 營(yíng)業(yè)執(zhí)照證書 | 不良信息舉報(bào)中心 | 粵公網(wǎng)安備 44030402000946號(hào)