專欄 | 基於 Jupyter 的特徵工程手冊:數據預處理(二)

作者:陳穎祥、楊子晗

編譯:AI有道

基於 Jupyter 的特徵工程手冊:數據預處理的上一篇:

專欄 | 基於 Jupyter 的特徵工程手冊:數據預處理(一)

項目地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook

本項目將探討數據預處理部分:介紹瞭如何利用 scikit-learn 處理靜態的連續變量,利用 Category Encoders 處理靜態的類別變量以及利用 Featuretools 處理常見的時間序列變量。

目錄

特徵工程的數據預處理我們將分爲三大部分來介紹:

  • 靜態連續變量

  • 靜態類別變量

  • 時間序列變量

本文將介紹 1.2 靜態類別變量的數據預處理(上部分,即1.2.1-1.2.6)。下面將結合 Jupyter,使用 sklearn,進行詳解。

1.2 Static Categorical Variables 靜態類別變量

真實世界的數據集還往往包含類別特徵。但是由於scikit-learn中的模型只能處理數值特徵,因此我們需要將類別特徵編碼爲數值特徵但是,很多新的模型開始直接提供類別變量支持,例如lightGBM和Catboost。這裏我們使用category_encoders包,因爲它涵蓋了更多的編碼方法。

1.2.1 Ordinal Encoding 序數編碼

序數編碼將類別變量轉化爲一列序數變量,包含從1到類別數量之間的整數

import numpy as np
import pandas as pd
from category_encoders import OrdinalEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set # 原始測試集

encoder = OrdinalEncoder(cols = ['Sex', 'Type'], 
                         handle_unknown = 'value', 
                         handle_missing = 'value').fit(train_set,train_y) # 在訓練集上訓練
# 將 handle_unknown設爲‘value’,即測試集中的未知特徵值將被標記爲-1
# 將 handle_missing設爲‘value’,即測試集中的缺失值將被標記爲-2
# 其他的選擇爲:‘error’:即報錯;‘return_nan’:即未知值/缺失之被標記爲nan 
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集


# 以測試集結果爲例
encoded_test


# 在序數編碼中:
  
# 變量Sex中: 'male' => 1.0, 'female' => 2.0, 未知 => -1.0, 缺失值 => -2.0
# (事實上,測試集中完全有可能出現未知與缺失情況)
# 在我們的例子中, Sex這一變量中的'other' 類別從未在訓練集中出現過
  
# 變量 Type 中: 10 => 1.0, 20 => 2.0, 15 => 3.0, 未知 => -1.0, 缺失值 => -2.0

encoded_train.astype(float) # 訓練集結果

1.2.2 One-hot Encoding 獨熱編碼

Scikit-learn中也提供來獨熱編碼函數,其可以將具有n_categories個可能值的一個分類特徵轉換爲n_categories個二進制特徵,其中一個爲1,所有其他爲0在category_encoders中,它包含了附加功能,即指示缺失或未知的值。在這裏,我們繼續使用category_encoders

import numpy as np
import pandas as pd
from category_encoders import OneHotEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set  # 原始測試集

encoder = OneHotEncoder(cols=['Sex', 'Type'], 
                        handle_unknown='indicator', 
                        handle_missing='indicator', 
                        use_cat_names=True).fit(train_set,train_y) # 在訓練集上訓練
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集
# 將 handle_unknown設爲‘indicator’,即會新增一列指示未知特徵值
# 將 handle_missing設爲‘indicator’,即會新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的選擇爲:
# ‘error’:即報錯; ‘return_nan’:即未知值/缺失之被標記爲nan; ‘value’:即未知值/缺失之被標記爲0


# 以測試集結果爲例
encoded_test


# 在獨熱編碼中:
  
# 變量 Sex => 變爲了4個新變量: 'male' => [1 ,0 ,0, 0];
#                           'female' => [0 ,1 ,0, 0];
#                           未知 =>  [0 ,0 ,0, 1];
#                           缺失 => [0, 0, 1, 0];
    
# 變量 Type => 變爲了5個新變量: 10 => [1, 0, 0, 0, 0];
#                            20 => [0, 1, 0, 0, 0];, 
#                            15 => [0, 0, 1, 0, 0];
#                            未知 => [0, 0, 0, 0, 1];
#                            缺失 => [0, 0, 0, 1, 0];

1.2.3 Hashing Encoding 哈希編碼

哈希編碼基於特徵哈希的方法。它將哈希函數應用於變量,將任意數量的變量以一定的規則映射到給定數量的變量。特徵哈希可能會導致要素之間發生衝突。但哈希編碼的優點是它不需要制定和維護原變量與新變量之間的映射關係。因此,哈希編碼器的大小及複雜程度不隨數據類別的增多而增多。

import numpy as np
import pandas as pd
from category_encoders.hashing import HashingEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set # 原始測試集

encoder = HashingEncoder(cols=['Sex', 'Type'],  
                         n_components = 5).fit(train_set,train_y)
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集


