推荐系统是现代互联网应用中不可或缺的一部分。无论是电子商务、社交媒体还是内容平台,都在使用各种推荐算法来为用户提供个性化的体验。今天,我们将深入探讨一种简单而有效的推荐算法——简单算法推荐(Simple Algorithm for Recommendation, SAR),并通过在著名的MovieLens数据集上的实践来展示其应用。
SAR算法简介
SAR是一种基于用户交互历史的快速、可扩展的个性化推荐算法。它的主要特点包括:
- 生成易于解释和理解的推荐结果
- 能够处理"冷启动物品"和"半冷启动用户"的场景
- 属于基于邻域的算法,旨在为每个用户推荐最合适的物品
SAR的核心思想是推荐与用户已有偏好相似的物品。这里的"相似"指的是:如果用户与物品A交互,那么他们也很可能与物品B交互;而"偏好"则指用户在过去与某个物品有过交互。
SAR的优势
- 高准确度:虽然算法简单,但能达到很好的推荐效果
- 训练速度快:只需要进行简单的计数就可以构建预测时使用的矩阵
- 预测速度快:预测过程仅涉及相似度矩阵与偏好向量的乘法运算
SAR的使用注意事项
- 由于不使用物品或用户特征,在某些场景下可能不如使用这些特征的算法
- 内存消耗大:需要创建一个m×m的稀疏方阵(m为物品数量)
- SAR更适合隐式评分场景,不适合预测具体评分值
数据准备
我们使用MovieLens数据集来演示SAR算法的应用。MovieLens是一个包含用户对电影评分的数据集,非常适合用来测试推荐算法。
首先,我们加载所需的库和数据:
import sys
import logging
import numpy as np
import pandas as pd
from recommenders.datasets import movielens
from recommenders.models.sar import SAR
from recommenders.datasets.python_splitters import python_stratified_split
# 加载MovieLens 100k数据集
data = movielens.load_pandas_df(size="100k")
data["rating"] = data["rating"].astype(np.float32)
接下来,我们将数据集分为训练集和测试集:
train, test = python_stratified_split(data, ratio=0.75, col_user="userID", col_item="itemID", seed=42)
这里我们使用了分层抽样的方法,保证每个用户的75%评分进入训练集,25%进入测试集。
模型训练与预测
现在,我们可以开始训练SAR模型了:
model = SAR(
col_user="userID",
col_item="itemID",
col_rating="rating",
col_timestamp="timestamp",
similarity_type="jaccard",
time_decay_coefficient=30,
timedecay_formula=True,
normalize=True
)
model.fit(train)
在这个过程中,SAR会计算物品之间的共现矩阵,然后基于Jaccard相似度计算物品相似度矩阵。同时,它还会计算用户-物品亲和度矩阵,捕捉用户与物品之间关系的强度。
训练完成后,我们可以为测试集中的用户生成Top-K推荐:
TOP_K = 10
top_k = model.recommend_k_items(test, top_k=TOP_K, remove_seen=True)
模型评估
为了评估SAR的性能,我们使用了几个常见的排序指标:
- 平均精度均值(MAP)
- 归一化折损累积增益(NDCG)
- 准确率(Precision)
- 召回率(Recall)
同时,我们还计算了一些评分指标:
- 均方根误差(RMSE)
- 平均绝对误差(MAE)
- R方(R-squared)
- 可解释方差(Explained Variance)
eval_map = map(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_ndcg = ndcg_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_precision = precision_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_recall = recall_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_rmse = rmse(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_mae = mae(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_rsquared = rsquared(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_exp_var = exp_var(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
这些指标能够全面地评估SAR算法在MovieLens数据集上的表现。
结论
通过在MovieLens数据集上的实验,我们展示了SAR算法的实际应用。SAR作为一种简单而有效的推荐算法,在许多场景下都能取得不错的效果。它的快速训练和预测特性使其特别适合需要实时推荐的应用场景。
然而,SAR也有其局限性。例如,它不能利用物品或用户的特征信息,这在某些场景下可能会限制其性能。此外,对于大规模数据集,其内存消耗可能会成为一个挑战。
总的来说,SAR是推荐系统工具箱中的一个有力工具。在实际应用中,我们需要根据具体的业务需求和数据特征,选择适合的算法或者多种算法的组合。
参考文献
- Recommenders contributors. (2023). SAR Single Node on MovieLens (Python, CPU). GitHub. https://github.com/recommenders-team/recommenders/blob/main/examples/00_quick_start/sar_movielens.ipynb
- Aggarwal, C. C. (2016). Recommender Systems: The Textbook. Springer International Publishing.
- Harper, F. M., & Konstan, J. A. (2015). The MovieLens Datasets: History and Context. ACM Transactions on Interactive Intelligent
这篇文章将介绍如何使用简单算法推荐(SAR)模型对MovieLens数据集进行协同过滤推荐。SAR是一种基于用户交互历史的快速可扩展的个性化推荐算法,具有易于解释和处理冷启动问题的优势。让我们一步步来看SAR模型的实现过程。
1. 数据准备
首先,我们加载MovieLens数据集并进行预处理:
data = movielens.load_pandas_df(size="100k")
data["rating"] = data["rating"].astype(np.float32)
这里我们使用了MovieLens 100k数据集,包含10万条用户对电影的评分记录。
接下来,我们将数据集分为训练集和测试集:
train, test = python_stratified_split(data, ratio=0.75, col_user="userID", col_item="itemID", seed=42)
我们使用了分层抽样的方法,保留75%的数据作为训练集,25%作为测试集。这种分割方法可以确保每个用户在训练集和测试集中都有数据。
2. SAR模型训练
SAR模型的核心思想是基于用户的历史交互来推荐相似的物品。我们首先实例化SAR模型:
model = SAR(
col_user="userID",
col_item="itemID",
col_rating="rating",
col_timestamp="timestamp",
similarity_type="jaccard",
time_decay_coefficient=30,
timedecay_formula=True,
normalize=True
)
这里我们使用了Jaccard相似度,并启用了时间衰减和归一化。
然后我们开始训练模型:
model.fit(train)
SAR模型的训练过程主要包括以下步骤:
- 计算物品共现矩阵
- 基于共现矩阵计算物品相似度矩阵
- 计算用户-物品亲和度矩阵
训练完成后,我们可以为测试集中的用户生成Top-K推荐:
top_k = model.recommend_k_items(test, top_k=TOP_K, remove_seen=True)
3. 模型评估
为了评估SAR模型的性能,我们使用了多个常用的推荐系统评估指标:
eval_map = map(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_ndcg = ndcg_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_precision = precision_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_recall = recall_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
这些指标包括平均精度均值(MAP)、归一化折损累积增益(NDCG)、精确率和召回率。
此外,我们还计算了一些评分预测相关的指标:
eval_rmse = rmse(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_mae = mae(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_rsquared = rsquared(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_exp_var = exp_var(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
这些指标包括均方根误差(RMSE)、平均绝对误差(MAE)、R方和解释方差。
4. 结果分析
在MovieLens 100k数据集上,SAR模型的表现如下:
- MAP: 0.106959
- NDCG: 0.379533
- Precision@K: 0.331071
- Recall@K: 0.176837
- RMSE: 1.229246
- MAE: 1.033912
这些结果表明,SAR模型在推荐相关性和排序质量方面表现不错,但在评分预测方面还有提升空间。
我们还可以查看特定用户的推荐结果:
user_id = 54
ground_truth = test[test["userID"] == user_id].sort_values(by="rating", ascending=False)[:TOP_K]
prediction = model.recommend_k_items(pd.DataFrame(dict(userID=[user_id])), remove_seen=True)
df = pd.merge(ground_truth, prediction, on=["userID", "itemID"], how="left")
这让我们能够直观地比较模型的推荐结果和用户的实际偏好。
5. 总结与展望
SAR模型作为一种简单高效的协同过滤算法,在MovieLens数据集上展现了不错的性能。它的优势在于:
- 训练和预测速度快
- 可解释性强
- 能够处理冷启动问题
然而,SAR模型也存在一些局限性:
- 不使用用户和物品特征,可能在某些场景下处于劣势
- 对于大规模数据集,内存消耗较大
未来的改进方向可以包括:
- 结合内容特征,构建混合推荐系统
- 使用更高级的相似度计算方法
- 探索模型集成,如将SAR与矩阵分解方法结合
总的来说,SAR模型为协同过滤推荐系统提供了一个简单而有效的baseline,值得在实际应用中尝试和优化。
简单算法推荐 (SAR) 在 MovieLens 数据集上的应用
简单算法推荐 (SAR) 是一种快速且可扩展的个性化推荐算法,它基于用户交易历史进行推荐。SAR 生成的推荐易于解释和理解,并能处理“冷启动物品”和“半冷启动用户”场景。SAR 属于一种基于邻域的算法,如 Aggarwal 的推荐系统 中所述,旨在为每个用户排名最顶级的物品。有关 SAR 的更多详细信息,请参阅 深入研究笔记本。
SAR 推荐与用户已有 亲和力 的物品最 相似 的物品。如果与一个物品交互的用户也可能与另一个物品交互,则这两个物品是 相似 的。如果用户过去与某个物品交互过,则该用户对该物品具有 亲和力。
SAR 的优势:
- 对于易于训练和部署的算法,具有很高的准确性。
- 快速训练,只需要简单的计数来构建预测时使用的矩阵。
- 快速评分,只需要将相似度矩阵与亲和度向量相乘。
正确使用 SAR 的注意事项:
- 由于它不使用物品或用户特征,因此在与使用特征的算法相比可能处于劣势。
- 它需要大量的内存,需要创建一个 $mxm$ 的稀疏方阵(其中 $m$ 是物品的数量)。这对于许多矩阵分解算法来说也是一个问题。
- SAR 倾向于隐式评分场景,它不预测评分。
本篇文章将以 Python 在 CPU 上为例,展示如何使用和评估 SAR。
1. 加载数据
SAR 旨在用于以下模式的交互:<用户 ID>, <物品 ID>,<时间>,[<事件类型>], [<事件权重>]
。
每行代表用户和物品之间的一次交互。这些交互可能是电子商务网站上不同类型的事件,例如用户点击查看物品、将物品添加到购物车、点击推荐链接等等。每个事件类型可以分配不同的权重,例如,我们可以将“购买”事件的权重分配为 10,而“查看”事件的权重可能只有 1。
MovieLens 数据集格式良好,包含用户对电影的评分(电影评分用作事件权重)——我们将使用它作为本篇文章的示例。
1.1 下载并使用 MovieLens 数据集
# top k 个推荐的物品
TOP_K = 10
# 选择 MovieLens 数据集大小:100k、1m、10m 或 20m
MOVIELENS_DATA_SIZE = "100k"
# 下载并加载 MovieLens 数据集
data = movielens.load_pandas_df(
size=MOVIELENS_DATA_SIZE
)
# 将浮点精度转换为 32 位以减少内存消耗
data["rating"] = data["rating"].astype(np.float32)
1.2 使用实用程序提供的 Python 随机拆分器拆分数据
我们将完整数据集拆分为 train
和 test
数据集,以评估算法在训练期间未见过的保留集上的性能。由于 SAR 根据用户偏好生成推荐,因此测试集中所有用户也必须存在于训练集中。在这种情况下,我们可以使用提供的 python_stratified_split
函数,该函数从每个用户中保留一定比例(在本例中为 25%)的物品,但确保所有用户都存在于 train
和 test
数据集中。dataset.python_splitters
模块中提供了其他选项,可以更详细地控制拆分方式。
train, test = python_stratified_split(data, ratio=0.75, col_user="userID", col_item="itemID", seed=42)
2. 训练 SAR 模型
2.1 实例化 SAR 算法并设置索引
我们将使用 SAR 的单节点实现,并指定列名以匹配我们的数据集(时间戳是一个可选列,如果您的数据集不包含它,可以删除)。
其他选项用于控制算法的行为,如 深入研究笔记本 中所述。
logging.basicConfig(level=logging.DEBUG,
format=
model = SAR(
col_user="userID",
col_item="itemID",
col_rating="rating",
col_timestamp="timestamp",
similarity_type="jaccard",
time_decay_coefficient=30,
timedecay_formula=True,
normalize=True
)
2.2 在我们的训练数据上训练 SAR 模型,并为我们的测试数据获取 top-k 推荐
SAR 首先计算一个物品到物品的 共现矩阵。共现表示两个物品在任何给定用户中同时出现的次数。一旦我们有了共现矩阵,我们就可以通过给定指标(本例中为 Jaccard 相似度)重新缩放共现来计算 物品相似度矩阵。
我们还计算一个 亲和度矩阵 来捕获每个用户与每个物品之间关系的强度。亲和度由不同的类型(如 评分 或 观看 电影)以及事件发生的时间驱动。
推荐是通过将亲和度矩阵 $A$ 与相似度矩阵 $S$ 相乘来实现的。结果是一个 推荐评分矩阵 $R$。我们在下面看到的 recommend_k_items
函数中计算了 test
数据集中每个用户的 top-k 结果。
SAR 算法的完整演练可以在这里找到 here。
with Timer() as train_time:
model.fit(train)
print("Took {} seconds for training.".format(train_time.interval))
with Timer() as test_time:
top_k = model.recommend_k_items(test, top_k=TOP_K, remove_seen=True)
print("Took {} seconds for prediction.".format(test_time.interval))
2.3 评估 SAR 的性能
我们评估 SAR 在 python_evaluation
模块中提供的几个常见排名指标上的性能。我们将考虑平均平均精度 (MAP)、归一化折损累积增益 (NDCG)、精确度和召回率,这些指标是针对我们使用 SAR 计算的每个用户的 top-k 物品。用户、物品和评分列名在每个评估方法中都已指定。
# 排名指标
eval_map = map(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_ndcg = ndcg_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_precision = precision_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
eval_recall = recall_at_k(test, top_k, col_user="userID", col_item="itemID", col_rating="rating", k=TOP_K)
# 评分指标
eval_rmse = rmse(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_mae = mae(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_rsquared = rsquared(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
eval_exp_var = exp_var(test, top_k, col_user="userID", col_item="itemID", col_rating="rating")
positivity_threshold = 2
test_bin = test.copy()
test_bin["rating"] = binarize(test_bin["rating"], positivity_threshold)
top_k_prob = top_k.copy()
top_k_prob["prediction"] = minmax_scale(top_k_prob["prediction"].astype(float))
eval_logloss = logloss(
test_bin, top_k_prob, col_user="userID", col_item="itemID", col_rating="rating"
)
print("Model:\t",
"Top K:\
"MAP:\
"NDCG:\
"Precision@K:\
"Recall@K:\
"RMSE:\
"MAE:\
"R2:\
"Exp var:\
"Logloss:\
sep='\n')
# 现在让我们看看特定用户的结果
user_id = 54
ground_truth = test[test["userID"] == user_id].sort_values(
by="rating", ascending=False
)[:TOP_K]
prediction = model.recommend_k_items(
pd.DataFrame(dict(userID=[user_id])), remove_seen=True
)
df = pd.merge(ground_truth, prediction, on=["userID", "itemID"], how="left")
df.head(10)
上面,我们看到测试集中评分最高的物品之一被模型的 top-k 推荐所恢复,但其他物品则没有。离线评估很困难,因为它们只能使用测试集中以前看到的内容,可能无法代表用户在整个物品集中的实际偏好。对数据拆分方式、算法使用方式和超参数的调整可以改善这里的结果。
参考文献
希望这篇文章能帮助您更好地理解 SAR 算法及其在 MovieLens 数据集上的应用。