前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >推荐系统

推荐系统

作者头像
杨熹
发布2018-04-02 17:12:23
1.1K0
发布2018-04-02 17:12:23
举报
文章被收录于专栏:杨熹的专栏杨熹的专栏
本文结构:
  1. 推荐系统
  2. 常用方法
    1. 简介
    2. 模型 cost, gradient 表达式
    3. 代码实现
  3. 应用实例

参考: Coursera-Andrew Ng 的 Machine Learning Sirajology 的 Recommendation Systems - Learn Python for Data Science


1. 推荐系统

根据用户的兴趣特点和购买行为,向用户推荐用户感兴趣的信息和商品。 为用户节省时间,还能挖掘可能用户自己都不知道的潜在兴趣点。

生活中的例子:喜马拉雅上根据我听过的书推荐相关的内容,效果不错,推荐的很多我都会订阅。Youtube上根据我看过的视频推荐内容,如果我在追剧,它会把最新的剧集放在我首页,还有我可能感兴趣的电影。

还有很多例子和方法,以及冷启动等关键问题,推荐大家看《推荐系统实战》这本书,之前去听新浪微博的分享,这本书是他们推荐系统部门的必备材料。


2. 常用模型

方法有基于内容,基于物品,基于用户和协同过滤等。

基于内容,物品,用户的推荐就是把相关的特征表达为向量形式后,计算它们之间的距离,根据相似度高的来为你推荐。

基于内容,例如,要判断文章间的相似性,就可以把每篇文章,按照它里面用到的单词,把一篇文章表达为向量的形式,然后计算文章之间的距离。

如果我们有一个用户对物品的打分矩阵,那么通过计算行向量间的距离,可以计算出物品之间的相似性,计算列向量的距离,可以得到用户间的相似性。

根据距离的定义公式,计算出向量间的距离,找到最相近的几个对象,再取平均值就可以作为预测值。

协同过滤

我们要解决一个推荐问题时,很自然的可以想到,用户为什么喜欢这些物品,应该是因为这些物品具有某些特点,而用户刚好对这些特点感兴趣。

但具体是哪些特点呢,每个特点又该用什么值来量化呢,这一步可能并不好做。协同过滤就可以提供一个解决方案,即使你并不知道这些特点都有什么,即使你并不知道各个特点都是多少值,你仍然可以得到预测结果。

它的模型表示为,x\_i 为电影 i 具有的特点向量,y\_j 为用户 j 对所有特点的偏好值向量。二者相乘就得到用户 j 对电影 i 的打分,然后可以用来和实际分数进行比较:

  1. 写出所有用户对所有电影的预测分数与实际分数的平方差公式,再加上 theta 和 x 的正则项,就得到了目标函数,我们要使这个函数达到最小值。
  1. 然后计算 cost function 对 theta 和 x 的偏导:
  1. 接着可以用梯度下降法迭代求 cost function 的最小值。

最后可以用计算得到的 theta 和 x 相乘,得到打分矩阵中未知的部分。


3. 代码实现

下面是用 matlab 实现的协同过滤。 其中的计算大多用矩阵表达,这样比写循环要快而且简洁,代码很简单,也可以很容易地用python写出来。

完整代码链接

1. 引入数据

图中可见用户对电影的评分热点图。

代码语言:javascript
复制
%  Load data
load ('ex8_movies.mat');

imagesc(Y);
ylabel('Movies');
xlabel('Users');

2. 写出 cost function 和 gradient 的表达式

其中 J 为 cost function,X\_grad,Theta\_grad 为相应的梯度。 先写了没有正则项的形式,在这基础上又加上了正则项,当然可以合二为一直接写带有正则项的。

需要注意的是,在数据矩阵中,我们只将有打分的地方拿来计算, 所以在代码中我们用 R 点乘误差矩阵,这个 R 的意思,R(i, j) = 1 时,说明用户 j 对电影 i 有评分,为 0 时就是没有打分。

代码语言:javascript
复制
function [J, grad] = cofiCostFunc(params, Y, R, num_users, num_movies, ...
                                  num_features, lambda)

% Unfold the U and W matrices from params
X = reshape(params(1:num_movies*num_features), num_movies, num_features);
Theta = reshape(params(num_movies*num_features+1:end), ...
                num_users, num_features);

% ========= without Regularization
M = X*Theta'-Y;
Z = R.*M;   
J = 0.5 * sum( sum(Z.*Z) );

