數據預處理:分類變量實體嵌入做特征提取


實體嵌入(embedding)目的將表格數據中的分類屬性(一個至多個)向量化

1.實體嵌入簡介:

  • 實體嵌入是主要應用於深度學習中處理表格分類數據的一種技術,或者更確切地說NLP領域最為常用,word2vec就是在做詞的實體嵌入。
  • 神經網絡相比於當下的流行的xgboost、LGBM等樹模型並不能很好地直接處理大量分類水平的分類特征。因為神經網絡要求輸入的分類數據進行one-hot處理。當分類特征的水平很高的時候,one-hot經常帶來維度爆炸問題,緊接着就是參數爆炸,局部極小值點更多,更容易產生過擬合等等一系列問題。
  • 實體嵌入可以用低維度的連續空間表示原始高維的離散空間。同時經過嵌入層的處理,獲得的連續型特征還可以學習到原始特征中的一些相似性。
  • 實體嵌入通過將分類屬性放入網絡的全連接層的輸入單元中,后接幾個單元數較輸入層更少的隱藏層(連續型變量直接接入第一個隱藏層),經過神經網絡訓練后輸出第一個隱藏層中分類變量關聯的隱層單元,作為提取的特征,用於各種模型的輸入。

 

2.用實體嵌入做特征提取的網絡結構(示例)

(暫略)

 

 

 

 

 

3.實體嵌入代碼(示例)

  1 import math
  4 import random as rn
  5 import numpy as np
  6 from keras.models import Model
  7 from keras.layers import Input, Dense, Concatenate, Reshape, Dropout
  8 from keras.layers.embeddings import Embedding
  9  10 
 11 #傳入分類變量數據(沒有one-hot)和連續變量數據,返回一個model對象(它根據數據的組成定義好了網絡框架類,這個類之后可以調用,喂入數據訓練)
 12 def build_embedding_network(category_data, continus_data):
 13     
 14     #獲取分類變量的名稱
 15     cat_cols = [x for x in category_data.columns]
 16     
 17     #以字典形式存儲分類變量的{名稱:維度}
 18     category_origin_dimension = [math.ceil(category_data[cat_col].drop_duplicates().size) for cat_col in cat_cols]
 19     
 20     #以字典形式存儲分類變量 計划 在embed后的{名稱:維度}
 21     category_embedding_dimension = [math.ceil(math.sqrt(category_data[cat_col].drop_duplicates().size)) for cat_col in cat_cols]
 22 
 23     # 以網絡結構embeddding層在前,dense層(全連接)在后;2.訓練集的X必須以分類特征在前,連續特征在后。
 24     inputs = []
 25     embeddings = [] #嵌入層用list組織數據
 26     
 27     #對於每一個分類變量,執行以下操作
 28     for cat_val, cat_origin_dim, cat_embed_dim in list(zip(cat_cols, category_origin_dimension, category_embedding_dimension)) :
 29         
 30         # 實例化輸入數據的張量對象
 31         input_cate_feature = Input(shape=(1,)) #batch_size, 空(維度)
 32         
 33         #實例化embed層的節點:定義輸入的維度(某個分類變量的onehot維度),輸出的維度(其embed后的維度),同時傳入input數據對象
 34         embedding = Embedding(input_dim = cat_origin_dim, 
 35                               output_dim = cat_embed_dim, 
 36                               input_length=1)(input_cate_feature)
 37         
 38         # 將embed層輸出的形狀調整
 39         embedding = Reshape(target_shape=(cat_embed_dim,))(embedding)
 40         
 41         #每遍歷一個分類變量就將輸入數據添加在inputs對象中
 42         inputs.append(input_cate_feature)
 43         
 44         #每遍歷一個分類變量就擴展一個embedding層的節點
 45         embeddings.append(embedding)
 46         
 47     #dda於連續特征執行以下操作:
 48     
 49     #獲取連續特征的變量個數
 50     cnt_val_num = continus_data.shape[1]
 51     #連續特征原封原樣迭代地加入與分類變量embedding后的輸出組合在一起(沒有embedding操作)
 52     for cnt_val_num in range(cnt_val_num) :
 53         input_numeric_features = Input(shape=(1,))
 54     
 55         #輸入的連續型數據不經過任何一種激活函數處理直接 與embed + reshape后的分類變量進行組合
 56         embedding_numeric_features = Dense(units = 16)(input_numeric_features) 
 57         inputs.append(input_numeric_features)
 58         embeddings.append(embedding_numeric_features)       
 59         
 60     #把有不同輸入的embedding 層的數據鏈接在一起
 61     x = Concatenate()(embeddings) #這種寫法表明concatenate返回的是一個函數,第二個括號是傳入這個返回的函數的參數
 62    
 63     x = Dense(units = 16, activation='relu')(x)
 64     
 65     #丟棄15%的節點
 66     x = Dropout( 0.15 )(x)
 67     
 68     #輸出層包含一個節點,激活函數是relu
 69     output = Dense(1, activation='relu')(x)
 70     model = Model(inputs, output)
 71     model.compile(loss='mean_squared_error', optimizer='adam')
 72 
 73     return model
 74 
 75 
 76 # 訓練
 77 NN = build_embedding_network(category_features_in_trainset, continus_features_in_trainset )
 78 NN.fit(X, y_train, epochs=3, batch_size=40, verbose=0)
 79 
 80 #讀取embedding層數據
 81 cate_feature_num = category_features_in_trainset.columns.size
 82 
 83 model = NN  # 創建原始模型
 84 for i in range(cate_feature_num):
 85     # 如果把類別特征放前,連續特征放后,cate_feature_num+i就是所有embedding層
 86     layer_name = NN.get_config()['layers'][cate_feature_num+i]['name']
 87  
 88     intermediate_layer_model = Model(inputs=NN.input,
 89                                      outputs=model.get_layer(layer_name).output)
 90     
 91     # numpy.array
 92     intermediate_output = intermediate_layer_model.predict(X)
 93 
 94 intermediate_output.resize([train_data.shape[0],cate_embedding_dimension[i][1]])
 95     
 96     if i == 0: #將第一個輸出賦值給X_embedding_trans,后續疊加在該對象后面
 97         X_embedding_trans = intermediate_output
 98     else:
 99         X_embedding_trans = np.hstack((X_embedding_trans,intermediate_output)) #水平拼接
100 
101 
102 #顯示分類變量向量化后的數據
103 X_embedding_trans

 

4.個人觀點

高levels的分類變量而言,多是用戶ID、地址、名字等。變量如‘地址’可以通過概念分層的辦法獲取省、市之類的維度較少的特征;‘商品’也可以通過概念分層獲取其更泛化的類別。概念分層這種數據規約操作實質是在平滑數據,很可能淹沒掉有用的信息。我可能不會選擇這種方式來建立預測模型(但做細分統計、透視圖的時候會經常使用到)。也有的人會不用這些分類變量,但是我覺得會損失一些有用的影響因素,所以最好物盡其用。

實體嵌入跟word2vector一樣會讓output相似的對象在隱藏層中的數值也相近。使用低緯度、連續型變量的數據訓練模型,效果也會比用高維、稀疏的數據訓練好得多。

這種針對分類變量特征提取的方法對於提升預測准確率來說是很有效的,跟模型堆疊一樣有效。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM