前言
协同过滤推荐算法是诞生最早,并且较为著名的推荐算法。主要的功能是预测和推荐。
协同过滤推荐系统在我们的日常生活之中无处不在,例如,在电子商城购物,系统会根据用户的记录或者其他的
信息来推荐相应的产品给客户。
协同过滤算法通过对用户历史行为数据的挖掘发现用户的偏好,基于不同的偏好对用户进行群组划分并推荐品味相似的商品。协同过滤推荐算法分为两类,分别是基于用户的协同过滤算法(user-based collaboratIve filtering),和基于物品的协同过滤算法(item-based collaborative filtering)。我们这篇文章主要讲基于用户的协同过滤,并附有python代码实现
基于用户的协同过滤算法
在下面的表格中,user_id_表示用户,Move_id_1表示用户喜爱的电影(如何知道用户喜爱与否,我们不考虑)
如下图所示,我们可以知道用户A(user_id_1)爱好的电影是Move_id_1,Move_id_2和Move_id_3
我们现在的目的是找到与用户A(user_id_1)具有相同兴趣爱好的用户群体集合Set<user_id>
找到该群体后,通过该群体找到该群体喜欢的电影集合Set<movie_id>
具体大致如下:
(1)假如横坐标Move_id_有10w个数据,纵坐标Move_id_有100w个数据
横纵坐标交叉处的‘1’代表用户喜爱这部电影,至入如何喜欢需要人为定义,例如浏览过,点赞过,从头到尾看完过等。
(2)如下表找到用户A(user_id_1)的兴趣爱好,我们可以看到,用户A喜欢电影{m1(这里简写一下), m2, m3}
3)找到与用户A(user_id_1)具有相同电影兴趣爱好的用户群体集合Set<user_id>
如上表,可以看到,喜欢{m1, m2, m3}的用户,除了u1,还有{u2, u3}
(4)找到该群体喜欢的电影集合Set<movie_id>
如上表,具备相同喜好的用户群里{u2, u3},还喜好的电影集合是{m4, m5}
划重点:“协同”就体现在这里。
(5)未来用户A(use_id_1)来访问网站时,我们便将要推荐电影{m4, m5}给他。
基于用户协同过滤的要点在于找与用户具有相同兴趣爱好的用户群体,在这些群体喜爱的项目群中我们可以找到可以向用户推荐的项目,我们可以通计算用户之间的相似度,来找到一个用户的与他拥有相同兴趣爱好的群体。
我们以电影推荐为例
假如我们现在有一份数据,里面记录的用户观看不同的电影后对电影的评分等一系列信息信息,下面的链接可以下载数据,建议使用1M大小的那个
去网站: https://grouplens.org/datasets/movielens/ 下载movieLen数据集
或者
ml-latest-small(1MB): http://files.grouplens.org/datasets/movielens/ml-latest-small.zip
ml-latest(234.2MB):http://files.grouplens.org/datasets/movielens/ml-latest.zip
上面数据的格式下载后自己看
第一步造数据
由于我们所给的数据时散杂的,当我们首先要对数据进行整理,整理后的数据保存到data.csv中,注意路径。
import pandas as pd
#数据整理
movies = pd.read_csv("C:\\Users\ever\\Desktop\\AI\ml-latest-small\movies.csv")
ratings = pd.read_csv("C:\\Users\ever\\Desktop\\AI\ml-latest-small\\ratings.csv") #ratings.csv开头是r要转义
data = pd.merge(movies, ratings, on = "movieId")#通过两个数据框之间的movieId属性连接
data[['userId', 'rating', 'movieId', 'title']].sort_values('userId').to_csv("C:\\Users\ever\\Desktop\\AI\\data.csv", index=False)
print(data)
结果:
data.csv用于存储数据
下面采用python字典来表示每位用户评论的电影和评分
#读取data.csv中每行除了名字外的数据
file = open("C:\\Users\ever\\Desktop\\AI\\data.csv", 'r', encoding = 'UTF-8')
#存放每位用户评论的电影和评分
data = {}
#readlines() 方法用于读取整个文件(所有行)到一个列表,可以由for... in ... 结构进行遍历。列表的每一行变成列表的每一个元素。
for line in file.readlines()[1:10000]:#循环结束后data中的数据都是电影名:评分形式的
print('line:', line)
# strip() 方法用于移除字符串头尾指定的字符,需要的朋友可以参考下
#split() 通过指定分隔符对字符串进行切片
line = line.strip().split(',')
#如果字典中没有某位用户,则使用用户ID来创建这位用户
if not line[0] in data.keys():
data[line[0]] = {line[3]:line[1]}
print('55555555',data[line[0]])
else:
data[line[0]][line[3]] = line[1]
print(data)
计算任何两位用户之间的相似度,由于每位用户评论的电影不完全一样,所以兽先要找到两位用户共同评论过的电影
然后计算两者之间的欧式距离,最后算出两者之间的相似度。根据相似度来推荐用户:
下面是完整的代码,造数据的代码单独放一个文件里面
代码中有一些输出项例如有55555555,111,等的print是我在调试的时候为了方便理解加的
import numpy as np
#取两位用户评论过的电影和评分
def Euclidean(user1, user2):
user1_data = data[user1]
user2_data = data[user2]
distance = 0
#找出user1和user2都看过的电影,计算二者的而是距离
for key in user1_data.keys():
if key in user2_data.keys():
#user1_data和user2_data为电影的评分
# print('user1_data', user1_data[key], ' user2_data', user2_data[key])
distance += pow(float(user1_data[key]) - float(user2_data[key]), 2)
# print('distance', distance, '\n')
return 1/(1 + np.sqrt(distance))#
def top_simliar(userID):
res = []
for userid in data.keys():
if not userid == userID:
simliar = Euclidean(userID, userid)
res.append((userid,simliar))
res.sort(key = lambda val:val[1])
print('已运行到这里111')
return res[:4]
#根据用户推荐电影给其他人
def recommend(user):
#相似度最高的用户
top_sim_user = top_simliar(user)[0][0]
#相似度最高的用户的观影记录
items = data[top_sim_user]
recommendations = []
#筛选出该用户未观看的电影并添加到列表中
for item in items.keys():
if item not in data[user].keys():
recommendations.append((item,items[item]))
recommendations.sort(key=lambda val:val[1],reverse=True)#按照评分排序
#返回评分最高的10部电影
return recommendations[:10]
#读取data.csv中每行除了名字外的数据
file = open("C:\\Users\ever\\Desktop\\AI\\data.csv", 'r', encoding = 'UTF-8')
#存放每位用户评论的电影和评分
data = {}
#readlines() 方法用于读取整个文件(所有行)到一个列表,可以由for... in ... 结构进行遍历。列表的每一行变成列表的每一个元素。
for line in file.readlines()[1:10000]:#循环结束后data中的数据都是电影名:评分形式的
print('line:', line)
# strip() 方法用于移除字符串头尾指定的字符,需要的朋友可以参考下
#split() 通过指定分隔符对字符串进行切片
line = line.strip().split(',')
#如果字典中没有某位用户,则使用用户ID来创建这位用户
print('56464654465', line[0], line[3])#line[0]是userid,line[3]是电影名称
if not line[0] in data.keys():
data[line[0]] = {line[3]:line[1]}
print('55555555',data[line[0]])
else:
data[line[0]][line[3]] = line[1]
print('111', [data[line[0]][line[3]]])
print('222', )
print(data)
print('keys', data.keys())
res = top_simliar('4')
print("运行完毕")
print(res)
print('推荐')
Recommendations = recommend('1')
print(Recommendations)
print('相关系数')
R = pearson_sim('1','3')
print(R)
上面就是基于用户的协同过滤推荐算法以及其实现
下面是我学习过程中找到的一些较好的链接,可作为参考
https://blog.youkuaiyun.com/qq_25948717/article/details/81839463
https://blog.youkuaiyun.com/u012050154/article/details/52268057
https://blog.youkuaiyun.com/yimingsilence/article/details/54934302