1. 程式人生 > >機器學習-特徵工程-Missing value和Category encoding

機器學習-特徵工程-Missing value和Category encoding

好了,大家現在進入到機器學習中的一塊核心部分了,那就是特徵工程,洋文叫做Feature Engineering。實際在機器學習的應用中,真正用於演算法的結構分析和部署的工作只佔很少的一部分,相反,用於特徵工程的時間基本都佔70%以上,因為是實際的工作中,絕大部分的資料都是非標資料。因而這一塊的內容是非常重要和必要的,如果想要提高機器學習應用開發的效率,feature engineering就像一把鑰匙,一個加速器,能給整個專案帶來事半功倍的效果。另外,feature engineering做的好不好,直接關係到後面的模型的質量。正因為上面的原因,feature engineering我準備詳細的解釋,我準備花三篇隨筆說完。這是第一篇,主要介紹兩部分,分別是missing value的處理和categorical data的處理。其中missing value的處理相對簡單,複雜的是categorical data的處理,有很多種處理方式,我們在這邊就直說常用的5中方式。那麼好啦,咱們就直接進入主題內容吧。

  • Missing value

missing value 顧名思義就是有些實際資料中,有很多的數值是缺失的,那麼怎麼處理這些缺失的資料,就變成了一個很有必要的事情。基本上,咱們處理missing value的方法就是三種,分別是:dropping, Imputation, 和 An extension to imputation。那下面就這三種方法分別來進行程式碼的演示和結果的展示

  1. Dropping。顧名思義,dropping的意思就是整個刪除掉一整行的資料。這裡的意思就是,如果某一列資料含有空資料NaN, 那麼就直接刪除掉這一整行的資料,它的操作如下所示
    missing_data_cols = [col for col in train_X.columns if train_X[col].isna().any()]
    #drop missing data columns
    reduced_train_X = train_X.drop(missing_data_cols, axis =1)

    上面程式碼的第一句是為了找出所有含有空資料的column,第二句程式碼的意思就是刪除掉這些含有空資料的column,記住axis引數設定成1代表著是column,如果設定成0或者沒有設定,則預設指刪除行row。

  2. Imputation。這裡對於處理missing value的第二種方法是指的填充的方法(不知道翻譯的對不對哈),它是什麼意思呢,其實很簡單,它的意思就是將這個空值的element,根據一定的條件填充資料,這裡的條件可以是平均值,中位數,出現頻率最高的等,具體採用哪種方式,還是按照裡面的引數strategy進行設定的。具體的程式碼實現方式,是通過下面來演示
    from sklearn.impute import SimpleImputer
    my_imputer = SimpleImputer(strategy = "mean")
    my_imputer.fit_transform(train_X)
    imputed_train_X = pd.DataFrame(my_imputer.fit_transform(train_X))

    注意這裡需要引進一個新的庫進行資料處理,那就是sklearn, 它是sci-kit learn的縮寫。這個庫也是一個很牛逼的庫,它和TensorFlow的功能一樣,提供了豐富的資料處理方面的介面,可以極大的方便咱們的資料處理,也提供了很多常用的模型供咱們選擇,在機器學習領域可以說是經常用到的。上面第二行程式碼就是設定通過什麼方式來impute,這裡設定的是平均數。第三行返回的是一個numpy array,第四行咱們將這個impute過後的numpy array轉化成dataframe。

  3. An Extension to Imputation。從這個命名咱們可以看出它是對上面imputation的一種補充,是基於imputation的。它實際上是先新增幾個column(有哪些column有missing value,咱們就新增幾個column),這些新增的column是boolean值,如果某一行對應是missing value,這個Boolean值就是True, 如果不是missing value,則是False。咱們看看下面的程式碼和圖片能夠更加深刻的理解。
    X_train_extension = train_X.copy()
    X_val_extension = val_X.copy()
    
    #making columns with missing data
    for col in missing_data_cols:
        X_train_extension[col + "_was_missing"] = train_X[col].isnull()
    
        
    #imputation
    my_imputer = SimpleImputer()
    X_train_extension_impute = pd.DataFrame(my_imputer.fit_transform(X_train_extension))

     

     上面展示了程式碼還有一小段結果的截圖。大家可以很明顯的看出來添加了三個新的columns。這裡的順序根據程式碼也可以看出來,是先新增新的columns,然後再imputation。

  • Categorical Data encoding

