前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于word2vec协同过滤推荐

基于word2vec协同过滤推荐

作者头像
刘笑江
发布2018-05-28 12:40:27
3.2K0
发布2018-05-28 12:40:27
举报
文章被收录于专栏:刘笑江的专栏刘笑江的专栏

引言

在文章 学习协同过滤推荐 \w 100行Python代码 中,介绍了基于物品的协同过滤推荐,根据 user-item 评分矩阵,找出与给定 item 评分最接近的物品,作为推荐结果。

在本文中,把书籍名称看作单词,以用户喜欢的书籍看作句子,利用 word2vec 模型构建了一个书籍的向量空间。对给定书籍,找出与其距离最近的书籍,作为推荐结果。

本文用 Python 60 行代码实现了一个 Demo,得到每本书籍在向量空间的表示,输出基于书籍的协同过滤推荐结果。

word2vec

简介

word2vec,是 Google 的 Mikolov 等人在 NIPS2013 发表的论文 Efficient Estimation of Word Representations in Vector Space 提出的模型,包括 Skip-gram 和 CBOW (Continuous Bag-of-Words) ,如下图所示。

fig1
fig1

word2vec 在没有词性标注的情况下,能够从原始语料学习到单词的向量表示,比较单词间的语义、句法的相似性。例如:

vector("King") - vector("Man") + vector("Woman") ≈ vector("Queen")

利用模型的特点,我们可以把书籍看作单词,把每个用户喜欢的书籍序列看作句子,用这些数据训练 word2vec 模型,得到每本书籍的向量表示。在推荐时,根据用户在读书籍 ,在向量空间中找到与其距离相近的书籍作为推荐。

与 Item-CF 相比,word2vec 在推荐时更加灵活,书籍向量可以相加、相减,能够更灵活地满足个性化推荐需求。例如,根据用户 amy 最近喜欢的《浪潮之巅》,考虑到他以前喜欢《从0到1》,不喜欢《寻路中国》,可以这样计算推荐书籍:

vector("浪潮之巅") + vector("从0到1") - vector("寻路中国") ≈ vector("推荐书籍")

CBOW

输入层

假设窗口=5,对输入单词向量求和

结果 xxx 进入输出层

输出层

在 CBOW 模型中,输出层是 hierarchical softmax,以霍夫曼树的叶子节点表示输出单词。用霍夫曼树使得叶子节点的输出概率,累加和等于一。

对第 jjj 个非叶子节点,有待训练的参数 θj\theta_jθ​j​​,输入纯量 xxx选择左、右分支的概率

叶子节点输出纯量

x⋅sign(x,θj)

对每个进入输出层的纯量 xxx,按以上方法递归地求得输出

代价函数

那么有

于是 θ\thetaθ 的更新公式

其中,η\etaη 是学习速率

同理得 x的梯度公式

因为 xwx_wx​w​​ 是多个单词向量 vvv 的累加,所以每轮迭代每个单词向量 vvv 的更新方法

Skip-gram

输入为一个单词向量,经过 continuous projection layer,输入到 log-linear classifier,得到前 n、后 n 个单词。

用同样方法,得到损失函数、损失函梯度函数、更新函数后,用 随机梯度下降(Stochastic Gradien Descent)算法得到估计参数 θ\thetaθ 、单词向量 v(w)v(w)v(w)。

本文借助 gensim 包,完成上述的训练过程。

数据准备

准备 user_prefs.txt

代码语言:javascript
复制
david 百年孤独
david 霍乱时期的爱情
david 从0到1
andy 霍乱时期的爱情
jack 浪潮之巅
jack 失控
jack 创业维艰
michale 寻路中国:从乡村到工厂的自驾之旅
michale 背包十年:我的职业是旅行
ann 活着
ann 霍乱时期的爱情
ann 迟到的间隔年
joel 巨人的陨落:世纪三部曲
joel 中国历代政治得失
joel 人类简史:从动物到上帝
joel 失控
jim 背包十年:我的职业是旅行
jim 迟到的间隔年
ray 霍乱时期的爱情
ray 迟到的间隔年
ray 枪炮、病菌与钢铁:人类社会的命运

训练模型

安装 gensim 包

代码语言:javascript
复制
brew install pip3
pip3 install gesim

训练模型

代码语言:javascript
复制
#!/usr/sbin/python3
#-*- encoding:utf-8 -*-
from gensim.models.word2vec import *

