推荐系统遇上深度学习 (四)-- 多值离散特征的 embedding 解决方案



转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com

AIQ 机器学习大数据 知乎专栏 点击关注

原文发布于微信公众号 - 小小挖掘机(wAIsjwj)
原文发表时间:2018.04.21 23:27

1、背景

在本系列第三篇文章中,在处理 DeepFM 数据时,由于每一个离散特征只有一个取值,因此我们在处理的过程中,将原始数据处理成了两个文件,一个记录特征的索引,一个记录了特征的值,而每一列,则代表一个离散特征。

但假如,我们某一个离散特征有多个取值呢?举个例子来说,每个人喜欢的 NBA 球队,有的人可能喜欢火箭和湖人,有的人可能只喜欢勇士,也有的人喜欢骑士、绿军、猛龙等一大堆。对于这种特征,我们本文将其称为多值离散特征。

根据 DeepFM 的思想,我们需要将每一个 field 的特征转换为定长的 embedding,即使有多个取值,也是要变换成定长的 embedding。

那么,一种思路来了,比如一个用户喜欢两个球队,这个 field 的特征可能是 [1,1,0,0,0,0,0…..0],那么我们使用两次 embedding lookup,再取个平均不就好了嘛。

嗯,这的确也许可能是一种思路吧,在 tensorflow 中,其实有一个函数能够实现我们上述的思路,那就是 tf.nn.embedding_lookup_sparse。别着急,我们一步一步来实现多值离散特征的 embedding 处理过程。

2、解决方案

输入数据

假设我们有三条数据,每条数据代表一个 user 所喜欢的 nba 球员,比如有登哥,炮哥,杜老四,慕斯等等:

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

我们建立一个所有球员的集合:

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

数据处理

这里我们需要一个得到一个 SparseTensor,即多为稀疏矩阵的一种表示方式,我们只记录非 0 值所在的位置和值。

比如说,下面就是我们对上面数据处理过后的一个 SparseTensor,indices 是数组中非 0 元素的下标,values 跟 indices 一一对应,表示该下标位置的值,最后一个表示的是数组的大小。

处理得到 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) ## 这里构造了个查找表 ##
 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 代表的每一个取值的权重,如果是 None 的话,所有权重都是 1,也就是相当于取了平均。如果不是 None 的话,我们需要同样传入一个 SparseTensor,代表不同球员的喜欢权重。大家感兴趣可以自己去尝试。

测试输出

最后我们来看看得到的效果:

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

这只是一种解决方案,大家可以去探索更多的方法哟。


更多高质资源 尽在AIQ 机器学习大数据 知乎专栏 点击关注

转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com