import pandas as pd
import numpy as np
from sklearn.metrics import jaccard_score
from sklearn.metrics.pairwise import pairwise_distances
users = ['user1', 'user2', 'user3', 'user4', 'user5']
items = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5']
# datasets = [
# [1, 0, 1, 1, 0, 0],
# [1, 0, 0, 1, 1, 0],
# [1, 0, 1, 0, 0, 1],
# [0, 1, 0, 1, 1, 0],
# [1, 1, 1, 0, 1, 1],
# [1, 0, 1, 0, 0, 0],
# ]
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]
]
df = pd.DataFrame(datasets, columns=items, index=users)
# print(df)
# print(jaccard_score(df['Item1'], df['Item2']))
# 整个矩阵计算杰卡德相似度
user_similar = 1 - pairwise_distances(df.values, metric='jaccard')
# [[1. 0.5 0.66666667 0.2 0.4 ]
# [0.5 1. 0.25 0.5 0.4 ]
# [0.66666667 0.25 1. 0. 0.5 ]
# [0.2 0.5 0. 1. 0.4 ]
# [0.4 0.4 0.5 0.4 1. ]]
# 上面算出来的结果是一个二维矩阵,用pd.DataFrame给矩阵加上标题和索引
user_similar = pd.DataFrame(user_similar, columns=users, index=users)
# print(user_similar)
# 加上索引和标题后的效果
# user1 user2 user3 user4 user5
# user1 1.000000 0.50 0.666667 0.2 0.4
# user2 0.500000 1.00 0.250000 0.5 0.4
# user3 0.666667 0.25 1.000000 0.0 0.5
# user4 0.200000 0.50 0.000000 1.0 0.4
# user5 0.400000 0.40 0.500000 0.4 1.0
# 定义一个字典来存放最相似的用户
topN_users = {}
# 将每一个 用户 都拿来处理
# 返回指定行的数据loc[i] 并且将自己在那一行中删除drop([i])
# 在删除自己后 对 这一行经行排序 sort_values(ascending=False) 由大到小排列
# 排序后对索引进行切片 取出排在最前面的两个 也就是 相似度最高的两个人的 名字!
# 将相似度最高的两个人 存放在topN_users[i]内 【topN_users[i]存放的是每个用户对应的相似度最高的两个用户】比如topN_users['user1']中存放的是['user3', 'user2']
# 也就是说 user1 和【user3和user2像】 但是user3比user2更像user1
for i in user_similar.index:
_df = user_similar.loc[i].drop([i])
_df_scorted = _df.sort_values(ascending=False)
top2 = list(_df_scorted.index[:2])
topN_users[i] = top2
# print(topN_users)
# 这时候topN_users字典内存放的内容是每个用户对应的最像的两个用户
# {'user1': ['user3', 'user2'], 'user2': ['user1', 'user4'], 'user3': ['user1', 'user5'], 'user4': ['user2', 'user5'], 'user5': ['user3', 'user1']}
# 定义一个推荐字典
# 外层循环topN_users.items()中有两项,一项是 用户的名字 一项是 最相似的两个人
# rs_result = set() 设置推荐项
# 进入二层循环 sim_users中存这 每一个用户 最相似的两个人 所以二层循环在外层循环内 循环二次
# 合并rs_result.union 函数的作用就是合并 取并集
# 拿user1举例 与他最相似的是user3和user2
# user3购买了item1、3 user2购买了item1、4、5 取并集就是 1、3、4、5
# replace()作用是将用户没买过的东西替换为nan dropna()作用是将nan给去除掉 剩下的就是购买过的物品 .index作用是拿到对应的索引
# 这时候rs_result存放的是user2和user3都购买过的物品
# rs_result = rs_result - set(df.loc[user].replace(0, np.nan).dropna().index)
# 将user2和user3都购买过的物品减去user1买过的物品剩下的就是user1没买过的物品 以此循环!
# 经过筛选后得出推荐结果
# 换句话说 协同过滤就是层层筛选
# 先筛选最相似的用户 再筛选相似用户购买过的产品 再在相似用户购买过的产品内去除被推荐用户已经购买过的产品
rs_results = {}
for user, sim_users in topN_users.items():
rs_result = set()
for sim_user in sim_users:
rs_result = rs_result.union(set(df.loc[sim_user].replace(0, np.nan).dropna().index))
print(rs_result)
rs_result = rs_result - set(df.loc[user].replace(0, np.nan).dropna().index)
rs_results[user] = rs_result
print(rs_results)
协同过滤 杰卡德相似度 usercf
于 2022-01-20 15:07:31 首次发布