model_file = 'word2vec.model'

with open('user_prefs.txt') as f:
    prefs_str = ''.join(f.readlines())

# {'andy': {'霍乱时期的爱情': 1},...}
def read_prefs(prefs_str):
    prefs = {}
    for line in prefs_str.split('\n'):
        parts = line.rstrip().split()
        if len(parts) == 2:
            userId, itemId = parts
            prefs.setdefault(userId, {})
            prefs[userId].update({itemId:1})
    return prefs

prefs = read_prefs(prefs_str)

def sents_from_prefs(prefs):
    sents = []
    for v in prefs.values():
        sent = ''
        for b in v.keys():
            sent += ' ' + b.replace(' ', '')
        sents.append(sent)
    return sents

def flatMap(vocab):
    ret = []
    for i in vocab:
        if type(i) == type('a'):
            ret.append(i)
        elif type(i) == type([]):
            for j in i:
                ret.append(j)
    return ret

def calc_item_cf():
    sents = sents_from_prefs(prefs)
    vocab = [s.split() for s in sents]
    model = Word2Vec(vocab, size=100, window=5, min_count=1, workers=4)
    model.save_word2vec_format(model_file, binary=False)
    model = Word2Vec.load_word2vec_format(model_file, binary=False)

    print('基于书籍的 word2vec 协同过滤推荐')
    for item in flatMap(vocab):
        print('\n根据 %s 推荐:' % item)
        for item_score in model.most_similar(positive=[item]):
            item, score = item_score
            print('\t%s %.2f' % (item, score))

calc_item_cf()

输出结果

书籍的向量表示保存在 word2vec.model 文件:

代码语言:javascript
复制
14 100
霍乱时期的爱情 -0.000769 -0.003323 -0.001202 -0.000913 0.003399 -0.001411 -0.003035 0.002229 0.004558 0.001640 ...
迟到的间隔年 -0.004531 0.004115 -0.004905 0.004209 -0.002952 0.002481 0.001582 ...

推荐结果:

代码语言:javascript
复制
基于书籍的 word2vec 协同过滤推荐

根据 背包十年:我的职业是旅行 推荐:
    迟到的间隔年 0.22
    人类简史:从动物到上帝 0.11
    失控 0.09
    枪炮、病菌与钢铁:人类社会的命运 0.09
    浪潮之巅 0.07
    霍乱时期的爱情 0.07
    中国历代政治得失 0.06
    寻路中国:从乡村到工厂的自驾之旅 0.05
    巨人的陨落:世纪三部曲 0.03
    活着 0.03

根据 枪炮、病菌与钢铁:人类社会的命运 推荐:
    百年孤独 0.20
    迟到的间隔年 0.16
    中国历代政治得失 0.09
    背包十年:我的职业是旅行 0.09
    失控 0.06
    巨人的陨落:世纪三部曲 0.06
    创业维艰 -0.02
    活着 -0.03
    浪潮之巅 -0.03
    从0到1 -0.09

根据 从0到1 推荐:
    百年孤独 0.08
    浪潮之巅 0.06
    中国历代政治得失 0.03
    寻路中国:从乡村到工厂的自驾之旅 0.03
    创业维艰 -0.03
    迟到的间隔年 -0.07
    失控 -0.07
    巨人的陨落:世纪三部曲 -0.07
    霍乱时期的爱情 -0.08
    背包十年:我的职业是旅行 -0.09

根据 寻路中国:从乡村到工厂的自驾之旅 推荐:
    活着 0.14
    背包十年:我的职业是旅行 0.05
    人类简史:从动物到上帝 0.03
    从0到1 0.03
    霍乱时期的爱情 0.03
    创业维艰 -0.03
    中国历代政治得失 -0.03
    百年孤独 -0.07
    浪潮之巅 -0.10
    迟到的间隔年 -0.10

根据 霍乱时期的爱情 推荐:
    人类简史:从动物到上帝 0.20
    巨人的陨落:世纪三部曲 0.17
    中国历代政治得失 0.07
    背包十年:我的职业是旅行 0.07
    寻路中国:从乡村到工厂的自驾之旅 0.03
    活着 0.02
    失控 -0.01
    创业维艰 -0.07
    从0到1 -0.08
    浪潮之巅 -0.10