# 將兩列的數據集哈希編碼爲5列
# 哈希編碼結果與訓練集/測試集中的內容無關
# 只要列名匹配,我們就可以在任何新數據集上使用哈希編碼方法
# 編碼結果僅由哈希函數確定


# 通常哈希編碼應用於更高和更稀疏的維空間,這裏以兩個變量作爲哈希編碼的例子
# 以測試集結果爲例
encoded_test

encoded_train # 訓練集結果

1.2.4 Helmert Encoding Helmert 編碼

Helmert編碼通常在計量經濟學中使用。在Helmert編碼(分類特徵中的每個值對應於Helmert矩陣中的一行)之後,線性模型中編碼後的變量係數可以反映在給定該類別變量某一類別值的情形下因變量的平均值與給定該類別其他類別值的情形下因變量的平均值的差值。在category_encoders包中實現的Helmert編碼爲反向Helmert編碼。更多信息:

https://www.statsmodels.org/devel/contrasts.html

import numpy as np
import pandas as pd
from category_encoders import HelmertEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set # 原始測試集

encoder = HelmertEncoder(cols=['Sex', 'Type'], 
                         handle_unknown='indicator', 
                         handle_missing='indicator').fit(train_set,train_y) # 在訓練集上訓練
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集
# 將 handle_unknown設爲‘indicator’,即會新增一列指示未知特徵值
# 將 handle_missing設爲‘indicator’,即會新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的選擇爲:
# ‘error’:即報錯; ‘return_nan’:即未知值/缺失之被標記爲nan; ‘value’:即未知值/缺失之被標記爲0


# 以測試集結果爲例
encoded_test


# 在Helmert編碼中:
  
# 變量 Sex => 變爲了4個新變量(包含常數項): 'male' => [ 1. -1. -1. -1.];
#                                      'female' => [ 1.  1. -1. -1.];
#                                      未知 =>  [ 1.  0.  0.  3.];
#                                      缺失 => [ 1.  0.  2. -1.];
    
# 變量 Type => 變爲了5個新變量(包含常數項): 10 => [ 1. -1. -1. -1. -1.];
#                                        20 => [ 1.  1. -1. -1. -1.];, 
#                                        15 => [ 1.  0.  2. -1. -1.];
#                                        未知 =>  [ 1.  0.  0.  0.  4.];
#                                        缺失 => [ 1.  0.  0.  3. -1.];

# 可以通過如下代碼計算變量Type的Helmert 矩陣


from patsy.contrasts import Helmert
levels = [1,2,3,4,5] # 3個變量值 + 1個未知值 + 1個缺失值
contrast = Helmert().code_with_intercept(levels)
print(contrast.matrix) # 第一列爲常數項
[[ 1. -1. -1. -1. -1.]
 [ 1.  1. -1. -1. -1.]
 [ 1.  0.  2. -1. -1.]
 [ 1.  0.  0.  3. -1.]
 [ 1.  0.  0.  0.  4.]]
encoded_train # 訓練集結果

1.2.5 Sum (Deviation) Encoding 偏差編碼

偏差編碼也通常在計量經濟學中被使用。偏差編碼後,線性模型的係數可以反映該給定該類別變量值的情況下因變量的平均值與全局因變量的平均值的差異。更多信息:

https://www.statsmodels.org/devel/contrasts.html

import numpy as np
import pandas as pd
from category_encoders.sum_coding import SumEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set # 原始測試集

encoder = SumEncoder(cols=['Sex', 'Type'], 
                     handle_unknown='indicator', 
                     handle_missing='indicator').fit(train_set,train_y) # 在訓練集上訓練
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集
# 將 handle_unknown設爲‘indicator’,即會新增一列指示未知特徵值
# 將 handle_missing設爲‘indicator’,即會新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的選擇爲:
# ‘error’:即報錯; ‘return_nan’:即未知值/缺失之被標記爲nan; ‘value’:即未知值/缺失之被標記爲0


# 以測試集結果爲例
encoded_test


# 在Helmert編碼中:
  
# 變量 Sex => 變爲了4個新變量(包含常數項): 'male' => [ 1.  1.  0.  0.];
#                                      'female' => [ 1.  0.  1.  0.];
#                                       未知 =>  [ 1. -1. -1. -1.];
#                                       缺失 => [ 1.  0.  0.  1.];
    
# 變量 Type => 變爲了5個新變量(包含常數項): 10 => [ 1.  1.  0.  0.  0.];
#                                        20 => [ 1.  0.  1.  0.  0.];, 
#                                        15 => [ 1.  0.  0.  1.  0.];
#                                        未知 =>  [ 1. -1. -1. -1. -1.];
#                                        缺失 => [ 1.  0.  0.  0.  1.];

# 可以通過如下代碼計算變量Type的Deviation 矩陣


from patsy.contrasts import Sum
levels = [1,2,3,4,5] # 3個變量值 + 1個未知值 + 1個缺失值
contrast = Sum().code_with_intercept(levels)
print(contrast.matrix) # 第一列爲常數項
[[ 1.  1.  0.  0.  0.]
 [ 1.  0.  1.  0.  0.]
 [ 1.  0.  0.  1.  0.]
 [ 1.  0.  0.  0.  1.]
 [ 1. -1. -1. -1. -1.]]
