现现在,网站用推荐系统为你提供个性化的体验,告诉你买啥,吃啥甚至你应该和谁交朋友。尽管每一个人口味不一样,但大致都适用这个套路。人们倾向于喜欢那些与本身喜欢的其余东西类似的东西,也倾向于与本身身边的人有类似的口味。推荐系统就尝试捕捉这一规律来帮助预测你也可能喜欢的其余东西。css
为帮用户高效挑选商品,电子商务、社交媒体、视频和在线新闻平台已积极部署了他们本身的推荐系统,这是一个共赢的策略。html
推荐系统两个最广泛的类型是基于内容过滤法和协同过滤法。协同过滤法基于用户对商品的评价信息来产生推荐,是用大众的智慧来推荐内容。相比之下,基于内容推荐系统关注的是商品的属性,基于它们之间的类似度给你推荐。python
大致上,协同过滤(CF)是推荐引擎工做的是主力。这一算法有一个颇有趣的特色,它可以自主学习,这意味着它可以开始学习哪些特色能为己所用。协同过滤又可分为基于内存的协同过滤和基于模型的协同过滤。在此教程中,你将实现运用奇异值分解的基于模型协同过滤法和经过计算余弦类似性的基于内存协同过滤法。算法
咱们将使用MovieLens数据集,这是用来实现和测试推荐引擎最广泛的数据集之一。它包含来自于943个用户的10万个电影评价和1682部电影集合。你最好将这个数据集(MoviesLens-100k)解压到你的notebook目录。
函数
1
2
|
import
numpy as np
import
pandas as pd
|
u.data文件中包含了完整数据集。你能够在这里查阅关于这个数据集的简要描述post
1
2
|
header
=
[
'user_id'
,
'item_id'
,
'rating'
,
'timestamp'
]
df
=
pd.read_csv(
'ml-100k/u.data'
, sep
=
'\t'
, names
=
header)
|
先看一眼数据集中的前两行。接下来,让咱们统计其中的用户和电影总数。性能
n_users = df.user_id.unique().shape[0] n_items = df.item_id.unique().shape[0] print 'Number of users = ' + str(n_users) + ' | Number of movies = ' + str(n_items)
Number of users = 943 | Number of movies = 1682
你可使用scikit-learn文库将数据集分为测试和训练两部分。Cross_validation.train_test_split
模块根据测试样本的百分比将数据混合并分为两部分,在这里百分比为0.25学习
from sklearn import cross_validation as cv train_data, test_data = cv.train_test_split(df, test_size=0.25)
基于内存协同过滤法
基于内存协同过滤法能够被主要分为两部分:用户-项目过滤(user-item filtering)和项目-项目过滤( item-item filtering)。 user-item filtering选取一个特定用户,基于评价类似性找到与该用户类似的其余用户,并推荐那些类似用户所喜欢的项目。相比之下, item-item filtering 先选取一个项目,而后找出也喜欢这个项目的其余用户,并找出这些用户或类似用户也喜欢的其余项目,推荐过程须要项目并输出其余项目。测试
- Item-Item Collaborative Filtering: “Users who liked this item also liked …”
- User-Item Collaborative Filtering: “Users who are similar to you also liked …”
在这两种状况中,你根据整个数据集建立了一个用户-项目的矩阵。由于已经把数据分红了测试和训练两部分因此你须要建立两个[943 x 1682]矩阵。训练矩阵包含75%的评价,测试矩阵包含25%的矩阵。网站
用户-项目矩阵例子:
建立了用户-项目矩阵以后,计算类似性并建立一个类似度矩阵。
Item-Item Collaborative Filtering算法中项目之间的类似度依靠观测全部的已对相同项目评价的用户来测算。
对于User-Item Collaborative Filtering算法,用户之间的类似性依靠观测相同用户已评价的全部项目。
推荐系统中一般使用余弦类似性做为距离度量,在n维孔空间中评价被视为向量,基于这些向量之间的夹角来计算类似性。
用户a和m能够用下面的公式计算余弦类似性,其中你可使用用户向量uk和ua之间的点积而后除以这两个向量欧式长度之乘。
而计算项目m和b之间的类似度能够用下面的公式:
首先建立user-item矩阵,所以你须要建立两个矩阵为测试和训练数据集。
1
2
3
4
5
6
7
8
|
#Create two user-item matrices, one for training and another for testing
train_data_matrix
=
np.zeros((n_users, n_items))
for
line
in
train_data.itertuples():
train_data_matrix[line[
1
]
-
1
, line[
2
]
-
1
]
=
line[
3
]
test_data_matrix
=
np.zeros((n_users, n_items))
for
line
in
test_data.itertuples():
test_data_matrix[line[
1
]
-
1
, line[
2
]
-
1
]
=
line[
3
]
|
你可使用 sklearn
的pairwise_distances函数来计算余弦类似性。注意,由于评价都为正值输出取值应为0到1.
1
2
3
|
from
sklearn.metrics.pairwise
import
pairwise_distances
user_similarity
=
pairwise_distances(train_data_matrix, metric
=
'cosine'
)
item_similarity
=
pairwise_distances(train_data_matrix.T, metric
=
'cosine'
)
|
下一步是做出预测。既然构造了类似度矩阵user_similarity
和item_similarity,
所以你能够运用下面的公式为user-based CF作一个预测:
用户k和用户a之间的类似度根据一个类似用户a的一系列评价的乘积(修正为该用户的平均评价)的权重。你将须要标准化类似度这样可使评价维持在1到5之间,最后一步,统计你想预测用户平均评价的总和。
这里考虑到的问题是一些用户评价全部电影时可能要么给最高分,要么给最低分。这些用户给出评价的相对不一样比绝对值更重要。例如:设想,用户k对他最喜欢的电影评价4颗星,其余的好电影则评价3颗星。假设如今另外一个用户t对他/她喜欢的一部电影评价为5颗星,看了想睡觉的一部电影评价为3颗星。这两位用户电影口味可能很类似但使用评价体系的方法不一样。
当为item-based CF作一个推荐时候,你不要纠正用户的平均评价,由于用户自己用查询来作预测。
1
2
3
4
5
6
7
8
9
|
def
predict(ratings, similarity,
type
=
'user'
):
if
type
=
=
'user'
:
mean_user_rating
=
ratings.mean(axis
=
1
)
#You use np.newaxis so that mean_user_rating has same format as ratings
ratings_diff
=
(ratings
-
mean_user_rating[:, np.newaxis])
pred
=
mean_user_rating[:, np.newaxis]
+
similarity.dot(ratings_diff)
/
np.array([np.
abs
(similarity).
sum
(axis
=
1
)]).T
elif
type
=
=
'item'
:
pred
=
ratings.dot(similarity)
/
np.array([np.
abs
(similarity).
sum
(axis
=
1
)])
return
pred
|
item_prediction = predict(train_data_matrix, item_similarity, type='item') user_prediction = predict(train_data_matrix, user_similarity, type='user')
评估
有许多的评价指标,可是用于评估预测精度最流行的指标之一是Root Mean Squared Error (RMSE)。
你能够用sklearn中的 mean_square_error
(MSE)函数,RMSE只是MSE其中的一个平方根。想阅读更多关于不一样评估指标你能够 查看这篇文章。
由于你仅仅想考虑在这个测试数据集中的预测评价,你能够用prediction[ground_truth.nonzero()]过滤测试矩阵中全部其余的元素。
1
2
3
4
5
6
|
from
sklearn.metrics
import
mean_squared_error
from
math
import
sqrt
def
rmse(prediction, ground_truth):
prediction
=
prediction[ground_truth.nonzero()].flatten()
ground_truth
=
ground_truth[ground_truth.nonzero()].flatten()
return
sqrt(mean_squared_error(prediction, ground_truth))
|
1
2
|
print
'User-based CF RMSE: '
+
str
(rmse(user_prediction, test_data_matrix))
print
'Item-based CF RMSE: '
+
str
(rmse(item_prediction, test_data_matrix))
|
1
2
|
User
-
based CF RMSE:
3.1236202241
Item
-
based CF RMSE:
3.44983070639
|
Memory-based算法容易实施并产生合理的预测质量。memory-based CF的缺点是它不能扩展到现实世界的场景和没有处理众所周知的冷启动问题(面对新用户或者新项目进去系统时)。Model-based CF方法可伸缩而且能处理 比memory-based方法更高等级的稀疏度,面对新用户或者没有任何评价的新项目进入系统时也会变差。我想感谢Ethan Rosenthal关于Memory-Based Collaborative Filtering的博客。
Model-based Collaborative Filtering
基于模型的协同过滤是基于已收到更大的曝光,主要是做为潜变量分解和降维无监督的学习方法矩阵分解(MF)
Model-based Collaborative Filtering基于已收到不少曝光的矩阵因式分解 (MF),主要是做为潜在变量分解和降维无监督学习方法。矩阵因式分解因其能比Memory-based CF更好解决可扩展性和稀疏问题而被普遍用于推荐系统。MF的目标是学习用户潜在的喜爱和从已知评分的项目的潜在属性(学习描述评分特征的特色),以随后经过用户和项目的潜在特征点积预测未知的评分。
当你有一个多维度稀疏矩阵,经过矩阵因式分解你可以将用户-项目矩阵(user-item matrix)重构成低评分结构(low-rank structure),而且你可以经过两个低评分( low-rank)矩阵相乘得出这个矩阵,其中矩阵的行包含潜在向量。
经过低评价矩阵乘积尽量调整这个矩阵近似原始矩阵,以填充原始矩阵中缺失的项。
如今开始计算MovieLens 数据集的稀疏等级:
1
2
|
sparsity
=
round
(
1.0
-
len
(df)
/
float
(n_users
*
n_items),
3
)
print
'The sparsity level of MovieLens100K is '
+
str
(sparsity
*
100
)
+
'%'
|
1
|
The sparsity level of MovieLens100K
is
93.7
%
|
举个例子说明学习用户和项目的潜在喜爱:就拿MovieLens数据集来讲你有一下信息:(用户ID,年龄,地理位置,性别,电影ID,导演,演员,语言,年份,评分)。经过运用矩阵因式分解这个模型学习到重要的用户特征是年龄段(10岁如下、10-18岁、18-30岁、30-90岁)、地理位置和 性别,对电影特征它学习到最重要的是年代、导演和演员。如今若是你回过头来看你已经存储的信息,没有诸如年代等的特征,可是这个模型能够本身学习到。重要的方面是CF模型仅需使用数据(用户ID,电影ID,评分)来学习这些潜在的特征。若是没有数据可用CF模型性能将会不好,由于这样它更困难学习这些潜在的特征。
评分和特征都要使用的模型称为混合推荐系统(Hybrid Recommender Systems),它是Collaborative Filtering 和Content-based 模型二者的结合。混合推荐系统一般比Collaborative Filtering 或者Content-based模型独立地表现出更高的精度:它们可以更好地处理冷启动问题(由于若是你没有可用于数据集的对于用户或项目的任何评价你就很难作出预测)。混合推荐系统将在下一篇介绍中介绍。
SVD
一个知名的矩阵因式分解方法是Singular value decomposition (SVD)。Collaborative Filtering 协同过滤能够经过使用奇异值分解近似矩阵X被配制