商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Python中如何通过Scikit-learn构建推荐系统原型_利用最近邻算法

Python中如何通过Scikit-learn构建推荐系统原型_利用最近邻算法

  发布于2026-05-23 阅读(0)

扫一扫,手机访问

Python中如何通过Scikit-learn构建推荐系统原型:利用最近邻算法

Python中如何通过Scikit-learn构建推荐系统原型_利用最近邻算法

开门见山地说,如果你想在 scikit-learn 里找一个叫 RecommendationSystem 的模块,那恐怕要失望了。它不提供协同过滤、矩阵分解这类开箱即用的推荐算法接口。这并非功能遗漏,而是由其作为通用机器学习库的设计定位所决定的。

不过,这绝不意味着它无能为力。恰恰相反,scikit-learn 提供的底层工具足够灵活,能让你快速搭建出一个基于相似度的推荐系统原型。其核心,就在于 NearestNeighbors 这个类。它特别适合那些需要快速冷启动、数据量中等、且核心逻辑是“找到相似用户或物品”的场景,比如内部工具验证、产品最小可行性原型(MVP)或是教学演示。

scikit-learn 里没有现成的推荐系统模块

明确一点:scikit-learn 的武器库里没有名为“推荐系统”的专用武器。你找不到 fit_predict_ratings() 这类方法,文档和源码里也没有。它的设计初衷是提供基础的、可组合的机器学习组件,而非封装好的垂直领域解决方案。

但别急着关掉页面。虽然没有“一键推荐”,但它给了你所有必要的零件。通过组合 NearestNeighbors、矩阵操作和相似度计算,完全可以构建出推荐系统的核心骨架。这种方法优势在于透明可控,每一步逻辑都清晰可见,非常适合理解原理和快速迭代想法。

用 NearestNeighbors 做基于用户的协同过滤

基于用户的协同过滤,其核心思路非常直观:将每个用户对所有物品的评分(或交互)视为一个高维向量,然后计算用户向量之间的相似度,为当前用户找到品味相近的“邻居”,最后将这些邻居喜欢的物品加权推荐过来。

具体到 NearestNeighbors,有几个关键细节决定了成败:

  • 度量标准选择:默认的 metric=‘minkowski’(即欧氏距离)在处理评分数据时往往不是最佳选择。更常用的是 metric=‘cosine’(余弦相似度),因为它对向量的绝对大小不敏感,更关注评分模式的相对差异,非常适合稀疏且量纲不一的用户评分向量。
  • 行归一化是必须的:在计算余弦相似度前,务必对每个用户的评分向量进行单位化(即行归一化)。否则,一个习惯打高分的用户和一个习惯打低分的用户,即使品味完全一致,也会因为评分绝对值差异而显得“距离很远”,从而扭曲真实的相似性。
  • 注意矩阵形状:调用 fit() 方法时,输入的矩阵形状应为 (n_users, n_items)。这里容易混淆的是,通常机器学习中的特征矩阵是 (n_samples, n_features),而在推荐场景下,“样本”是用户,“特征”是物品,逻辑需要转换一下。
  • 拥抱稀疏矩阵:用户-物品矩阵天然是稀疏的(一个用户只与极少物品交互)。强烈建议使用 scipy.sparse.csr_matrix 来存储和计算,这能带来内存占用和计算速度的显著提升。直接使用稠密的 numpy 数组,数据量稍大就可能遭遇内存溢出(OOM)。

来看一个简洁的代码片段:

from sklearn.neighbors import NearestNeighbors
from scipy.sparse import csr_matrix

# 假设 user_item_matrix 已经是 csr_matrix,形状为 (n_users, n_items)
nn = NearestNeighbors(n_neighbors=5, metric=‘cosine’, algorithm=‘brute’)
nn.fit(user_item_matrix)

# 查找用户 123 的最近邻(返回距离和邻居索引)
distances, indices = nn.kneighbors(user_item_matrix[123], return_distance=True)

如何处理缺失值和冷启动用户

现实中的数据从不完美。新用户(冷启动)或交互极少的用户,其对应的评分行可能全部为零。这里有一个隐蔽的陷阱:NearestNeighbors 在处理全零向量时,计算出的距离可能为零或产生无意义的结果,且 kneighbors() 可能返回随机的邻居索引,而不会抛出错误。

如何应对?

  • 预处理过滤:在训练模型前,使用 user_item_matrix.getnnz(axis=1) > 0 筛选出至少有过一次交互的活跃用户。这是避免静默错误的第一步。
  • 冷启动策略:对于全新用户,他无法被嵌入现有的相似度空间。这时需要一个后备(fallback)方案,例如直接推荐全局热门物品(通过对 user_item_matrix 按列求和并排序得到),或者转向基于用户画像内容的简单规则。
  • 谨慎填充缺失值:切忌对整个评分矩阵用全局均值进行填充,这会严重污染相似度计算。如果必须填充,可以考虑仅对单个用户的缺失值,用该用户已有评分的均值进行行方向(axis=1)的填充。
  • 增量更新限制NearestNeighbors 不支持增量学习。当有新用户加入或用户行为更新后,通常需要重新拟合(fit())整个模型。对于大规模数据,需要考虑设计定期的离线重训练流程。

为什么不用 NearestNeighbors 做基于物品的推荐

理论上,将用户-物品矩阵转置后,同样可以用 NearestNeighbors 计算物品间的相似度,实现“买了这个商品的人也买了……”的推荐。但实践中,这常常会遇到挑战。

首要问题是维度和稀疏性。在许多场景下,物品数量(如百万商品)远大于用户数量(如十万用户)。在高维且极度稀疏的空间中(一个商品可能只被极少数人购买),NearestNeighbors 的查询效率会急剧下降。此外,计算出的物品-物品相似度矩阵(n_items × n_items)规模可能非常庞大,容易超出内存限制。

如果仍然想尝试,请注意:

  • 务必使用 algorithm=‘brute’(暴力计算)配合 metric=‘cosine’。基于树的算法如 ‘ball_tree’‘kd_tree’ 在高维稀疏数据上性能很差,甚至可能失效。
  • 考虑只对热门物品的子集构建相似度关系,以控制计算和存储成本。
  • 对于基于物品的推荐,另一个更实用的方法是使用 sklearn.metrics.pairwise.cosine_similarity 函数,批量计算小批次物品间的相似度,而非进行实时的最近邻查询。

说到底,用 NearestNeighbors 构建的推荐系统,其定位是一个清晰、快速的原型工具。它无法直接处理负采样、排序学习损失(Learning-to-Rank)或复杂的实时反馈闭环。要构建生产级的推荐系统,你可能需要转向 lightfmimplicit 等专用库,或自研更复杂的服务架构。

但对于验证想法、跑通数据流水线、理解推荐核心逻辑而言,NearestNeighbors 方案足够轻快、透明,是一个绝佳的起点。

本文转载于:https://www.php.cn/faq/2412580.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

产品推荐

热门关注