時(shí)間:2018-11-22 10:43:22來源:網(wǎng)絡(luò)轉(zhuǎ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)簽:
中國(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é)任。
產(chǎn)品新聞
更多>新品發(fā)布:CD300系列總線型伺服驅(qū)動(dòng)器
2024-10-31
2024-10-31
2024-10-31
新勢(shì)能 新期待|維智B1L直線伺服驅(qū)動(dòng)器
2024-10-31
纖薄之間,化繁為簡(jiǎn)|合信全新simple系...
2024-10-29
2024-10-18
推薦專題
更多>