word2Vec 的主要目的是利用曝光量日志的大前提,得到每个商品在这个大前提下的商品指定维度的向量表示。
它的原理并不复杂,在代码层面的执行也很简明,下面就一起来看一下:
在代码中涉及到需要 word2vec 的地方包括 3 处:
w2v(log,'uid','good_id',flag,64)
w2v(log,'uid','advertiser',flag,64)
w2v(log,'uid','aid',flag,64)
以上代码的含义是:在曝光日志 log 中以用户编号 uid 为索引,对商品编号 good_id 进行 embedding 分解,分解为 64 维的向量。
log['good_id']=log['good_id'].fillna(-1).astype(int)
选择 log 中所有 'good_id' 的内容,将其中是空值的内容填充为 -1 。
sentence=[]
dic={}
day=0
log=log.sort_values(by='request_day')
log['day']=log['request_day']
对 log 中的值以 'request_day' 为索引进行排序。更新 'request_day' 列名为 “day”
for item in log[['day','uid','good_id']].values:
if day!=item[0]:
for key in dic:
sentence.append(dic[key])
dic={}
day=item[0]
try:
dic[item[1]].append(str(int(item[2])))
except:
dic[item[1]]=[str(int(item[2]))]
for key in dic:
sentence.append(dic[key])
从 log 中抽取出 'day','uid','good_id' 三列的内容,统计同一天内,相同用户点击过的不同商品到变量 sentence 中。得到的结果如下图:
from gensim.models import Word2Vec
random.shuffle(sentence)
model = Word2Vec(sentence, size=L, window=10, min_count=1, workers=10,iter=10)
对 sentence 中的内容进行随机乱序,利用 gensim 中的 Word2Vec 模型对 sentence 中记录的商品编号 good_id 进行矩阵分解。得到的结果就是每个商品编号 good_id 的 64 维向量表达。
这里需要详细的解释下 word2vec 里的 sentence 表示什么意义,为何要以用户编号对应的商品编号来作为 sentence 的输入?最后得到的分解内容又是什么?
首先回答第一个问题,之所以要以用户编号对应的商品编号来作为 sentence 的输入,我们可以把每一条用户选择了哪些商品点击的行为想象成一句表达,用这样的表达表述出了这个用户对哪些商品有这特别的偏爱。这样这个 sentence 就形成了一个大的背景,在这个大背景的前提下,每个商品编号就有了不同的分量,这个分量是由不同的用户选择表达出来的。
下面回答第二个问题,用 Word2Vec 对大背景 sentence 进行分解之后的中间产物,就是这其中每个商品编号 good_id 的权重表达,也就是每个商品在 sentence 大背景下的分量表示。而这个中间产物又恰好可以作为商品 good_id 的特征的一种表达,用在我们对其他目标的预测中,比如像本赛题的曝光量的预测,扩展开来,还可以用在很多其他的地方,只有想不到没有达不到!
values=set(log['good_id'].values)
w2v=[]
for v in values:
try:
a=[int(v)]
a.extend(model[str(v)])
w2v.append(a)
except:
pass
从模型中提取每个商品编号 good_id 的 64 维向量表示,填入到变量数组 w2v 中。最终将结果变成数据帧命名保存,后续的预测可以直接提取使用。
out_df=pd.DataFrame(w2v)
names=[f]
for i in range(L):
names.append(“uid“+'_w2v_embedding_'+'good_id'+'_'+str(L)+'_'+str(i))
out_df.columns = names
out_df.to_pickle('data/' +“uid“+'_'+ 'good_id' +'_'+flag +'_w2v_'+str(L)+'.pkl')