【数据竞赛】Kaggle实战之单类别变量特征工程总结!
作者:塵沙杰少、櫻落、新峰、DOTA、謝嘉嘉
特征工程--類別變量完結(jié)篇!
前 言
這是一個系列篇,后續(xù)我們會按照我們第一章中的框架進(jìn)行更新,因為大家平時都較忙,不會定期更新,如有興趣歡迎長期關(guān)注我們的公眾號,如有任何建議可以在評論區(qū)留言,該系列以往的經(jīng)典內(nèi)容可參考下面的篇章。
1. kaggle競賽寶典-競賽框架篇!
2.1?賽題理解,分析,規(guī)劃之賽題理解與分析!
2.2??kaggle競賽寶典-回歸相關(guān)指標(biāo)優(yōu)化!
2.3??kaggle競賽寶典-二分類相關(guān)指標(biāo)優(yōu)化!
2.4??kaggle競賽寶典-多分類相關(guān)指標(biāo)優(yōu)化!
2.5?數(shù)據(jù)競賽規(guī)劃!
3.1?數(shù)據(jù)探索分析-全局?jǐn)?shù)據(jù)探索分析!
3.2?數(shù)據(jù)探索分析-單變量數(shù)據(jù)分析!
3.3 數(shù)據(jù)探索分析-交叉變量分析篇!
3.4?訓(xùn)練集測試集分布不一致性探索!
4.1?kaggle競賽寶典-樣本篩選篇!
4.2?kaggle競賽寶典-樣本組織篇!
5. 驗證策略設(shè)計!
6.1. 模型理解、選擇--GBDT!
6.2.模型理解、選擇--XGBoost!
6.3.模型理解、選擇--LightGBM!
6.4.模型理解、選擇--CatBoost!
7.1 特征工程--為什么要做特征工程!
前言
在之前的文章中,我們已經(jīng)介紹過部分類別特征編碼的內(nèi)容,此處,我們將所有的內(nèi)容進(jìn)行整合為一個系列,我們不羅列過多的知識點,重點介紹在kaggle過往幾年內(nèi)中大家最為常用有效的類別編碼技巧,如果對其它類型編碼感興趣的朋友可以學(xué)習(xí)擴展部分的內(nèi)容。
類別特征編碼
在很多表格類的問題中,高基數(shù)的特征類別處理一直是一個困擾著很多人的問題,究竟哪一種操作是最好的,很難說,不同的數(shù)據(jù)集有不同的特性,可能某一種數(shù)據(jù)轉(zhuǎn)化操作這A數(shù)據(jù)集上取得了提升,但在B數(shù)據(jù)集上就不行了,但是知道的技巧越多,我們能取得提升的概率往往也會越大。此處我們會介紹幾種常見的處理類別特征的方法。
1. Label編碼
無序的類別變量,在很多時候是以字符串形式的出現(xiàn)的,例如:
- 顏色:紅色,綠色,黑色... 
- 形狀:三角形,正方形,圓形... 
而我們知道,梯度提升樹模型是無法對此類特征進(jìn)行處理的。直接將其輸入到模型就會報錯。而這個時候最為常見的就是使用LabelEncoder對其進(jìn)行編碼。LabelEncoder可以將類型為object的變量轉(zhuǎn)變?yōu)閿?shù)值形式,具體的例子如下:
LabelEncoder默認(rèn)會先將object類型的變量進(jìn)行排序,然后按照大小順序進(jìn)行的編碼,此處N為該特征中不同變量的個數(shù)。幾乎所有的賽題中都會這么做,這樣做我們就可以將轉(zhuǎn)化后的特征輸入到模型,雖然這并不是模型最喜歡的形式,但是至少也可以吸收10%左右的信息,會總直接丟棄該變量的信息好很多。
對應(yīng)代碼:
from?sklearn?import?preprocessing df?=?pd.DataFrame({'color':['red','blue','black','green']}) le?=?preprocessing.LabelEncoder() le.fit(df['color'].values) df['color_labelencode']?=?le.transform(df['color'].values)? df| red | 3 | 
| blue | 1 | 
| black | 0 | 
| green | 2 | 
2. One-Hot編碼
One-Hot編碼對于一個類別特征變量,我們對每個類別,使用二進(jìn)制編碼(0或1)創(chuàng)建一個新列(有時稱為dummy變量),以表示特定行是否屬于該類別。One-Hot編碼可以將一個基數(shù)為的類別變量轉(zhuǎn)變?yōu)閭€二元向量,我們以上面的顏色為案例,進(jìn)行one-hot編碼之后就得到:
我們發(fā)現(xiàn)One-Hot編碼將我們的數(shù)據(jù)展開之后內(nèi)存的消耗變得非常大,因為使用One-Hot編碼時需要創(chuàng)建額外的列,為我們需要編碼的特征列中的每個每個唯一值創(chuàng)建一個列。也就是說,如果我們有一個包含10000個不同值的類別特征,那么在One-Hot編碼之后將會生成10000個額外的新的列,這是不可以接受的。
但它的好處也非常明顯,One-Hot編碼之后,我們的線性模型可以更好的吸收High-Cadinality的類別信息,原先我們的采用線性模型,那么我們類別變量A的對預(yù)測帶來的貢獻(xiàn)為,, (A由(組成)我們發(fā)現(xiàn)類別2的貢獻(xiàn)就是類別1的一倍,這很明顯和我們的直覺不符,但是展開之后,我們類別變量A對預(yù)測帶來的貢獻(xiàn)為:。變量之間的關(guān)系變得更加合理了。所以O(shè)ne-Hot編碼對于很多線性模型是有必要的。
那么對于XGBoost,LightGBM之類的樹模型是否有必要呢?答案是有的!在我們的實踐中,很多時候?qū)Ω呋鶖?shù)的類別特征直接進(jìn)行One-Hot編碼的效果往往可能不如直接LabelEncoder來的好。但是當(dāng)我們的類別變量中有一些變量是人為構(gòu)造的,加入了很多噪音,這個時候?qū)⑵湔归_,那么模型可以更加快的找到那些非構(gòu)建的類別。(參考訊飛18年舉辦的推薦比賽),取得更好的效果。
對應(yīng)代碼:
from?sklearn?import?preprocessing df?=?pd.DataFrame({'color':['red','blue','black','green']}) pd.get_dummies(df['color'].values)?| 0 | 0 | 0 | 1 | 
| 0 | 1 | 0 | 0 | 
| 1 | 0 | 0 | 0 | 
| 0 | 0 | 1 | 0 | 
3. Frequency編碼
Frequency編碼是數(shù)據(jù)競賽中使用最為廣泛的技術(shù),在90%以上的數(shù)據(jù)建模的問題中都可以帶來提升。因為在很多的時候,頻率的信息與我們的目標(biāo)變量往往存在有一定關(guān)聯(lián),例如:
- 在音樂推薦問題中,對于樂曲進(jìn)行Frequency編碼可以反映該樂曲的熱度,而熱度高的樂曲往往更受大家的歡迎; 
- 在購物推薦問題中,對于商品進(jìn)行Frequency編碼可以反映該商品的熱度,而熱度高的商品大家也更樂于購買; 
- 微軟設(shè)備被攻擊概率問題中,預(yù)測設(shè)備受攻擊的概率,那么設(shè)備安裝的軟件是非常重要的信息,此時安裝軟件的count編碼可以反映該軟件的流行度,越流行的產(chǎn)品的受眾越多,那么黑客往往會傾向?qū)Υ祟惍a(chǎn)品進(jìn)行攻擊,這樣黑客往往可以獲得更多的利益 
Frequency編碼通過計算特征變量中每個值的出現(xiàn)次數(shù)來表示該特征的信息,詳細(xì)的案例如下所示:
在很多實踐問題中,Count編碼往往可以給模型的效果帶來不錯的幫助。
對應(yīng)代碼:
from?sklearn?import?preprocessing df?=?pd.DataFrame({'color':['red','red','red','blue','blue','black','green','green','green']}) df['color_cnt']?=?df['color'].map(df['color'].value_counts()) df| red | 3 | 
| red | 3 | 
| red | 3 | 
| blue | 2 | 
| blue | 2 | 
| black | 1 | 
| green | 3 | 
| green | 3 | 
| green | 3 | 
4. target編碼
target編碼是06年提出的一種結(jié)合標(biāo)簽進(jìn)行編碼的技術(shù),它將類別特征替換為從標(biāo)簽衍生而來的特征,在類別特征為高基數(shù)的時候非常有效。該技術(shù)在非常多的數(shù)據(jù)競賽中都取得了非常好的效果,但特別需要注意過擬合的問題。在kaggle競賽中成功的案例有owen zhang的leave-one-out的操作和莫斯科GM的基于K-fold的mean-target編碼,此處我們介紹兩種Mean-target編碼;
4.1. Leave-one-out mean-target 編碼
Leave-one-out mean-target編碼的思路相對簡單,我們每次編碼時,不考慮當(dāng)前樣本的情況,用其它樣本對應(yīng)的標(biāo)簽的均值作為我們的編碼,而測試集則用全部訓(xùn)練集樣本的均值進(jìn)行編碼,案例如下:
的案例摘自owen-zhang(曾經(jīng)的kaggle第一名)的分享。
對應(yīng)代碼:
from?sklearn?import?preprocessing from?pandas?import?pandas from?category_encoders.leave_one_out?import?LeaveOneOutEncoder df_tr?=?pd.DataFrame({'color':['red','red','red','red','red','red','black','black'],?'label':[1,0,1,1,0,1,1,0]})? df_te?=?pd.DataFrame({'color':['red','red','black']?})? loo?=?LeaveOneOutEncoder() loo.fit_transform(df_tr['color'],?df_tr['label'])| 0.6 | 
| 0.8 | 
| 0.6 | 
| 0.6 | 
| 0.8 | 
| 0.6 | 
| 0.0 | 
| 1.0 | 
| 0.666667 | 
| 0.666667 | 
| 0.500000 | 
4.2. K-fold mean-target 編碼
K-fold mean-target編碼的基本思想來源于Mean target編碼。K-fold mean-target編碼的訓(xùn)練步驟如下,我們先將訓(xùn)練集劃分為K折;
- 在對第A折的樣本進(jìn)行編碼時,我們刪除K折中A折,并用剩余的數(shù)據(jù)計算如下公式: 
- 后利用上面計算得到的值對第A折進(jìn)行編碼; 
- 依次對所有折進(jìn)行編碼即可。 
首先我們先理解一下上面的公式,最原始的Mean-target編碼是非常容易導(dǎo)致過擬合的,這其中過擬合的最大的原因之一在于對于一些特征列中出現(xiàn)次數(shù)很少的值過擬合了,比如某些值只有1個或者2到3個,但是這些樣本對應(yīng)的標(biāo)簽全部是1,怎么辦,他們的編碼值就應(yīng)該是1,但是很明顯這些值的統(tǒng)計意義不大,大家可以通過伯努利分布去計算概率來理解。而如果我們直接給他們編碼了,就會誤導(dǎo)模型的學(xué)習(xí)。那么我們該怎么辦呢?
- 加正則! 
于是我們就有了上面的計算式子,式子是值出現(xiàn)的次數(shù),是它對應(yīng)的概率,是全局的均值, 那么當(dāng)為0同時比較小的時候, 就會有大概率出現(xiàn)過擬合的現(xiàn)象,此時我們調(diào)大就可以緩解這一點,所以很多時候都需要不斷地去調(diào)整的值。
from?category_encoders.target_encoder?import?TargetEncoder? from?sklearn?import?base from?sklearn.model_selection?import?KFolddf?=?pd.DataFrame({'Feature':['A','B','B','B','B',?'A','B','A','A','B','A','A','B','A','A','B','B','B','A','A'],\'Target':[1,0,0,1,1,?1,0,0,0,0,1,?0,1,?0,1,0,0,0,1,1]})class?KFoldTargetEncoderTrain(base.BaseEstimator,?base.TransformerMixin):def?__init__(self,?colnames,targetName,n_fold=5,verbosity=True,discardOriginal_col=False):self.colnames???=?colnamesself.targetName?=?targetNameself.n_fold?????=?n_foldself.verbosity??=?verbosityself.discardOriginal_col?=?discardOriginal_coldef?fit(self,?X,?y=None):return?selfdef?transform(self,X):assert(type(self.targetName)?==?str)assert(type(self.colnames)?==?str)assert(self.colnames?in?X.columns)assert(self.targetName?in?X.columns)mean_of_target?=?X[self.targetName].mean()kf?=?KFold(n_splits?=?self.n_fold,?shuffle?=?False,?random_state=2019)col_mean_name?=?self.colnames?+?'_'?+?'Kfold_Target_Enc'X[col_mean_name]?=?np.nanfor?tr_ind,?val_ind?in?kf.split(X):X_tr,?X_val?=?X.iloc[tr_ind],?X.iloc[val_ind]?X.loc[X.index[val_ind],?col_mean_name]?=?X_val[self.colnames].map(X_tr.groupby(self.colnames)[self.targetName].mean())X[col_mean_name].fillna(mean_of_target,?inplace?=?True)if?self.verbosity:encoded_feature?=?X[col_mean_name].valuesprint('Correlation?between?the?new?feature,?{}?and,?{}?is?{}.'.format(col_mean_name,self.targetName,np.corrcoef(X[self.targetName].values,?encoded_feature)[0][1]))if?self.discardOriginal_col:X?=?X.drop(self.targetName,?axis=1)return?Xclass?KFoldTargetEncoderTest(base.BaseEstimator,?base.TransformerMixin):def?__init__(self,train,colNames,encodedName):self.train?=?trainself.colNames?=?colNamesself.encodedName?=?encodedNamedef?fit(self,?X,?y=None):return?selfdef?transform(self,X):mean?=?self.train[[self.colNames,self.encodedName]].groupby(self.colNames).mean().reset_index()?dd?=?{}for?index,?row?in?mean.iterrows():dd[row[self.colNames]]?=?row[self.encodedName]X[self.encodedName]?=?X[self.colNames]X?=?X.replace({self.encodedName:?dd})return?X '''?訓(xùn)練集編碼 ''' targetc???=?KFoldTargetEncoderTrain('Feature','Target',n_fold=5) new_train?=?targetc.fit_transform(df) new_train Correlation between the new feature, Feature_Kfold_Target_Enc and, Target is 0.11082358287080162.| A | 1 | 0.555556 | 
| B | 0 | 0.285714 | 
| B | 0 | 0.285714 | 
| B | 1 | 0.285714 | 
| B | 1 | 0.250000 | 
| A | 1 | 0.625000 | 
| B | 0 | 0.250000 | 
| A | 0 | 0.625000 | 
| A | 0 | 0.714286 | 
| B | 0 | 0.333333 | 
| A | 1 | 0.714286 | 
| A | 0 | 0.714286 | 
| B | 1 | 0.250000 | 
| A | 0 | 0.625000 | 
| A | 1 | 0.625000 | 
| B | 0 | 0.250000 | 
| B | 0 | 0.375000 | 
| B | 0 | 0.375000 | 
| A | 1 | 0.500000 | 
| A | 1 | 0.500000 | 
4.3. Beta Target編碼
Beta Target編碼來源于kaggle之前的競賽Avito Demand Prediction Challenge第14名方案。該編碼和傳統(tǒng)Target Encoding不一樣,
- Beta Target Encoding可以提取更多的特征,不僅僅是均值,還可以是方差等等; 
- 在開源中,是沒有進(jìn)行N Fold提取特征的,所以可能在時間上提取會更快一些; 
Beta Target編碼利用Beta分布作為共軛先驗,對二元目標(biāo)變量進(jìn)行建模。Beta分布用和來參數(shù)化,和可以被當(dāng)作是重復(fù)Binomial實驗中的正例數(shù)和負(fù)例數(shù)。分布中許多有用的統(tǒng)計數(shù)據(jù)可以用和表示,例如,
平均值:
方差:
等等。
從實驗對比上我們發(fā)現(xiàn),使用Beta Target Encoding可以得到大幅提升。因為Beta Target Encoding屬于類別編碼的一種,所以適用于高基數(shù)類別特征的問題。
對應(yīng)代碼:
import?numpy?as?np? import?pandas?as?pd from?sklearn.preprocessing?import?LabelEncoder'''代碼摘自原作者:https://www.kaggle.com/mmotoki/beta-target-encoding ''' class?BetaEncoder(object):def?__init__(self,?group):self.group?=?groupself.stats?=?None#?get?counts?from?dfdef?fit(self,?df,?target_col):#?先驗均值self.prior_mean?=?np.mean(df[target_col])?stats???????????=?df[[target_col,?self.group]].groupby(self.group)#?count和sumstats???????????=?stats.agg(['sum',?'count'])[target_col]????stats.rename(columns={'sum':?'n',?'count':?'N'},?inplace=True)stats.reset_index(level=0,?inplace=True)???????????self.stats??????=?stats#?extract?posterior?statisticsdef?transform(self,?df,?stat_type,?N_min=1):df_stats?=?pd.merge(df[[self.group]],?self.stats,?how='left')n????????=?df_stats['n'].copy()N????????=?df_stats['N'].copy()#?fill?in?missingnan_indexs????=?np.isnan(n)n[nan_indexs]?=?self.prior_meanN[nan_indexs]?=?1.0#?prior?parametersN_prior?????=?np.maximum(N_min-N,?0)alpha_prior?=?self.prior_mean*N_priorbeta_prior??=?(1-self.prior_mean)*N_prior#?posterior?parametersalpha???????=??alpha_prior?+?nbeta????????=??beta_prior??+?N-n#?calculate?statisticsif?stat_type=='mean':num?=?alphadem?=?alpha+betaelif?stat_type=='mode':num?=?alpha-1dem?=?alpha+beta-2elif?stat_type=='median':num?=?alpha-1/3dem?=?alpha+beta-2/3elif?stat_type=='var':num?=?alpha*betadem?=?(alpha+beta)**2*(alpha+beta+1)elif?stat_type=='skewness':num?=?2*(beta-alpha)*np.sqrt(alpha+beta+1)dem?=?(alpha+beta+2)*np.sqrt(alpha*beta)elif?stat_type=='kurtosis':num?=?6*(alpha-beta)**2*(alpha+beta+1)?-?alpha*beta*(alpha+beta+2)dem?=?alpha*beta*(alpha+beta+2)*(alpha+beta+3)#?replace?missingvalue?=?num/demvalue[np.isnan(value)]?=?np.nanmedian(value)return?value N_min?=?1000 feature_cols?=?[]????#?encode?variables for?c?in?cat_cols:#?fit?encoderbe?=?BetaEncoder(c)be.fit(train,?'deal_probability')#?meanfeature_name?=?f'{c}_mean'train[feature_name]?=?be.transform(train,?'mean',?N_min)test[feature_name]??=?be.transform(test,??'mean',?N_min)feature_cols.append(feature_name)#?modefeature_name?=?f'{c}_mode'train[feature_name]?=?be.transform(train,?'mode',?N_min)test[feature_name]??=?be.transform(test,??'mode',?N_min)feature_cols.append(feature_name)#?medianfeature_name?=?f'{c}_median'train[feature_name]?=?be.transform(train,?'median',?N_min)test[feature_name]??=?be.transform(test,??'median',?N_min)feature_cols.append(feature_name)????#?varfeature_name?=?f'{c}_var'train[feature_name]?=?be.transform(train,?'var',?N_min)test[feature_name]??=?be.transform(test,??'var',?N_min)feature_cols.append(feature_name)????????#?skewnessfeature_name?=?f'{c}_skewness'train[feature_name]?=?be.transform(train,?'skewness',?N_min)test[feature_name]??=?be.transform(test,??'skewness',?N_min)feature_cols.append(feature_name)????#?kurtosisfeature_name?=?f'{c}_kurtosis'train[feature_name]?=?be.transform(train,?'kurtosis',?N_min)test[feature_name]??=?be.transform(test,??'kurtosis',?N_min)feature_cols.append(feature_name)??5. Weight of evidence
Weight of evidence(WoE)是變量轉(zhuǎn)化的利器,經(jīng)常會出現(xiàn)在信用卡評分等問題中,用來判斷好的和壞的客戶。WOE不僅簡單,而且可以依據(jù)其大小來篩選出重要的分組(group),可解釋性較強,早期WOE和邏輯回歸算法經(jīng)常一起使用并且可以幫助獲得較大的提升,在Kaggle的數(shù)據(jù)競賽中,我們發(fā)現(xiàn)WOE和梯度提升樹模型結(jié)合也可以取得不錯的效果。
- 此處的Event和Non Event為別是標(biāo)簽為1的樣本的分布以及標(biāo)簽為0的樣本的分布; 
- 標(biāo)簽為1的樣本分布:在某個類內(nèi)正樣本占所有正樣本的比例;標(biāo)簽為0的樣本分布也是類似的。 
從上面的公式中,我們知道,正樣本的分布和負(fù)樣本的分布如果在某個類中差別越大的話,涵蓋的信息就越大,如果WOE的值越大,擇該這個類內(nèi)的為正的概率極大,反之越小。
在實踐中,我們可以直接通過下面的步驟計算得到WOE的結(jié)果:
- 對于一個連續(xù)變量可以將數(shù)據(jù)先進(jìn)行分箱,對于類別變量(無需做任何操作); 
- 計算每個類內(nèi)(group)中正樣本和負(fù)樣本出現(xiàn)的次數(shù); 
- 計算每個類內(nèi)(group)正樣本和負(fù)樣本的百分比events%以及non events %; 
- 按照公式計算WOE; 
對應(yīng)代碼:
'''代碼摘自:https://github.com/Sundar0989/WOE-and-IV ''' import?os import?pandas?as?pd import?numpy?as?npdf?=?pd.read_csv('./data/bank.csv',sep=';') dic?=?{'yes':1,?'no':0} df['target']?=?df['y'].map(dic) df?=?df.drop('y',axis=1)?import?pandas.core.algorithms?as?algos from?pandas?import?Series import?scipy.stats.stats?as?stats import?re import?traceback import?stringmax_bin?=?20 force_bin?=?3#?define?a?binning?function def?mono_bin(Y,?X,?n?=?max_bin):df1??????=?pd.DataFrame({"X":?X,?"Y":?Y})justmiss?=?df1[['X','Y']][df1.X.isnull()]notmiss??=?df1[['X','Y']][df1.X.notnull()]r????????=?0while?np.abs(r)?<?1:try:d1?=?pd.DataFrame({"X":?notmiss.X,?"Y":?notmiss.Y,?"Bucket":?pd.qcut(notmiss.X,?n)})d2?=?d1.groupby('Bucket',?as_index=True)r,?p?=?stats.spearmanr(d2.mean().X,?d2.mean().Y)n?=?n?-?1?except?Exception?as?e:n?=?n?-?1if?len(d2)?==?1:n????=?force_bin?????????bins?=?algos.quantile(notmiss.X,?np.linspace(0,?1,?n))if?len(np.unique(bins))?==?2:bins?=?np.insert(bins,?0,?1)bins[1]?=?bins[1]-(bins[1]/2)d1?=?pd.DataFrame({"X":?notmiss.X,?"Y":?notmiss.Y,?"Bucket":?pd.cut(notmiss.X,?np.unique(bins),include_lowest=True)})?d2?=?d1.groupby('Bucket',?as_index=True)d3?=?pd.DataFrame({},index=[])d3["MIN_VALUE"]?=?d2.min().Xd3["MAX_VALUE"]?=?d2.max().Xd3["COUNT"]?????=?d2.count().Yd3["EVENT"]?????=?d2.sum().Y??#?正樣本d3["NONEVENT"]??=?d2.count().Y?-?d2.sum().Y?#?負(fù)樣本d3??????????????=?d3.reset_index(drop=True)if?len(justmiss.index)?>?0:d4?=?pd.DataFrame({'MIN_VALUE':np.nan},index=[0])d4["MAX_VALUE"]?=?np.nand4["COUNT"]?=?justmiss.count().Yd4["EVENT"]?=?justmiss.sum().Yd4["NONEVENT"]?=?justmiss.count().Y?-?justmiss.sum().Yd3?=?d3.append(d4,ignore_index=True)d3["EVENT_RATE"]?????=?d3.EVENT/d3.COUNT???????#?正樣本類內(nèi)百分比d3["NON_EVENT_RATE"]?=?d3.NONEVENT/d3.COUNT????#?負(fù)樣本類內(nèi)百分比d3["DIST_EVENT"]?????=?d3.EVENT/d3.sum().EVENT?#?正的樣本占所有正樣本百分比d3["DIST_NON_EVENT"]?=?d3.NONEVENT/d3.sum().NONEVENT?#?負(fù)的樣本占所有負(fù)樣本百分比d3["WOE"]?=?np.log(d3.DIST_EVENT/d3.DIST_NON_EVENT)d3["IV"]?=?(d3.DIST_EVENT-d3.DIST_NON_EVENT)*np.log(d3.DIST_EVENT/d3.DIST_NON_EVENT)d3["VAR_NAME"]?=?"VAR"d3?=?d3[['VAR_NAME','MIN_VALUE',?'MAX_VALUE',?'COUNT',?'EVENT',?'EVENT_RATE',?'NONEVENT',?'NON_EVENT_RATE',?'DIST_EVENT','DIST_NON_EVENT','WOE',?'IV']]???????d3?=?d3.replace([np.inf,?-np.inf],?0)d3.IV?=?d3.IV.sum()return(d3)def?char_bin(Y,?X):df1?=?pd.DataFrame({"X":?X,?"Y":?Y})justmiss?=?df1[['X','Y']][df1.X.isnull()]notmiss?=?df1[['X','Y']][df1.X.notnull()]????df2?=?notmiss.groupby('X',as_index=True)d3?=?pd.DataFrame({},index=[])d3["COUNT"]?=?df2.count().Yd3["MIN_VALUE"]?=?df2.sum().Y.indexd3["MAX_VALUE"]?=?d3["MIN_VALUE"]d3["EVENT"]?=?df2.sum().Yd3["NONEVENT"]?=?df2.count().Y?-?df2.sum().Yif?len(justmiss.index)?>?0:d4?=?pd.DataFrame({'MIN_VALUE':np.nan},index=[0])d4["MAX_VALUE"]?=?np.nand4["COUNT"]?=?justmiss.count().Yd4["EVENT"]?=?justmiss.sum().Yd4["NONEVENT"]?=?justmiss.count().Y?-?justmiss.sum().Yd3?=?d3.append(d4,ignore_index=True)d3["EVENT_RATE"]?=?d3.EVENT/d3.COUNTd3["NON_EVENT_RATE"]?=?d3.NONEVENT/d3.COUNTd3["DIST_EVENT"]?=?d3.EVENT/d3.sum().EVENTd3["DIST_NON_EVENT"]?=?d3.NONEVENT/d3.sum().NONEVENTd3["WOE"]?=?np.log(d3.DIST_EVENT/d3.DIST_NON_EVENT)d3["IV"]?=?(d3.DIST_EVENT-d3.DIST_NON_EVENT)*np.log(d3.DIST_EVENT/d3.DIST_NON_EVENT)d3["VAR_NAME"]?=?"VAR"d3?=?d3[['VAR_NAME','MIN_VALUE',?'MAX_VALUE',?'COUNT',?'EVENT',?'EVENT_RATE',?'NONEVENT',?'NON_EVENT_RATE',?'DIST_EVENT','DIST_NON_EVENT','WOE',?'IV']]??????d3?=?d3.replace([np.inf,?-np.inf],?0)d3.IV?=?d3.IV.sum()d3?=?d3.reset_index(drop=True)return(d3)?def?data_vars(df1,?target):stack?=?traceback.extract_stack()filename,?lineno,?function_name,?code?=?stack[-2]vars_name?=?re.compile(r'\((.*?)\).*$').search(code).groups()[0]final?=?(re.findall(r"[\w']+",?vars_name))[-1]x?=?df1.dtypes.indexcount?=?-1for?i?in?x:if?i.upper()?not?in?(final.upper()):if?np.issubdtype(df1[i],?np.number)?and?len(Series.unique(df1[i]))?>?2:conv?=?mono_bin(target,?df1[i])conv["VAR_NAME"]?=?icount?=?count?+?1else:conv?=?char_bin(target,?df1[i])conv["VAR_NAME"]?=?i????????????count?=?count?+?1if?count?==?0:iv_df?=?convelse:iv_df?=?iv_df.append(conv,ignore_index=True)return?iv_df?final_iv?=?data_vars(df,df.target)6. 人工編碼
6.1 人工轉(zhuǎn)化編碼:
這個需要一些專業(yè)背景知識,可以認(rèn)為是Label編碼的一種補充,如果我們的類別特征是字符串類型的,例如:
- 城市編號:'10','100','90','888'... 
這個時候,我們使用Labelencoder會依據(jù)字符串排序編碼。在字符串中'90' > '100',但我們直觀感覺是為'100' > '90',所以需要人為但進(jìn)行干預(yù)編碼,如果都是可以直接轉(zhuǎn)化為數(shù)值形的,編碼時可以直接轉(zhuǎn)化為數(shù)值,或者自己書寫一個字典進(jìn)行映射。
6.2 人工組合編碼:
這個同樣的也設(shè)計到部分專業(yè)背景知識,有些問題會出現(xiàn)一些臟亂的數(shù)據(jù),例如:
- 在一些位置字段中,有的是中文的,有的是英文的,例如“ShangHai”,“上?!?#xff0c;二者描述的是同一個地方,但如果我們不注意就忽略了; 
這個時候,我們可以先采用字典映射等方式對其進(jìn)行轉(zhuǎn)化,然后再使用上面所屬的Frequency等編碼重新對其進(jìn)行處理。
7. 擴展
上面是數(shù)據(jù)競賽中最為常用的編碼特征,在基于梯度提升樹模型的建模中,上面的編碼往往可以帶來非常大的幫助,也都是非常值得嘗試的。當(dāng)然還有一些其它的類別特征的編碼形式,目前使用較多的一個庫就是category_encoders,有興趣的朋友可以當(dāng)作擴展進(jìn)行學(xué)習(xí),此處不再敘述。
往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載機器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機器學(xué)習(xí)在線手冊深度學(xué)習(xí)筆記專輯《統(tǒng)計學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載機器學(xué)習(xí)的數(shù)學(xué)基礎(chǔ)專輯溫州大學(xué)《機器學(xué)習(xí)課程》視頻 本站qq群851320808,加入微信群請掃碼:總結(jié)
以上是生活随笔為你收集整理的【数据竞赛】Kaggle实战之单类别变量特征工程总结!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 新萝卜家园windows11 64位官网
- 下一篇: 如何解决Win11系统蓝牙鼠标经常掉线
