1.什么是协同过滤?
我先举一个例子,有一天,你想去看电影了,但你不知道有什么电影好看,然后你可能就会问问你的朋友们,看看有什么好看的电影推荐,这时候大部分人都会倾向于问跟你有品味差不多的人。而这也就是协同过滤的核心思想。
一般来说,协同过滤推荐分为三种类型。第一种是基于用户(user-based)的协同过滤,第二种是基于项目(item-based)的协同过滤,第三种是基于模型(model based)的协同过滤。
2.基于用户(user-based)的协同过滤
基于用户的协同过滤的基本原理是,根据所有用户对物品或者信息的偏好,发现与当前用户口味和偏好相似的用户群,然后基于这些用户的历史偏好,为当前用户进行推荐。
基于用户的协同过滤原理图
假设用户A喜欢物品A、物品C,用户B喜欢物品B,用户C喜欢物品A、物品C和物品D。从这些用户的历史偏好中,我们可以看出用户A和用户C的偏好是类似的。同时我们可以看到用户C喜欢物品D,所以我们可以猜想用户A可能也喜欢物品D,因此可以把物品D推荐给用户A。
3.基于物品(item-based)的协同过滤
基于物品的协同过滤推荐的基本原理也是类似的,只是它使用所有用户对物品或者信息的偏好,发现物品和物品之间的相似度,然后根据用户的历史偏好信息,将类似的物品推荐给当前用户。
基于项目的协调过滤原理图
假设用户A喜欢物品A、物品C,用户B喜欢物品A、物品B和物品C,用户C喜欢物品A。从这些用户的历史偏好中,我们可以分析出物品A和物品C是比较相似的,因此我们可以把物品C推荐给用户C。
UserCF和ItemCF的比较
Item CF是利用物品间的相似性来推荐的,所以假如用户的数量远远超过物品的数量,那么可以考虑使用Item CF,比如购物网站,因其物品的数据相对稳定,因此计算物品的相似度时不但计算量较小,而且不必频繁更新;User CF更适合做新闻、博客或者微内容的推荐系统,因为其内容更新频率非常高,特别是在社交网络中,User CF是一个更好的选择,可以增加用户对推荐解释的信服程度。
4.基于模型(model based)的协同过滤。
基于模型的协同过滤是目前最流行的协同过滤类型,我们这里主要是对其思想做有一个归类概括。我们的问题是这样的m个物品,n个用户的数据,只有部分用户和部分数据之间是有评分数据的,其它部分评分是空白,此时我们要用已有的部分稀疏数据来预测那些空白的物品和数据之间的评分关系,找到最高评分的物品推荐给用户。
对于这个问题,用机器学习的思想来建模解决,主流的方法可以分为:用关联算法,聚类算法,分类算法,回归算法,矩阵分解,神经网络,图模型以及隐语义模型来解决。
5.代码
首先导入我们的数据
import numpy as np
import pandas as pd
# 读取u.data文件
header = ['user_id', 'item_id', 'rating', 'timestamp']
df = pd.read_csv('./ml-100k/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库将数据集分割成测试和训练。train_test_split根据测试样本的比例(test_size)
# ,本例中是0.2,来将数据混洗并分割成两个数据集
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(df, test_size=0.2)
# 基于内容的协同过滤
# 第一步是创建uesr-item矩阵,此处需创建训练和测试两个UI矩阵
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]
接下来通过 pairwise_distances求相似度
# 计算相似度
# 使用sklearn的pairwise_distances函数来计算余弦相似性
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')
最后就是预测
# 预测
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')
print("item_prediction:")
print(item_prediction)
print("user_prediction")
print(user_prediction)
# 评估指标,均方根误差
# 使用sklearn的mean_square_error (MSE)函数,其中,RMSE仅仅是MSE的平方根
# 只是想要考虑测试数据集中的预测评分,因此,使用prediction[ground_truth.nonzero()]筛选出预测矩阵中的所有其他元素
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))
print('User-based CF RMSE: ' + str(rmse(user_prediction, test_data_matrix)))
print('Item-based CF RMSE: ' + str(rmse(item_prediction, test_data_matrix
RMSE
我们选用RNSE作为评价准度的标准,RMSE越小越好。
关于评估标准可以参考一下这篇文章:https://blog.csdn.net/allenalex/article/details/51318270
网友评论