超越 One-hot encoding — Entity Embedding
終於不只是0跟1了....
以往在結構化資料(structured data)遇到類別變數,我往往只會直接 One-hot encoding 下去,如果有順序的話則是 Label-encoding。然而每次遇到那種類別超過幾十種,甚至幾百種的類別變數時,One-hot encoding 的問題立即浮現出來──原本可能特徵只有 10 個的 dataset,瞬間變成 200 個特徵,而且非常稀疏(200個特徵裡只有 1 個是 1,其他都是 0),造成難以訓練的結果。以往遇到這種情形,我只知道把數量相對少、或者用 boxplot 去看對 y 影響比較低的類別合併成同一類別,藉此降低 One-hot encoding 之後的特徵數量。但是這樣的作法太過主觀,也很沒有效率。
我一直為這個問題苦惱著,直到我遇見 Entity Embedding。
Entity Embedding
這個新潮的方法(其實也不新了)起源於自然語言處理(NLP)裡的 Word Embedding,也就是經典的 word2vec。但是從來沒有人想到要把這個想法套用到結構化資料裡的類別變數上,直到 2016 年的 kaggle 比賽
Rossmann Store Sales 中,Cheng Kuo 發明了這樣的做法,這裡是他的訪談。賽後作者也將方法整理成了一篇論文:《Entity Embeddings of Categorical Variables》。
Entity Embedding 的主要思想是把 word2vec 的作法拿來對類別變數做同樣的事情,也就是把類別向量化,讓類別的表示方法不再單純由0與1組成,而是以0與1以外的數字組成,不僅能夠降低特徵的數量,甚至能夠計算不同類別之間的相似度(距離)。這很好的解決了 One-hot encoding 會遇到的三大問題:太多特徵、太多零、特徵之間彼此無關。以下舉個例子:
假設現在有大小為 (3, 1) 的資料集叫做 x,x 只有一個叫做電器的變數,含有三列,剛好一列一個類別。對這個變數做熟悉的 One-hot 轉換之後,電器這個變數的表示方法從文字變成了向量。「電視」在 x 裡的表示方法為 [1, 0, 0],「手機」為 [0, 1, 0],「平板電腦」為 [0, 0, 1]。由於這樣的表示方法,各類別(向量)之間是正交的(在此理解為垂直就可以), cosine distance 也皆為 1。如果對 cosine distance 不熟悉沒有關係,它只是計算向量距離的其中一種方式,它仍然屬於一種「距離」──也就是數字越大,表示越遠、兩個向量相似性越低,反之則越近、相似性越高。
# Toy example
x = ['電器', # 變數名稱
'電視',
'手機',
'平板電腦']# 以 one-hot encoding 形式表示
x_ohe = [['電視','手機','平板電腦', # 變數名稱
[1,0,0],
[0,1,0],
[0,0,1]]# 彼此 cosine distance -> 1
而經過 Entity Embedding 訓練之後,可能變成這樣:
x_embs = [['embs_1', 'embs_2'],
[0.1, -0.3], # 電視
[-0.3, 0.5], # 手機
[-0.2, 0.1]] # 平板電腦# cosine distance
# 電視 vs 手機: 1.976
# 電視 vs 平板電腦: 1.707
# 手機 vs 平板電腦: 0.156
Entity Embedding 到底做了甚麼事?先不論他是做了甚麼神祕的轉換,首先我們看到,原本電視為 [1, 0, 0] 的向量,變成了 [0.1, -0.3];手機從 [0, 1, 0] 變成 [-0.1, 0.5];平板電腦從 [0, 0, 1] 變成 [-0.2, 0.1]。
而各個類別的表示方法,從原本的 0, 1 變成了含有其他實數的向量,同時也從 3 維降到了 2 維。單看向量裡的數字,並不具任何絕對意義;但如果去計算向量之間的距離的話,就會發現各類別彼此之間的 cosine distance 有所差異。電視與手機的距離為 1.976,相較於電視與平板電腦的距離 1.707 來得遠一些;手機和平板電腦的距離為 0.156,則比電視和手機、平板的距離近的多。換句話說,手機跟平板電腦比較類似,而兩者跟電視的相似度則較低(距離遠表示相似性低)。
這樣做轉換之後,我們便把電器這個文字型的特徵成功轉換為具空間意義的向量。
所以,這又代表甚麼?
這樣做的好處就是,我們得到了一種新的特徵表示方式。我們可以把降維之後得到的維度想成一種「新的特徵」,而這個「新特徵」是用來描述那些電器底下那些「類別」的。舉個不恰當但是可能比較好理解的例子,從上面的簡短範例裡,你可以看到我把做完 Entity Embedding 之後的兩個維度,取名為 embs_1 和 embs_2,在這裡可以這麼想像:embs_1 也許代表的是螢幕大小,embs_2 則可能表示使用時間(翻回去看看,可以看到我設計數字的小心機)。
當然,前面提過轉換之後的數字不具任何絕對意義,端看怎麼解釋而已,上面只是其中一種解釋方法,你可以有你自己詮釋的方式。實際上,去賦予 Embedding 之後的維度意義,並不是 Entity Embedding 主要的運用方式,當維度更大的時候,我們可能就很難去理解數字的意義。上述只是為了方便理解 Embedding 的結果所舉的例子而已。
小結
以上便是 Entity Embedding 的簡單範例。這裡只是讓大家初步認識 Entity Embedding 到底在做甚麼事情,實際上能做的遠遠不只如此,例如結合 t-SNE 做探索類別之間的關係、還是加入資料集當作新的變數做訓練(kaggle 比賽中就是這樣做的)。而從 Cheng Kuo 的訪談來看,Entity Embedding 應該確實是能提升模型表現的。(雖然我自己還沒成功過...QQ)
參考資源