推薦系統(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]))
這只是一種解決方案,大家可以去探索更多的方法喲。