根据 创业维艰 推荐:
    浪潮之巅 0.14
    活着 0.11
    中国历代政治得失 0.01
    巨人的陨落:世纪三部曲 -0.01
    百年孤独 -0.02
    枪炮、病菌与钢铁:人类社会的命运 -0.02
    迟到的间隔年 -0.03
    从0到1 -0.03
    寻路中国:从乡村到工厂的自驾之旅 -0.03
    失控 -0.05

根据 中国历代政治得失 推荐:
    活着 0.19
    枪炮、病菌与钢铁:人类社会的命运 0.09
    霍乱时期的爱情 0.07
    失控 0.06
    背包十年:我的职业是旅行 0.06
    百年孤独 0.04
    迟到的间隔年 0.04
    从0到1 0.03
    创业维艰 0.01
    巨人的陨落:世纪三部曲 -0.01

根据 巨人的陨落:世纪三部曲 推荐:
    人类简史:从动物到上帝 0.17
    霍乱时期的爱情 0.17
    浪潮之巅 0.13
    迟到的间隔年 0.07
    枪炮、病菌与钢铁:人类社会的命运 0.06
    背包十年:我的职业是旅行 0.03
    失控 0.01
    创业维艰 -0.01
    中国历代政治得失 -0.01
    从0到1 -0.07

根据 失控 推荐:
    背包十年:我的职业是旅行 0.09
    迟到的间隔年 0.07
    中国历代政治得失 0.06
    枪炮、病菌与钢铁:人类社会的命运 0.06
    浪潮之巅 0.03
    人类简史:从动物到上帝 0.02
    巨人的陨落:世纪三部曲 0.01
    霍乱时期的爱情 -0.01
    百年孤独 -0.04
    创业维艰 -0.05

根据 人类简史:从动物到上帝 推荐:
    霍乱时期的爱情 0.20
    巨人的陨落:世纪三部曲 0.17
    背包十年:我的职业是旅行 0.11
    寻路中国:从乡村到工厂的自驾之旅 0.03
    失控 0.02
    浪潮之巅 -0.01
    迟到的间隔年 -0.05
    百年孤独 -0.07
    中国历代政治得失 -0.09
    从0到1 -0.09

根据 活着 推荐:
    中国历代政治得失 0.19
    寻路中国:从乡村到工厂的自驾之旅 0.14
    创业维艰 0.11
    背包十年:我的职业是旅行 0.03
    霍乱时期的爱情 0.02
    浪潮之巅 0.02
    枪炮、病菌与钢铁:人类社会的命运 -0.03
    迟到的间隔年 -0.05
    失控 -0.05
    百年孤独 -0.07

根据 浪潮之巅 推荐:
    创业维艰 0.14
    巨人的陨落:世纪三部曲 0.13
    背包十年:我的职业是旅行 0.07
    从0到1 0.06
    失控 0.03
    活着 0.02
    人类简史:从动物到上帝 -0.01
    枪炮、病菌与钢铁:人类社会的命运 -0.03
    中国历代政治得失 -0.08
    百年孤独 -0.09

根据 迟到的间隔年 推荐:
    背包十年:我的职业是旅行 0.22
    枪炮、病菌与钢铁:人类社会的命运 0.16
    百年孤独 0.10
    失控 0.07
    巨人的陨落:世纪三部曲 0.07
    中国历代政治得失 0.04
    创业维艰 -0.03
    活着 -0.05
    人类简史:从动物到上帝 -0.05
    从0到1 -0.07

根据 百年孤独 推荐:
    枪炮、病菌与钢铁:人类社会的命运 0.20
    迟到的间隔年 0.10
    从0到1 0.08
    中国历代政治得失 0.04
    创业维艰 -0.02
    失控 -0.04
    寻路中国:从乡村到工厂的自驾之旅 -0.07
    活着 -0.07
    人类简史:从动物到上帝 -0.07
    浪潮之巅 -0.09

附录

https://github.com/liuslevis/CFDemo 完整源码

http://www.shareditor.com/blogshow/?blogId=100 自己动手做聊天机器人 二十五-google的文本挖掘深度学习工具word2vec的实现原理

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • word2vec
    • 简介
      • CBOW
        • 输入层
        • 输出层
        • 代价函数
      • Skip-gram
      • 数据准备
      • 训练模型
      • 输出结果
      • 附录
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档