上面一節主要講的是Missing value的一些簡單的處理方式,在實際的資料處理中,咱們大部分時間遇到的資料並不是numerical data,相反,咱們大部分時間遇到的都是categorical data,可是在咱們的計算機處理資料的時候,處理的都是numerical data,所以咱們得想辦法將這些categorical data轉成numerical才行。實際中咱們經常使用的策略就是下面的五種方式,下面咱們來一個個講解一下,這一塊也是咱們的重點內容。

  1. dropping。和前面的missing data一樣,直接dropping是最簡單粗暴的方法,雖然這是最簡單的方法,但是實際中,這種方式卻並不常用,因為她往往不利於咱們的模型。極端的想一下,如果咱們的dataframe都是categorical的資料,難道咱們直接把他們全部刪除?????哈哈,那咱們還訓練個毛模型。但是,咱們還是得了解一下,畢竟在極少數的情況下,咱們還是要用到的。咱們直接看程式碼演示,然後解釋一下
    X_train_result_drop = X_train_result.select_dtypes(exclude=["object"])

    看看上面這一句簡單的程式碼,通過dataframe的select_dtypes方法,傳遞一個exclude引數,因為在dataframe中object的資料型別就是categorical data,所以上面的api直接就是刪除了所有categorical data的資料。

  2. Label encoding。對於有些categorical data,咱們可以給每一個category賦值一個數字,例如Female=0,Male = 1等等。那麼哪些categorical data適合label encoding呢?就是那些一列資料中category的種類不是特別多的資料。例如一列categorical data一共有20個category或者50個category都是OK的,如果直接有1000多category,那麼簡單的labeling的效率就不高了,結果也可能不理想。這其實在實際的處理中還是經常會用到的。下面通過一句簡單的程式碼進行演示。注意,這裡都是用sklearn這個元件來進行的演示的,並沒有用其他的例如TensorFlow來演示。
    from sklearn.preprocessing import LabelEncoder
    label_encoder = LabelEncoder() X_train_result_label[col] = label_encoder.fit_transform(X_train_result[col])#one column after one column

    咱們也可以看出,咱們得先建立一個LabelEncoder例項物件,然後對每一個categorical data的column分別應用encoder, 如果需要對多個categorical column進行lable encoding, 咱們得寫一個迴圈,分別對每一個column 進行label encoding。

  3.  one-hot encoding。這是一個大家可能最常用到的一種category encoding的方法,至少在我學習機器學習的過程中,這是最常見到的一種方式,那麼到底什麼是one-hot encoding呢?這裡沒有一個官方的定義,最直接的方法就是先看一下下面的圖片,這是最直接的方式,也最簡單易懂                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 現在咱們來解釋一下,首先先計算出一個category column中一共有多少個categories,然後有多少category就建立多少個columns,每一個category對應一個column,最後在相對應的位置填充1,其他則填充0。故而新建立的dataframe中,每一行只有一個1 其他都是0。這也是one-hot encoding這個名字的來歷。那咱們來看看one hot encoding的程式碼實現吧

    from sklearn.preprocessing import OneHotEncoder
    one_hot_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
    X_train_result_one_hot = pd.DataFrame(one_hot_encoder.fit_transform(X_train_result[object_cols]))

    和之前的label encoding一樣,它也需要引用sklearn這個庫,但是它是先例項化一個OneHotEncoder物件,然後用這個encoder一次性的應用於多個categorical columns, 而不像label encoding那樣要一個column一個column的呼叫。one hot encoding是categorical data encoding中最常用的技術了,但是在有些情況下也不是很適用,例如:如果一個categorical column的categories太多的話,例如1000個,10000個等等,那麼它就不適用於one hot encoding了,因為有1000個categories,就會產生1000個columns,產生的資料就太大了,而且很容易會產生overfitting的情況。

  4. Count encoding

    這也是一種簡單而且高效的encoding方法,它是先計算一個categorical column中的每一個category出現的次數,然後就將這些category用次數來代替,同一個category被代替後,數值是一樣的,有點和series.values_countt()有點類似,大家滿滿體會一下哈。這種方式和label encoding一樣的簡單,而且Python也幫助咱們處理好了細節部分,咱們可以通過下面的方式直接呼叫它的介面進行計算

    import category_encoders as ce
    count_encoder = ce.CountEncoder()
    categorical_data_ce = count_encoder.fit_transform(ks[categorical_cols])

    從上面的程式碼,咱們可以看出來,它也是encoder直接作用於多個categorical columns。

  5. Target encoding                                                                                                                                                                                                                                                                                                                                                                                                        Target encoding是根據target來計算category的,然後來替代的。那麼它的具體流程是什麼呢? 其實呢它是很簡單的,就是先看每一個category對應的target值,然後計算相對應的target的平均數,最後用這個平均數來代替每一個category。其實就是這麼的so easy。老規矩,咱們先看看如何實現的

    import category_encoders as ce
    target_encoder = ce.TargetEncoder(cols=categorical_cols)
    target_encoder.fit_transform(train[categorical_cols], train.outcome)

    從上面咱們可以看出,整體的步驟和count encoding很相似。但是這種方法也有一個致命的弱點,那就是這裡的encoding太過於依賴target了,有很大的可能會有data leakage的風險,target encoding與target有很強的correlation,就有很強的data leakage的風險。所以大家在選擇target encoding的時候一定要仔細考慮分析資料後在選擇。

總結:最後國際慣例咱們先來總結一下feature engineering的第一部分,就是category data和missing value的處理。上面的一些方法是最簡單常用的一些方法了,大家一定要熟悉理解應用,這裡也設計到一些庫的使用,我會在後面詳細叫大家怎麼用。missing value常用的處理方式是:1. dropping

      2. Imputation

      3. Extension to Imputation

然後category data的處理主要是下面的5中方式,這裡大家一定要理解

      1. Dropping

      2. Label encoding

      3. one hot encoding (最常用)

      4. Count encoding

      5. Target encoding (risk of data leak