【数据竞赛】Kaggle实战之单类别变量特征工程总结!
作者:塵沙杰少、櫻落、新峰、DOTA、謝嘉嘉
特征工程--類別變量完結篇!
前 言
這是一個系列篇,后續我們會按照我們第一章中的框架進行更新,因為大家平時都較忙,不會定期更新,如有興趣歡迎長期關注我們的公眾號,如有任何建議可以在評論區留言,該系列以往的經典內容可參考下面的篇章。
1. kaggle競賽寶典-競賽框架篇!
2.1?賽題理解,分析,規劃之賽題理解與分析!
2.2??kaggle競賽寶典-回歸相關指標優化!
2.3??kaggle競賽寶典-二分類相關指標優化!
2.4??kaggle競賽寶典-多分類相關指標優化!
2.5?數據競賽規劃!
3.1?數據探索分析-全局數據探索分析!
3.2?數據探索分析-單變量數據分析!
3.3 數據探索分析-交叉變量分析篇!
3.4?訓練集測試集分布不一致性探索!
4.1?kaggle競賽寶典-樣本篩選篇!
4.2?kaggle競賽寶典-樣本組織篇!
5. 驗證策略設計!
6.1. 模型理解、選擇--GBDT!
6.2.模型理解、選擇--XGBoost!
6.3.模型理解、選擇--LightGBM!
6.4.模型理解、選擇--CatBoost!
7.1 特征工程--為什么要做特征工程!
前言
在之前的文章中,我們已經介紹過部分類別特征編碼的內容,此處,我們將所有的內容進行整合為一個系列,我們不羅列過多的知識點,重點介紹在kaggle過往幾年內中大家最為常用有效的類別編碼技巧,如果對其它類型編碼感興趣的朋友可以學習擴展部分的內容。
類別特征編碼
在很多表格類的問題中,高基數的特征類別處理一直是一個困擾著很多人的問題,究竟哪一種操作是最好的,很難說,不同的數據集有不同的特性,可能某一種數據轉化操作這A數據集上取得了提升,但在B數據集上就不行了,但是知道的技巧越多,我們能取得提升的概率往往也會越大。此處我們會介紹幾種常見的處理類別特征的方法。
1. Label編碼
無序的類別變量,在很多時候是以字符串形式的出現的,例如:
顏色:紅色,綠色,黑色...
形狀:三角形,正方形,圓形...
而我們知道,梯度提升樹模型是無法對此類特征進行處理的。直接將其輸入到模型就會報錯。而這個時候最為常見的就是使用LabelEncoder對其進行編碼。LabelEncoder可以將類型為object的變量轉變為數值形式,具體的例子如下:
LabelEncoder默認會先將object類型的變量進行排序,然后按照大小順序進行的編碼,此處N為該特征中不同變量的個數。幾乎所有的賽題中都會這么做,這樣做我們就可以將轉化后的特征輸入到模型,雖然這并不是模型最喜歡的形式,但是至少也可以吸收10%左右的信息,會總直接丟棄該變量的信息好很多。
對應代碼:
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編碼對于一個類別特征變量,我們對每個類別,使用二進制編碼(0或1)創建一個新列(有時稱為dummy變量),以表示特定行是否屬于該類別。One-Hot編碼可以將一個基數為的類別變量轉變為個二元向量,我們以上面的顏色為案例,進行one-hot編碼之后就得到:
我們發現One-Hot編碼將我們的數據展開之后內存的消耗變得非常大,因為使用One-Hot編碼時需要創建額外的列,為我們需要編碼的特征列中的每個每個唯一值創建一個列。也就是說,如果我們有一個包含10000個不同值的類別特征,那么在One-Hot編碼之后將會生成10000個額外的新的列,這是不可以接受的。
但它的好處也非常明顯,One-Hot編碼之后,我們的線性模型可以更好的吸收High-Cadinality的類別信息,原先我們的采用線性模型,那么我們類別變量A的對預測帶來的貢獻為,, (A由(組成)我們發現類別2的貢獻就是類別1的一倍,這很明顯和我們的直覺不符,但是展開之后,我們類別變量A對預測帶來的貢獻為:。變量之間的關系變得更加合理了。所以One-Hot編碼對于很多線性模型是有必要的。
那么對于XGBoost,LightGBM之類的樹模型是否有必要呢?答案是有的!在我們的實踐中,很多時候對高基數的類別特征直接進行One-Hot編碼的效果往往可能不如直接LabelEncoder來的好。但是當我們的類別變量中有一些變量是人為構造的,加入了很多噪音,這個時候將其展開,那么模型可以更加快的找到那些非構建的類別。(參考訊飛18年舉辦的推薦比賽),取得更好的效果。
對應代碼:
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編碼是數據競賽中使用最為廣泛的技術,在90%以上的數據建模的問題中都可以帶來提升。因為在很多的時候,頻率的信息與我們的目標變量往往存在有一定關聯,例如:
在音樂推薦問題中,對于樂曲進行Frequency編碼可以反映該樂曲的熱度,而熱度高的樂曲往往更受大家的歡迎;
在購物推薦問題中,對于商品進行Frequency編碼可以反映該商品的熱度,而熱度高的商品大家也更樂于購買;
微軟設備被攻擊概率問題中,預測設備受攻擊的概率,那么設備安裝的軟件是非常重要的信息,此時安裝軟件的count編碼可以反映該軟件的流行度,越流行的產品的受眾越多,那么黑客往往會傾向對此類產品進行攻擊,這樣黑客往往可以獲得更多的利益
Frequency編碼通過計算特征變量中每個值的出現次數來表示該特征的信息,詳細的案例如下所示:
在很多實踐問題中,Count編碼往往可以給模型的效果帶來不錯的幫助。
對應代碼:
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年提出的一種結合標簽進行編碼的技術,它將類別特征替換為從標簽衍生而來的特征,在類別特征為高基數的時候非常有效。該技術在非常多的數據競賽中都取得了非常好的效果,但特別需要注意過擬合的問題。在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編碼的思路相對簡單,我們每次編碼時,不考慮當前樣本的情況,用其它樣本對應的標簽的均值作為我們的編碼,而測試集則用全部訓練集樣本的均值進行編碼,案例如下:
的案例摘自owen-zhang(曾經的kaggle第一名)的分享。
對應代碼:
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編碼的訓練步驟如下,我們先將訓練集劃分為K折;
在對第A折的樣本進行編碼時,我們刪除K折中A折,并用剩余的數據計算如下公式:
后利用上面計算得到的值對第A折進行編碼;
依次對所有折進行編碼即可。
首先我們先理解一下上面的公式,最原始的Mean-target編碼是非常容易導致過擬合的,這其中過擬合的最大的原因之一在于對于一些特征列中出現次數很少的值過擬合了,比如某些值只有1個或者2到3個,但是這些樣本對應的標簽全部是1,怎么辦,他們的編碼值就應該是1,但是很明顯這些值的統計意義不大,大家可以通過伯努利分布去計算概率來理解。而如果我們直接給他們編碼了,就會誤導模型的學習。那么我們該怎么辦呢?
加正則!
于是我們就有了上面的計算式子,式子是值出現的次數,是它對應的概率,是全局的均值, 那么當為0同時比較小的時候, 就會有大概率出現過擬合的現象,此時我們調大就可以緩解這一點,所以很多時候都需要不斷地去調整的值。
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 '''?訓練集編碼 ''' 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名方案。該編碼和傳統Target Encoding不一樣,
Beta Target Encoding可以提取更多的特征,不僅僅是均值,還可以是方差等等;
在開源中,是沒有進行N Fold提取特征的,所以可能在時間上提取會更快一些;
Beta Target編碼利用Beta分布作為共軛先驗,對二元目標變量進行建模。Beta分布用和來參數化,和可以被當作是重復Binomial實驗中的正例數和負例數。分布中許多有用的統計數據可以用和表示,例如,
平均值:
方差:
等等。
從實驗對比上我們發現,使用Beta Target Encoding可以得到大幅提升。因為Beta Target Encoding屬于類別編碼的一種,所以適用于高基數類別特征的問題。
對應代碼:
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)是變量轉化的利器,經常會出現在信用卡評分等問題中,用來判斷好的和壞的客戶。WOE不僅簡單,而且可以依據其大小來篩選出重要的分組(group),可解釋性較強,早期WOE和邏輯回歸算法經常一起使用并且可以幫助獲得較大的提升,在Kaggle的數據競賽中,我們發現WOE和梯度提升樹模型結合也可以取得不錯的效果。
此處的Event和Non Event為別是標簽為1的樣本的分布以及標簽為0的樣本的分布;
標簽為1的樣本分布:在某個類內正樣本占所有正樣本的比例;標簽為0的樣本分布也是類似的。
從上面的公式中,我們知道,正樣本的分布和負樣本的分布如果在某個類中差別越大的話,涵蓋的信息就越大,如果WOE的值越大,擇該這個類內的為正的概率極大,反之越小。
在實踐中,我們可以直接通過下面的步驟計算得到WOE的結果:
對于一個連續變量可以將數據先進行分箱,對于類別變量(無需做任何操作);
計算每個類內(group)中正樣本和負樣本出現的次數;
計算每個類內(group)正樣本和負樣本的百分比events%以及non events %;
按照公式計算WOE;
對應代碼:
'''代碼摘自: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?#?負樣本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???????#?正樣本類內百分比d3["NON_EVENT_RATE"]?=?d3.NONEVENT/d3.COUNT????#?負樣本類內百分比d3["DIST_EVENT"]?????=?d3.EVENT/d3.sum().EVENT?#?正的樣本占所有正樣本百分比d3["DIST_NON_EVENT"]?=?d3.NONEVENT/d3.sum().NONEVENT?#?負的樣本占所有負樣本百分比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 人工轉化編碼:
這個需要一些專業背景知識,可以認為是Label編碼的一種補充,如果我們的類別特征是字符串類型的,例如:
城市編號:'10','100','90','888'...
這個時候,我們使用Labelencoder會依據字符串排序編碼。在字符串中'90' > '100',但我們直觀感覺是為'100' > '90',所以需要人為但進行干預編碼,如果都是可以直接轉化為數值形的,編碼時可以直接轉化為數值,或者自己書寫一個字典進行映射。
6.2 人工組合編碼:
這個同樣的也設計到部分專業背景知識,有些問題會出現一些臟亂的數據,例如:
在一些位置字段中,有的是中文的,有的是英文的,例如“ShangHai”,“上海”,二者描述的是同一個地方,但如果我們不注意就忽略了;
這個時候,我們可以先采用字典映射等方式對其進行轉化,然后再使用上面所屬的Frequency等編碼重新對其進行處理。
7. 擴展
上面是數據競賽中最為常用的編碼特征,在基于梯度提升樹模型的建模中,上面的編碼往往可以帶來非常大的幫助,也都是非常值得嘗試的。當然還有一些其它的類別特征的編碼形式,目前使用較多的一個庫就是category_encoders,有興趣的朋友可以當作擴展進行學習,此處不再敘述。
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯溫州大學《機器學習課程》視頻 本站qq群851320808,加入微信群請掃碼:總結
以上是生活随笔為你收集整理的【数据竞赛】Kaggle实战之单类别变量特征工程总结!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新萝卜家园windows11 64位官网
- 下一篇: Win11正版和盗版有什么区别