协同过滤
2.1 简介
协同过滤(Collaborative Filtering)是推荐系统中最基础的技术之一。它的基本想法很简单:如果两个用户过去喜欢相似的物品,那么他们未来也可能有相似的偏好。或者反过来说,如果两个物品被相似的用户群体喜欢,那么喜欢其中一个物品的用户也可能喜欢另一个。
协同过滤主要分为两大类:基于用户的协同过滤(User-Based Collaborative Filtering)和基于物品的协同过滤(Item-Based Collaborative Filtering)。无 论是哪种方法,核心思想都是利用用户与物品之间的交互数据来进行推荐。
这是两种传统方法,复杂一些的有矩阵分解这种基于模型的方法,通过学习用户和物品的低维向量表示来进行推荐。
2.2 基于用户的协同过滤
具有相似历史行为的用户,未来偏好也相似。
UserCF是最早提出的协同过滤方法。它的工作原理很直观:先找到与目标用户购买偏好相似的“邻居用户”,然后基于这些邻居对商品的选择来预测目标用户的偏好。
2.2.1 相似度计算
首先我们两两配对用户的时候,需要衡量他们的“相似”程度,常用的方法有杰卡德相似度、余弦相似度、皮尔逊相关系数等。
杰卡德相似度:
余弦相似度:
皮尔逊相关系数:
2.2.2 候选物品推荐
那有了相似度指标之后,我们需要为目标用户推荐物品,预测目标用户对未评分物品的兴趣度。
**简单加权平均:**最直接的方法是用相似度作为权重,对邻居的评分进行加权平均:
这里,是用户对物品的预测评分,是与用户相似的邻居用户集合,是用户和之间的相似度,是用户对物品的实际评分。
考虑评分偏置的版本:为了进一步消除个人评分习惯的影响,我们可以加入偏置修正:
这里,和分别是用户和的平均评分。先看邻居们对这个物品的评分相比他们平均水平如何,然后根据目标用户的平均评分水平进行调整。
2.2.3 算法优化策略
基于物品倒排表的优化:
- 构建倒排表:为每个物品维护一个用户列表,记录哪些用户对这个物品有过行为。这样就可以通过物品快速找到相关用户。
- 稀疏矩阵计算:创建一个矩阵来记录用户和的共同物品数量。遍历每个物品的用户列表,将列表中的用户两两配对,对应的值加1。
- 计算最终相似度:矩阵给出了余弦相似度公式的分子,再除以分母就得到了用户相似度。
- 生成推荐:使用以下公式计算用户对物品的兴趣分数:
其中,是与用户最相似的用户集合,是对物品的物品有过行为的用户集合实际推荐时,针对目标用户未交互过的物品计算上述兴趣度量值,并按分值降序排列,选择Top-N物品作为推荐结果。
新算法的时间复杂度约为。其中,是总的用户-物品交互记录数,是每个物品的平均用户数,在稀疏数据场景下显示出了更好的性能。
2.2.4 code实践
import numpy as np
user_data = {
'user1': {'item1': 5, 'item2': 3, 'item3': 4, 'item4': 4},
'user2': {'item1': 3, 'item2': 1, 'item3': 2, 'item4': 3, 'item5': 3},
'user3': {'item1': 4, 'item2': 3, 'item3': 4, 'item4': 3, 'item5': 5},
'user4': {'item1': 3, 'item2': 3, 'item3': 1, 'item4': 5, 'item5': 4},
'user5': {'item1': 1, 'item2': 5, 'item3': 5, 'item4': 2, 'item5': 1},
}
# 我们计划预测用户1对物品5的评分
similarity_matrix = pd.DataFrame(
np.identity(len(user_data)),
index=user_data.keys(),
columns=user_data.keys(),
)
# 首先计算他们的相似度:
# 遍历每条用户-物品评分数据
for u1, items1 in user_data.items():
for u2, items2 in user_data.items():
if u1 == u2:
continue
vec1, vec2 = [], []
for item, rating1 in items1.items():
rating2 = items2.get(item, -1)
if rating2 == -1:
continue
vec1.append(rating1)
vec2.append(rating2)
# 计算不同用户之间的皮尔逊相关系数
similarity_matrix[u1][u2] = np.corrcoef(vec1, vec2)[0][1]
print(similarity_matrix)
target_user = 'user1'
num = 2
# 由于最相似的用户 为自己,去除本身
sim_users = similarity_matrix[target_user].sort_values(ascending=False)[1:num+1].index.tolist()
print(f'与用户{target_user}最相似的{num}个用户为:{sim_users}')
weighted_scores = 0.
corr_values_sum = 0.
target_item = 'item5'
# 基于皮尔逊相关系数预测用户评分
for user in sim_users:
corr_value = similarity_matrix[target_user][user]
user_mean_rating = np.mean(list(user_data[user].values()))
weighted_scores += corr_value * (user_data[user][target_item] - user_mean_rating)
corr_values_sum += corr_value
target_user_mean_rating = np.mean(list(user_data[target_user].values()))
target_item_pred = target_user_mean_rating + weighted_scores / corr_values_sum
print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred:.4f}')
import os
import sys
import funrec
from funrec.utils import build_metrics_table
# 加载配置
config = funrec.load_config('user_cf')
# 加载数据
train_data, test_data = funrec.load_data(config.data)
# 准备特征
feature_columns, processed_data = funrec.prepare_features(config.features, train_data, test_data)
# 训练模型
models = funrec.train_model(config.training, feature_columns, processed_data)
# 评估模型
metrics = funrec.evaluate_model(models, processed_data, config.evaluation, feature_columns)
print(build_metrics_table(metrics))