1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【數(shù)據(jù)競賽】Kaggle實戰(zhàn)之單類別變量特征工程總結!

        共 33200字,需瀏覽 67分鐘

         ·

        2021-04-13 11:41

        作者:塵沙杰少、櫻落、新峰、DOTA、謝嘉嘉

        特征工程--類別變量完結篇!

        前 言

        這是一個系列篇,后續(xù)我們會按照我們第一章中的框架進行更新,因為大家平時都較忙,不會定期更新,如有興趣歡迎長期關注我們的公眾號,如有任何建議可以在評論區(qū)留言,該系列以往的經(jīng)典內容可參考下面的篇章。

        1. kaggle競賽寶典-競賽框架篇!

        2.1 賽題理解,分析,規(guī)劃之賽題理解與分析!

        2.2  kaggle競賽寶典-回歸相關指標優(yōu)化!

        2.3  kaggle競賽寶典-二分類相關指標優(yōu)化!

        2.4  kaggle競賽寶典-多分類相關指標優(yōu)化!

        2.5 數(shù)據(jù)競賽規(guī)劃!

        3.1 數(shù)據(jù)探索分析-全局數(shù)據(jù)探索分析!

        3.2 數(shù)據(jù)探索分析-單變量數(shù)據(jù)分析!

        3.3 數(shù)據(jù)探索分析-交叉變量分析篇!

        3.4 訓練集測試集分布不一致性探索!

        4.1 kaggle競賽寶典-樣本篩選篇!

        4.2 kaggle競賽寶典-樣本組織篇!

        5. 驗證策略設計!

        6.1. 模型理解、選擇--GBDT!

        6.2.模型理解、選擇--XGBoost!

        6.3.模型理解、選擇--LightGBM!

        6.4.模型理解、選擇--CatBoost!

        7.1 特征工程--為什么要做特征工程!

        前言
        在之前的文章中,我們已經(jīng)介紹過部分類別特征編碼的內容,此處,我們將所有的內容進行整合為一個系列,我們不羅列過多的知識點,重點介紹在kaggle過往幾年內中大家最為常用有效的類別編碼技巧,如果對其它類型編碼感興趣的朋友可以學習擴展部分的內容。

        類別特征編碼

        在很多表格類的問題中,高基數(shù)的特征類別處理一直是一個困擾著很多人的問題,究竟哪一種操作是最好的,很難說,不同的數(shù)據(jù)集有不同的特性,可能某一種數(shù)據(jù)轉化操作這A數(shù)據(jù)集上取得了提升,但在B數(shù)據(jù)集上就不行了,但是知道的技巧越多,我們能取得提升的概率往往也會越大。此處我們會介紹幾種常見的處理類別特征的方法。

        1. Label編碼

        無序的類別變量,在很多時候是以字符串形式的出現(xiàn)的,例如:

        • 顏色:紅色,綠色,黑色...
        • 形狀:三角形,正方形,圓形...

        而我們知道,梯度提升樹模型是無法對此類特征進行處理的。直接將其輸入到模型就會報錯。而這個時候最為常見的就是使用LabelEncoder對其進行編碼。LabelEncoder可以將類型為object的變量轉變?yōu)閿?shù)值形式,具體的例子如下:

        LabelEncoder默認會先將object類型的變量進行排序,然后按照大小順序進行的編碼,此處N為該特征中不同變量的個數(shù)。幾乎所有的賽題中都會這么做,這樣做我們就可以將轉化后的特征輸入到模型,雖然這并不是模型最喜歡的形式,但是至少也可以吸收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

        colorcolor_labelencode
        0red3
        1blue1
        2black0
        3green2

        2. One-Hot編碼

        One-Hot編碼對于一個類別特征變量,我們對每個類別,使用二進制編碼(0或1)創(chuàng)建一個新列(有時稱為dummy變量),以表示特定行是否屬于該類別。One-Hot編碼可以將一個基數(shù)為的類別變量轉變?yōu)?span style="font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;cursor: pointer;">個二元向量,我們以上面的顏色為案例,進行one-hot編碼之后就得到:

        我們發(fā)現(xiàn)One-Hot編碼將我們的數(shù)據(jù)展開之后內存的消耗變得非常大,因為使用One-Hot編碼時需要創(chuàng)建額外的列,為我們需要編碼的特征列中的每個每個唯一值創(chuàng)建一個列。也就是說,如果我們有一個包含10000個不同值的類別特征,那么在One-Hot編碼之后將會生成10000個額外的新的列,這是不可以接受的。

        但它的好處也非常明顯,One-Hot編碼之后,我們的線性模型可以更好的吸收High-Cadinality的類別信息,原先我們的采用線性模型,那么我們類別變量A的對預測帶來的貢獻為,, (A由(組成)我們發(fā)現(xiàn)類別2的貢獻就是類別1的一倍,這很明顯和我們的直覺不符,但是展開之后,我們類別變量A對預測帶來的貢獻為:。變量之間的關系變得更加合理了。所以One-Hot編碼對于很多線性模型是有必要的。

        那么對于XGBoost,LightGBM之類的樹模型是否有必要呢?答案是有的!在我們的實踐中,很多時候對高基數(shù)的類別特征直接進行One-Hot編碼的效果往往可能不如直接LabelEncoder來的好。但是當我們的類別變量中有一些變量是人為構造的,加入了很多噪音,這個時候將其展開,那么模型可以更加快的找到那些非構建的類別。(參考訊飛18年舉辦的推薦比賽),取得更好的效果。

        對應代碼:

        from sklearn import preprocessing
        df = pd.DataFrame({'color':['red','blue','black','green']})
        pd.get_dummies(df['color'].values) 

        blackbluegreenred
        00001
        10100
        21000
        30010

        3. Frequency編碼

        Frequency編碼是數(shù)據(jù)競賽中使用最為廣泛的技術,在90%以上的數(shù)據(jù)建模的問題中都可以帶來提升。因為在很多的時候,頻率的信息與我們的目標變量往往存在有一定關聯(lián),例如:

        • 在音樂推薦問題中,對于樂曲進行Frequency編碼可以反映該樂曲的熱度,而熱度高的樂曲往往更受大家的歡迎;
        • 在購物推薦問題中,對于商品進行Frequency編碼可以反映該商品的熱度,而熱度高的商品大家也更樂于購買;
        • 微軟設備被攻擊概率問題中,預測設備受攻擊的概率,那么設備安裝的軟件是非常重要的信息,此時安裝軟件的count編碼可以反映該軟件的流行度,越流行的產(chǎn)品的受眾越多,那么黑客往往會傾向對此類產(chǎn)品進行攻擊,這樣黑客往往可以獲得更多的利益

        Frequency編碼通過計算特征變量中每個值的出現(xiàn)次數(shù)來表示該特征的信息,詳細的案例如下所示:

        在很多實踐問題中,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

        colorcolor_cnt
        0red3
        1red3
        2red3
        3blue2
        4blue2
        5black1
        6green3
        7green3
        8green3

        4. target編碼

        target編碼是06年提出的一種結合標簽進行編碼的技術,它將類別特征替換為從標簽衍生而來的特征,在類別特征為高基數(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編碼的思路相對簡單,我們每次編碼時,不考慮當前樣本的情況,用其它樣本對應的標簽的均值作為我們的編碼,而測試集則用全部訓練集樣本的均值進行編碼,案例如下:

        的案例摘自owen-zhang(曾經(jīng)的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'])

        color
        00.6
        10.8
        20.6
        30.6
        40.8
        50.6
        60.0
        71.0
        loo.transform(df_te['color'])

        color
        00.666667
        10.666667
        20.500000

        4.2. K-fold mean-target 編碼

        K-fold mean-target編碼的基本思想來源于Mean target編碼。K-fold mean-target編碼的訓練步驟如下,我們先將訓練集劃分為K折;

        • 在對第A折的樣本進行編碼時,我們刪除K折中A折,并用剩余的數(shù)據(jù)計算如下公式:
        • 后利用上面計算得到的值對第A折進行編碼;
        • 依次對所有折進行編碼即可。

        首先我們先理解一下上面的公式,最原始的Mean-target編碼是非常容易導致過擬合的,這其中過擬合的最大的原因之一在于對于一些特征列中出現(xiàn)次數(shù)很少的值過擬合了,比如某些值只有1個或者2到3個,但是這些樣本對應的標簽全部是1,怎么辦,他們的編碼值就應該是1,但是很明顯這些值的統(tǒng)計意義不大,大家可以通過伯努利分布去計算概率來理解。而如果我們直接給他們編碼了,就會誤導模型的學習。那么我們該怎么辦呢?

        • 加正則!

        于是我們就有了上面的計算式子,式子是值出現(xiàn)的次數(shù),是它對應的概率,是全局的均值, 那么當為0同時比較小的時候, 就會有大概率出現(xiàn)過擬合的現(xiàn)象,此時我們調大就可以緩解這一點,所以很多時候都需要不斷地去調整的值。


        from category_encoders.target_encoder import TargetEncoder 
        from sklearn import base
        from sklearn.model_selection import KFold

        df = 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,11,0,0,0,0,10,10,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   = colnames
                self.targetName = targetName
                self.n_fold     = n_fold
                self.verbosity  = verbosity
                self.discardOriginal_col = discardOriginal_col

            def fit(self, X, y=None):
                return self


            def 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.nan

                for 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].values
                    print('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 X
            
        class KFoldTargetEncoderTest(base.BaseEstimator, base.TransformerMixin):
            
            def __init__(self,train,colNames,encodedName):
                
                self.train = train
                self.colNames = colNames
                self.encodedName = encodedName
                
                
            def fit(self, X, y=None):
                return self

            def 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.

        FeatureTargetFeature_Kfold_Target_Enc
        0A10.555556
        1B00.285714
        2B00.285714
        3B10.285714
        4B10.250000
        5A10.625000
        6B00.250000
        7A00.625000
        8A00.714286
        9B00.333333
        10A10.714286
        11A00.714286
        12B10.250000
        13A00.625000
        14A10.625000
        15B00.250000
        16B00.375000
        17B00.375000
        18A10.500000
        19A10.500000
        '''
           測試集編碼
        '''

        test_targetc = KFoldTargetEncoderTest(new_train,
                                              'Feature',
                                              'Feature_Kfold_Target_Enc')
        new_test = test_targetc.fit_transform(test)

        4.3. Beta Target編碼

        Beta Target編碼來源于kaggle之前的競賽Avito Demand Prediction Challenge第14名方案。該編碼和傳統(tǒng)Target Encoding不一樣,

        • Beta Target Encoding可以提取更多的特征,不僅僅是均值,還可以是方差等等;
        • 在開源中,是沒有進行N Fold提取特征的,所以可能在時間上提取會更快一些;

        Beta Target編碼利用Beta分布作為共軛先驗,對二元目標變量進行建模。Beta分布用來參數(shù)化,可以被當作是重復Binomial實驗中的正例數(shù)和負例數(shù)。分布中許多有用的統(tǒng)計數(shù)據(jù)可以用表示,例如,

        平均值:

        方差:

        等等。

        從實驗對比上我們發(fā)現(xiàn),使用Beta Target Encoding可以得到大幅提升。因為Beta Target Encoding屬于類別編碼的一種,所以適用于高基數(shù)類別特征的問題。

        對應代碼:

        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 = group
                self.stats = None
                
            # get counts from df
            def fit(self, df, target_col):
                # 先驗均值
                self.prior_mean = np.mean(df[target_col]) 
                stats           = df[[target_col, self.group]].groupby(self.group)
                # count和sum
                stats           = 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 statistics
            def 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 missing
                nan_indexs    = np.isnan(n)
                n[nan_indexs] = self.prior_mean
                N[nan_indexs] = 1.0
                
                # prior parameters
                N_prior     = np.maximum(N_min-N, 0)
                alpha_prior = self.prior_mean*N_prior
                beta_prior  = (1-self.prior_mean)*N_prior
                
                # posterior parameters
                alpha       =  alpha_prior + n
                beta        =  beta_prior  + N-n
                
                # calculate statistics
                if stat_type=='mean':
                    num = alpha
                    dem = alpha+beta
                            
                elif stat_type=='mode':
                    num = alpha-1
                    dem = alpha+beta-2
                    
                elif stat_type=='median':
                    num = alpha-1/3
                    dem = alpha+beta-2/3
                
                elif stat_type=='var':
                    num = alpha*beta
                    dem = (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 missing
                value = num/dem
                value[np.isnan(value)] = np.nanmedian(value)
                return value
        N_min = 1000
        feature_cols = []    

        # encode variables
        for c in cat_cols:

            # fit encoder
            be = BetaEncoder(c)
            be.fit(train, 'deal_probability')

            # mean
            feature_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)

            # mode
            feature_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)
            
            # median
            feature_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)    

            # var
            feature_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)        
            
            # skewness
            feature_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)    
            
            # kurtosis
            feature_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)是變量轉化的利器,經(jīng)常會出現(xiàn)在信用卡評分等問題中,用來判斷好的和壞的客戶。WOE不僅簡單,而且可以依據(jù)其大小來篩選出重要的分組(group),可解釋性較強,早期WOE和邏輯回歸算法經(jīng)常一起使用并且可以幫助獲得較大的提升,在Kaggle的數(shù)據(jù)競賽中,我們發(fā)現(xiàn)WOE和梯度提升樹模型結合也可以取得不錯的效果。

        • 此處的Event和Non Event為別是標簽為1的樣本的分布以及標簽為0的樣本的分布;
        • 標簽為1的樣本分布:在某個類內正樣本占所有正樣本的比例;標簽為0的樣本分布也是類似的。

        從上面的公式中,我們知道,正樣本的分布和負樣本的分布如果在某個類中差別越大的話,涵蓋的信息就越大,如果WOE的值越大,擇該這個類內的為正的概率極大,反之越小

        在實踐中,我們可以直接通過下面的步驟計算得到WOE的結果:

        • 對于一個連續(xù)變量可以將數(shù)據(jù)先進行分箱,對于類別變量(無需做任何操作);
        • 計算每個類內(group)中正樣本和負樣本出現(xiàn)的次數(shù);
        • 計算每個類內(group)正樣本和負樣本的百分比events%以及non events %;
        • 按照公式計算WOE;

        對應代碼:

        '''
            代碼摘自:https://github.com/Sundar0989/WOE-and-IV
        '''

        import os
        import pandas as pd
        import numpy as np

        df = 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 string

        max_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        = 0
            
            while 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 - 1

            if len(d2) == 1:
                n    = force_bin         
                bins = algos.quantile(notmiss.X, np.linspace(01, n))
                if len(np.unique(bins)) == 2:
                    bins = np.insert(bins, 01)
                    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().X
            d3["MAX_VALUE"] = d2.max().X
            d3["COUNT"]     = d2.count().Y
            d3["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.nan
                d4["COUNT"] = justmiss.count().Y
                d4["EVENT"] = justmiss.sum().Y
                d4["NONEVENT"] = justmiss.count().Y - justmiss.sum().Y
                d3 = 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().Y
            d3["MIN_VALUE"] = df2.sum().Y.index
            d3["MAX_VALUE"] = d3["MIN_VALUE"]
            d3["EVENT"] = df2.sum().Y
            d3["NONEVENT"] = df2.count().Y - df2.sum().Y
            
            if len(justmiss.index) > 0:
                d4 = pd.DataFrame({'MIN_VALUE':np.nan},index=[0])
                d4["MAX_VALUE"] = np.nan
                d4["COUNT"] = justmiss.count().Y
                d4["EVENT"] = justmiss.sum().Y
                d4["NONEVENT"] = justmiss.count().Y - justmiss.sum().Y
                d3 = 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()
            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.index
            count = -1
            
            for 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"] = i
                        count = count + 1
                    else:
                        conv = char_bin(target, df1[i])
                        conv["VAR_NAME"] = i            
                        count = count + 1
                        
                    if count == 0:
                        iv_df = conv
                    else:
                        iv_df = iv_df.append(conv,ignore_index=True)
             
            return iv_df 

        final_iv = data_vars(df,df.target)

        6. 人工編碼

        6.1 人工轉化編碼

        這個需要一些專業(yè)背景知識,可以認為是Label編碼的一種補充,如果我們的類別特征是字符串類型的,例如:

        • 城市編號:'10','100','90','888'...

        這個時候,我們使用Labelencoder會依據(jù)字符串排序編碼。在字符串中'90' > '100',但我們直觀感覺是為'100' > '90',所以需要人為但進行干預編碼,如果都是可以直接轉化為數(shù)值形的,編碼時可以直接轉化為數(shù)值,或者自己書寫一個字典進行映射。

        6.2 人工組合編碼

        這個同樣的也設計到部分專業(yè)背景知識,有些問題會出現(xiàn)一些臟亂的數(shù)據(jù),例如:

        • 在一些位置字段中,有的是中文的,有的是英文的,例如“ShangHai”,“上?!?,二者描述的是同一個地方,但如果我們不注意就忽略了;

        這個時候,我們可以先采用字典映射等方式對其進行轉化,然后再使用上面所屬的Frequency等編碼重新對其進行處理。

        7. 擴展

        上面是數(shù)據(jù)競賽中最為常用的編碼特征,在基于梯度提升樹模型的建模中,上面的編碼往往可以帶來非常大的幫助,也都是非常值得嘗試的。當然還有一些其它的類別特征的編碼形式,目前使用較多的一個庫就是category_encoders,有興趣的朋友可以當作擴展進行學習,此處不再敘述。

        往期精彩回顧





        本站qq群851320808,加入微信群請掃碼:

        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产69精品久久久久乱码网站 | 超碰97干 | 国产18在线 | 国产精品久久久久久久久久春嫩 | 在线播放亚洲 | 日韩一区二区婬片国产欧美在线 | 成人美女黄网站色大色费全看在线观看 | 久久九九精品久久 | 国产探花伦理在线观看 | 含羞草2023 |