Data(数据)—>Features(特征)—>ML Algorithm(选择算法训练模型)—>Prediction Output(预测输出)
算法的思想:物以类聚,人以群分
基本的协同过滤推荐算法基于以下的假设:
1.找出最相似的人或物品:TOP-N相似的人或物品
通过计算两两的相似度来进行排序,找出TOP-N相似人或者物品
2.根据相似的人或物品产生推荐结果
利用TOP-N结果生成初始推荐结果,然后过滤掉用户已经有过记录的物品或明确表示过不喜欢的物品
以下有一个简单的小案例,数据集相当于一个用户对物品的购买记录
User-Based CF
Item-Based CF
# 根据表格构建数据集
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 用户购买记录数据集
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
import pandas as pd
df = pd.DataFrame(data=datasets,index=users,columns=items)
# 这里我们使用杰卡德相似系数来计算相似度
from sklearn.metrics.pairwise import pairswise_distances
# 计算用户之间的相似度 1 - 杰卡德距离 = 杰卡德相似度
user_similar = 1 - pairwise_distances(df,metric = 'jaccard')
user_similar = pd.DataFrame(data=user_similar,index=users,columns=users)
# 接下来计算TOP-N相似结果 (相似度最接近的前两名用户)
topN_users = {
}
for i in user_similar.index:
_df = user_similar.loc[i].drop(i)
_df_sorted = _df.sort_values(ascending=False)
top2 = list(_df_sorted.index[:2])
topN_users[i] = top2
import numpy as np
results = {
}
for user,sim_users in topN_users.items():
res = set()
for sim_user in sim_users:
res = res.union(set(df.loc[sim_user].replace(0,np.NaN).dropna().index))
# 过滤掉用户已经购买过的物品
res -= set(df.loc[user].replace(0,np.NaN).dropna().index)
results[user] = res
print("最终推荐结果:",results)
# 根据表格构建数据集
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 用户购买记录数据集
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
import pandas as pd
df = pd.DataFrame(data=datasets,index=users,columns=items)
# 计算用户之间的相似度 1 - 杰卡德距离 = 杰卡德相似度
item_similar = df.pairwise_distances(df,matric = 'jaccard')
item_similar = pd.DataFrame(data=item_similar,index=items,columns=items)
# # 接下来计算TOP-N相似结果 (相似度最接近的前两名用户)
topN_items = {
}
for i in item_similar.index:
# 取出每一列数据,并删除自身,然后排序数据
_df = item_similar.loc[i].drop(i)
_df_sorted = _df.sort_values(ascending=False)
top2 = list(_df_sorted.index[:2])
topN_items[i] = top2
results = {
}
for user in df.index:
res = set()
# 取出每一个用户当前已购买的物品列表
for item in df.loc[user].replace(0,np.NaN).dropna().index:
# 根据每个物品找出最相似的TOP-N物品,构建初始推荐结果
res = res.union(topN_items[item])
# 过滤用户已买过的物品
res -= set(df.loc[user].replace(0,np.NaN).dropna().index)
results[user] = res
print("最终推荐结果",results)
import numpy as np
import pandas as pd
# 获取数据
dtype = {
'userId':np.int32,'movieId':np.int32,'rating':np.float32}
# 只取前三列数据 用户id 电影id 和 电影对应评分
ratings = pd.read_csv('ratings.csv',dtype=dtype,usecols=range(3))
# 使用透视表,将电影ID转换为列名称,转换成一个User_Movie的评分矩阵
ratings_matrix = ratings.pivot_table(index=['userId'],columns=['movieId'],values='rating')
# 计算用户之间的相似度 corr就是可以直接计算皮尔逊相关系数
user_similar = ratings.matrix.T.corr()
# 预测某一用户对某一个电影的评分
def predict(uid,iid,ratings_matrix,user_similar):
# 1.找出与用户相似的相似用户
# 1.1 先删除自己与自己的相似度
similar_users = user_similar.loc[uid].drop(uid).dropna()
# 1.2 找出正相关的相似用户
similar_users = similar_users.where(similar_users > 0 ).dropna()
# 2.从近邻用户中选出对iid电影有评分的用户
ids = set(ratings_matrix[iid].dropna().index)&set(similar_users.index)
# 2.1 将这些用户从相似用户中提取出来
finally_similar_users = similar_users.loc[list(ids)]
# 3.结合用户与近邻用户的相似度 预测用户对iid电影的评分
num = 0 # 评分预测公式的分子部分
deno = 0 # 评分预测公式的分母部分
for sim_uid,similarity in finally_similar_user.iteritems():
# 计算这个近邻用户对所有电影的评分
sim_user_rated_movies = ratings_matrix.loc[sim_uid].dropna()
# 求出这个用户对iid当前的电影的评分
sim_user_for_item = sim_user_rated_movies[iid]
# 计算分子
num += similarity * sim_user_for_item
deno += similarity
# 计算预测的评分
predict_rating = num / deno
print("预测出用户<%d>对电影<%d>的评分:%0.2f" % (uid,iid,predict_rating))
return round(predct_rating,2)
# 预测某一个用户对所有电影评分
def predict_all(uid,ratings_matrix,user_similar):
# 准备要预测的电影列表
item_ids = ratings_matrix.columns
for iid in item_ids:
try:
rating = predict(uid,iid,ratings_matrix,user_similar)
except Exception as e:
print(e)
else:
yield uid,iid,rating
# 根据评分为指定用户推荐topN个电影
def top_k_result(k):
results = predict_all(1,ratings_matrix,user_similar)
return sorted(results,key=lambda x:x[2],reverse = True)[:k]
result = top_k_result(5)
print(result)