M_grad = X*Theta'-Y;
Z_grad = R.* M_grad;
X_grad = ( Z_grad )*Theta;   
Theta_grad = ( Z_grad )'*X; 

% ========= Regularization

Theta_regu = sum( sum(Theta.*Theta) )*lambda/2;
X_regu = sum( sum(X.*X) )*lambda/2;
J = J + Theta_regu + X_regu;

X_grad = X_grad + lambda*X;
Theta_grad = Theta_grad + lambda*Theta;


% Fold the U and W matrices to params
grad = [X_grad(:); Theta_grad(:)];

end

3.用随机梯度下降来训练模型

先随机初始化 X 和 Theta。 定义 'MaxIter' 迭代次数和 'lambda' 正则项之后, 调用 'fmincg' 训练模型,得到 cost function 达到最小时对应的 X 和 Theta。

代码语言:javascript
复制
% Set Initial Parameters (Theta, X)
X = randn(num_movies, num_features);
Theta = randn(num_users, num_features);

initial_parameters = [X(:); Theta(:)];

% Set options for fmincg
options = optimset('GradObj', 'on', 'MaxIter', 100);

% Set Regularization
lambda = 10;
theta = fmincg (@(t)(cofiCostFunc(t, Y, R, num_users, num_movies, ...
                                num_features, lambda)), ...
                initial_parameters, options);

% Unfold the returned theta back into U and W
X = reshape(theta(1:num_movies*num_features), num_movies, num_features);
Theta = reshape(theta(num_movies*num_features+1:end), ...
                num_users, num_features);

4.得到预测值

用 X * Theta' 得到预测值,其中第一列是目标用户的向量。 再根据打分进行排序,输出前10个推荐影片。

代码语言:javascript
复制
p = X * Theta';
my_predictions = p(:,1) + Ymean;

movieList = loadMovieList();

[r, ix] = sort(my_predictions, 'descend');
fprintf('\\nTop recommendations for you:\\n');
for i=1:10
    j = ix(i);
    fprintf('Predicting rating %.1f for movie %s\\n', my_predictions(j), ...
            movieList{j});
end

4. 用 python 的 lightFM 库实现

完整代码见 Sirajology 的 Github

今天会用到三个库, Numpy, Scipy, LightFM。 先从 lightfm 这个库里引入需要的数据,还有 LightFM 用来构建模型。

代码语言:javascript
复制
import numpy as np
from lightfm.datasets import fetch_movielens
from lightfm import LightFM

接下来导入数据。 它有1k的用户对1700部电影的100k的评分数据。每个用户对二十个左右的电影进行评分,分数由1到5,以字典的形式存储。

代码语言:javascript
复制
#fetch data and format it
data = fetch_movielens(min_rating=4.0)

接下来建立模型 定义它的损失函数为 wrap,即给定一个用户来找到与他相似的用户,并且得到他们喜欢的电影的排序,用这个排序作为对新用户的预测。用 fit 函数来训练模型。

代码语言:javascript
复制
#create model
model = LightFM(loss='warp')
#train model
model.fit(data['train'], epochs=30, num_threads=2)

接下来就是建立推荐的函数 sample_recommendation

先从训练数据中得到我们有多少个用户和电影。 对每个用户,取到他们已经喜欢的电影的前三个, 再取 model.predict 得到的预测值中,排名前三的 top_items。 打印出来可以观察一下。

代码语言:javascript
复制
def sample_recommendation(model, data, user_ids):

    #number of users and movies in training data
    n_users, n_items = data['train'].shape

    #generate recommendations for each user we input
    for user_id in user_ids:

        #movies they already like
        known_positives = data['item_labels'][data['train'].tocsr()[user_id].indices]

        #movies our model predicts they will like
        scores = model.predict(user_id, np.arange(n_items))
        
        #rank them in order of most liked to least
        top_items = data['item_labels'][np.argsort(-scores)]

        #print out the results
        print("User %s" % user_id)
        print("     Known positives:")

        for x in known_positives[:3]:
            print("        %s" % x)

        print("     Recommended:")

        for x in top_items[:3]:
            print("        %s" % x)

在调用函数时只需要传入 model,data 和 user_ids 即可。

代码语言:javascript
复制
sample_recommendation(model, data, [3, 25, 450])
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.11.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 推荐系统
  • 2. 常用模型
    • 协同过滤
    • 3. 代码实现
    • 4. 用 python 的 lightFM 库实现
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档