推薦系統(tǒng)遇上深度學(xué)習(xí)(四)--多值離散特征的embedding解決方案

推薦系統(tǒng)遇上深度學(xué)習(xí)系列:
推薦系統(tǒng)遇上深度學(xué)習(xí)(一)--FM模型理論和實(shí)踐:http://www.lxweimin.com/p/152ae633fb00
推薦系統(tǒng)遇上深度學(xué)習(xí)(二)--FFM模型理論和實(shí)踐:http://www.lxweimin.com/p/781cde3d5f3d
推薦系統(tǒng)遇上深度學(xué)習(xí)(三)--DeepFM模型理論和實(shí)踐:
http://www.lxweimin.com/p/6f1c2643d31b

1、背景

在本系列第三篇文章中,在處理DeepFM數(shù)據(jù)時(shí),由于每一個(gè)離散特征只有一個(gè)取值,因此我們在處理的過程中,將原始數(shù)據(jù)處理成了兩個(gè)文件,一個(gè)記錄特征的索引,一個(gè)記錄了特征的值,而每一列,則代表一個(gè)離散特征。

但假如,我們某一個(gè)離散特征有多個(gè)取值呢?舉個(gè)例子來說,每個(gè)人喜歡的NBA球隊(duì),有的人可能喜歡火箭和湖人,有的人可能只喜歡勇士,也有的人喜歡騎士、綠軍、猛龍等一大堆。對于這種特征,我們本文將其稱為多值離散特征。

根據(jù)DeepFM的思想,我們需要將每一個(gè)field的特征轉(zhuǎn)換為定長的embedding,即使有多個(gè)取值,也是要變換成定長的embedding。

那么,一種思路來了,比如一個(gè)用戶喜歡兩個(gè)球隊(duì),這個(gè)field的特征可能是[1,1,0,0,0,0,0.....0],那么我們使用兩次embedding lookup,再取個(gè)平均不就好了嘛。

嗯,這的確也許可能是一種思路吧,在tensorflow中,其實(shí)有一個(gè)函數(shù)能夠?qū)崿F(xiàn)我們上述的思路,那就是tf.nn.embedding_lookup_sparse。別著急,我們一步一步來實(shí)現(xiàn)多值離散特征的embedding處理過程。

2、解決方案

輸入數(shù)據(jù)

假設(shè)我們有三條數(shù)據(jù),每條數(shù)據(jù)代表一個(gè)user所喜歡的nba球員,比如有登哥,炮哥,杜老四,慕斯等等:

csv = [
  "1,harden|james|curry",
  "2,wrestbrook|harden|durant",
  "3,|paul|towns",
]

我們建立一個(gè)所有球員的集合:

TAG_SET = ["harden", "james", "curry", "durant", "paul","towns","wrestbrook"]

數(shù)據(jù)處理
這里我們需要一個(gè)得到一個(gè)SparseTensor,即多為稀疏矩陣的一種表示方式,我們只記錄非0值所在的位置和值。

比如說,下面就是我們對上面數(shù)據(jù)處理過后的一個(gè)SparseTensor,indices是數(shù)組中非0元素的下標(biāo),values跟indices一一對應(yīng),表示該下標(biāo)位置的值,最后一個(gè)表示的是數(shù)組的大小。

處理得到SparseTensor的完整代碼如下:

def sparse_from_csv(csv):
  ids, post_tags_str = tf.decode_csv(csv, [[-1], [""]])
  table = tf.contrib.lookup.index_table_from_tensor(
      mapping=TAG_SET, default_value=-1) ## 這里構(gòu)造了個(gè)查找表 ##
  split_tags = tf.string_split(post_tags_str, "|")
  return tf.SparseTensor(
      indices=split_tags.indices,
      values=table.lookup(split_tags.values), ## 這里給出了不同值通過表查到的index ##
      dense_shape=split_tags.dense_shape)

定義embedding變量

定義我們的embedding的大小為3:

TAG_EMBEDDING_DIM = 3
embedding_params = tf.Variable(tf.truncated_normal([len(TAG_SET), TAG_EMBEDDING_DIM]))

得到embedding值

將我們剛才得到的SparseTensor,傳入到tf.nn.embedding_lookup_sparse中,我們就可以得到多值離散特征的embedding值。

tags = sparse_from_csv(csv)
embedded_tags = tf.nn.embedding_lookup_sparse(embedding_params, sp_ids=tags, sp_weights=None)

sp_ids就是我們剛剛得到的SparseTensor,而sp_weights=None代表的每一個(gè)取值的權(quán)重,如果是None的話,所有權(quán)重都是1,也就是相當(dāng)于取了平均。如果不是None的話,我們需要同樣傳入一個(gè)SparseTensor,代表不同球員的喜歡權(quán)重。大家感興趣可以自己去嘗試。

測試輸出

最后我們來看看得到的效果:

with tf.Session() as s:
  s.run([tf.global_variables_initializer(), tf.tables_initializer()])
  print(s.run([embedded_tags]))

這只是一種解決方案,大家可以去探索更多的方法喲。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容