encoded_train # 訓練集結果

1.2.6 Target Encoding 目標編碼

目標編碼是一種不僅基於特徵值本身,還基於相應因變量的類別變量編碼方法。對於分類問題:將類別特徵替換爲給定某一特定類別值的因變量後驗概率與所有訓練數據上因變量的先驗概率的組合。對於連續目標:將類別特徵替換爲給定某一特定類別值的因變量目標期望值與所有訓練數據上因變量的目標期望值的組合。該方法嚴重依賴於因變量的分佈,但這大大減少了生成編碼後特徵的數量。

公式:

其中min_samples_leaf和smoothing是用戶定義的參數;
min_samples_leaf:計算類別平均值時的最小樣本數(即若該類別出現次數少,則將被忽略),用以控制過擬合;
smoothing:平衡分類平均值與先驗平均值的平滑係數。其值越高,則正則化越強;
????′????是類別特徵X中類別爲k的編碼值;
Prior Prob:目標變量的先驗概率/期望;
n:類別特徵X中,類別爲k的樣本數;
????+:不僅在類別特徵X中具有類別k,而且具有正結果的樣本數(分類問題);

參考文獻: Micci-Barreca, D. (2001). A preprocessing scheme for high-cardinality categorical attributes in classification and prediction problems. ACM SIGKDD Explorations Newsletter, 3(1), 27-32.

import numpy as np
import pandas as pd
from category_encoders.target_encoder import TargetEncoder
# category_encoders 直接支持dataframe


# 隨機生成一些訓練集
train_set = pd.DataFrame(np.array([['male',10],['female', 20], ['male',10], 
                       ['female',20],['female',15]]),
             columns = ['Sex','Type'])
train_y = np.array([False, True, True, False, False])


# 隨機生成一些測試集, 並有意讓其包含未在訓練集出現過的類別與缺失值
test_set = pd.DataFrame(np.array([['female',20],['male', 20], ['others',15], 
                       ['male',20],['female',40], ['male', 25]]),
             columns = ['Sex','Type'])
test_set.loc[4,'Type'] = np.nan
train_set # 原始訓練集

test_set # 原始測試集

encoder = TargetEncoder(cols=['Sex','Type'], 
                        handle_unknown='value',  
                        handle_missing='value').fit(train_set,train_y) # 在訓練集上訓練
encoded_train = encoder.transform(train_set) # 轉換訓練集
encoded_test = encoder.transform(test_set) # 轉換測試集


# handle_unknown 和 handle_missing 被設定爲 'value'
# 在目標編碼中,handle_unknown 和 handle_missing 僅接受 ‘error’, ‘return_nan’ 及 ‘value’ 設定
# 兩者的默認值均爲 ‘value’, 即對未知類別或缺失值填充訓練集的因變量平均值


encoded_test # 編碼後的變量數與原類別變量數一致

# 驗證一下計算的結果,在測試集中,‘male’類別的編碼值爲 0.473106
prior = train_y.mean() # 先驗概率
min_samples_leaf = 1.0 # 默認爲1.0
smoothing = 1.0 # 默認爲1.0
n = 2 # 訓練集中,兩個樣本包含‘male’這個標籤
n_positive = 1 # 在訓練集中,這兩個包含‘male’標籤的樣本中僅有一個有正的因變量標籤


???????????????????????? = 1 / (1 + np.exp(-(n - min_samples_leaf) / smoothing))
male_encode = prior * (1-????????????????????????) + ???????????????????????? * n_positive/n
male_encode # return 0.4731058578630005,與要驗證的值吻合
0.4731058578630005
encoded_train # 訓練集結果

好了,以上就是關於靜態類別變量(上部分)的數據預處理介紹。建議讀者結合代碼,在 Jupyter 中實操一遍。

目前該項目完整中文版正在製作中,請持續關注哦~

中文版 Jupyter 地址:

http://localhost:8888/notebooks/feature-engineering-handbook-master/%E4%B8%AD%E6%96%87%E7%89%88/1.%20%E6%95%B0%E6%8D%AE%E9%A2%84%E5%A4%84%E7%90%86.ipynb#Ordinal-Encoding-%E5%BA%8F%E6%95%B0%E7%BC%96%E7%A0%81


推薦閱讀

(點擊標題可跳轉閱讀)

乾貨 | 公衆號歷史文章精選

我的深度學習入門路線

我的機器學習入門路線圖

重磅!

林軒田機器學習完整視頻和博主筆記來啦!

掃描下方二維碼,添加 AI有道小助手微信,可申請入羣,並獲得林軒田機器學習完整視頻 + 博主紅色石頭的精煉筆記(一定要備註:入羣 + 地點 + 學校/公司。例如:入羣+上海+復旦。 

長按掃碼,申請入羣

(添加人數較多,請耐心等待)

 

最新 AI 乾貨,我在看 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章