尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Python scikit-learn 1.4 实战:5种相似度算法在推荐系统中的性能对比

Python scikit-learn 1.4 实战:5种相似度算法在推荐系统中的性能对比
📅 发布时间:2026/7/8 2:40:02

Python scikit-learn 1.4 实战:5种相似度算法在推荐系统中的性能对比

推荐系统作为信息过滤的核心技术,其核心挑战在于准确量化用户偏好与内容特征之间的匹配程度。相似度计算作为推荐算法的基石,直接影响着推荐结果的精准度。本文将基于scikit-learn 1.4版本,深入分析5种主流相似度算法在真实推荐场景中的性能表现,并提供可复现的完整实现方案。

1. 推荐系统中的相似度计算基础

在构建推荐系统时,我们通常面临两种典型场景:基于用户(User-Based)的协同过滤和基于物品(Item-Based)的协同过滤。无论哪种场景,都需要解决一个根本问题——如何定义"相似性"。

相似度算法的选择需要考虑三个关键因素:

  • 数据稀疏性:用户-物品交互矩阵通常具有95%以上的稀疏度
  • 计算效率:线上服务需要毫秒级响应
  • 业务解释性:算法结果需要支持业务决策

下表对比了不同数据特性对算法选择的影响:

数据类型适用算法优势局限性
显式评分(1-5分)皮尔逊相关系数考虑用户评分偏差需要稠密数据
隐式反馈(点击/购买)余弦相似度适合稀疏数据忽略量级差异
二元特征(喜欢/不喜欢)Jaccard系数计算效率高丢失强度信息
文本特征TF-IDF余弦相似度捕捉语义关系需要分词处理
混合特征Gower距离处理异构数据计算复杂度高

在Python生态中,scikit-learn提供了高效的相似度计算实现。1.4版本主要优化包括:

  • 稀疏矩阵运算性能提升30%
  • 新增pairwise_distances_chunked支持大数据分块处理
  • 改进的并行计算支持
from sklearn.metrics.pairwise import cosine_similarity from scipy.sparse import csr_matrix # 稀疏矩阵表示用户-物品交互数据 interactions = csr_matrix([ [1, 0, 3, 0, 0], [0, 2, 0, 1, 0], [0, 0, 0, 4, 5] ]) # 计算物品相似度矩阵 item_sim = cosine_similarity(interactions.T)

2. 五种核心算法原理与实现

2.1 余弦相似度(Cosine Similarity)

余弦相似度通过测量两个向量夹角的余弦值来评估方向相似性,其值域为[-1,1]。在推荐系统中,我们通常使用调整余弦相似度(Adjusted Cosine)来消除用户评分偏差:

def adjusted_cosine(user_item_matrix): # 计算每个用户的平均评分 user_means = user_item_matrix.mean(axis=1) # 减去用户平均分 demeaned = user_item_matrix - user_means.reshape(-1, 1) # 计算余弦相似度 return cosine_similarity(demeaned.T)

注意:对于隐式反馈数据(如点击记录),直接使用原始余弦相似度即可,因为不存在评分偏差问题

2.2 皮尔逊相关系数(Pearson Correlation)

皮尔逊系数衡量两个变量的线性相关性,能够捕捉用户评分模式的一致性。scikit-learn中可通过以下方式计算:

from scipy.stats import pearsonr def pearson_sim(user_item_matrix): n_items = user_item_matrix.shape[1] sim_matrix = np.zeros((n_items, n_items)) for i in range(n_items): for j in range(i, n_items): # 提取共同评分的用户 common_users = ~np.isnan(user_item_matrix[:,i]) & ~np.isnan(user_item_matrix[:,j]) if sum(common_users) > 1: # 至少需要2个共同用户 sim, _ = pearsonr(user_item_matrix[common_users,i], user_item_matrix[common_users,j]) sim_matrix[i,j] = sim_matrix[j,i] = sim return sim_matrix

2.3 Jaccard相似系数

适用于二元交互数据(如是否点击),计算两个物品的共同用户占比:

from sklearn.metrics import jaccard_score def jaccard_sim(user_item_matrix): # 转换为二元矩阵 binary = (user_item_matrix > 0).astype(int) n_items = binary.shape[1] sim_matrix = np.zeros((n_items, n_items)) for i in range(n_items): for j in range(i, n_items): sim = jaccard_score(binary[:,i], binary[:,j]) sim_matrix[i,j] = sim_matrix[j,i] = sim return sim_matrix

2.4 欧氏距离相似度

虽然欧氏距离是距离度量,但可以转换为相似度。适合处理稠密评分数据:

from sklearn.metrics.pairwise import euclidean_distances def euclidean_sim(user_item_matrix): distances = euclidean_distances(user_item_matrix.T) # 将距离转换为相似度 return 1 / (1 + distances)

2.5 改进的Slope One算法

Slope One是一种基于评分差异的轻量级算法,特别适合稀疏数据:

class SlopeOne: def __init__(self): self.diffs = {} self.freqs = {} def fit(self, user_item_matrix): n_items = user_item_matrix.shape[1] # 初始化差异矩阵 self.diffs = np.zeros((n_items, n_items)) self.freqs = np.zeros((n_items, n_items)) # 计算物品间评分差异 for u in range(user_item_matrix.shape[0]): rated_items = np.where(~np.isnan(user_item_matrix[u]))[0] for i in rated_items: for j in rated_items: if i != j: diff = user_item_matrix[u,i] - user_item_matrix[u,j] self.diffs[i,j] += diff self.freqs[i,j] += 1 # 计算平均差异 self.diffs = np.divide(self.diffs, self.freqs, out=np.zeros_like(self.diffs), where=self.freqs!=0) def predict(self, user_ratings): preds = np.zeros_like(user_ratings) for i in range(len(user_ratings)): if np.isnan(user_ratings[i]): mask = ~np.isnan(user_ratings) preds[i] = np.sum((user_ratings[mask] + self.diffs[i,mask]) * self.freqs[i,mask]) / np.sum(self.freqs[i,mask]) return preds

3. 性能评估体系构建

3.1 评估指标选择

推荐系统评估需要多维度指标综合考量:

from sklearn.metrics import mean_squared_error from collections import defaultdict def evaluate(model, test_data): # 命中率(Hit Ratio) hits = 0 # 平均倒数排名(MRR) reciprocal_ranks = [] # RMSE preds, truths = [], [] for user in test_data: true_items = test_data[user] if not true_items: continue # 获取推荐列表 recs = model.recommend(user, top_n=10) # 计算命中率 hits += len(set(recs) & set(true_items)) > 0 # 计算MRR for i, item in enumerate(recs, 1): if item in true_items: reciprocal_ranks.append(1/i) break # 收集预测评分 user_preds = model.predict_ratings(user) preds.extend([user_preds[i] for i in true_items]) truths.extend([true_items[i] for i in true_items]) hr = hits / len(test_data) mrr = np.mean(reciprocal_ranks) if reciprocal_ranks else 0 rmse = np.sqrt(mean_squared_error(truths, preds)) if preds else 0 return {'HR': hr, 'MRR': mrr, 'RMSE': rmse}

3.2 交叉验证策略

采用时间序列分割保证评估真实性:

from sklearn.model_selection import TimeSeriesSplit def temporal_cv(data, n_splits=5): # 按时间排序用户交互记录 sorted_users = sorted(data.keys(), key=lambda x: data[x]['timestamp']) tscv = TimeSeriesSplit(n_splits=n_splits) for train_idx, test_idx in tscv.split(sorted_users): train_users = [sorted_users[i] for i in train_idx] test_users = [sorted_users[i] for i in test_idx] train_data = {u: data[u] for u in train_users} test_data = {u: data[u] for u in test_users} yield train_data, test_data

4. 真实数据集测试对比

我们使用MovieLens 100K数据集进行测试,该数据集包含943位用户对1682部电影的10万条评分。

4.1 数据预处理

import pandas as pd from scipy.sparse import csr_matrix def load_movielens(path): ratings = pd.read_csv(path, sep='\t', names=['user_id', 'item_id', 'rating', 'timestamp']) # 创建用户-物品矩阵 n_users = ratings['user_id'].nunique() n_items = ratings['item_id'].nunique() matrix = csr_matrix((ratings['rating'], (ratings['user_id'], ratings['item_id'])), shape=(n_users, n_items)) return matrix # 加载数据 ml_100k = load_movielens('ml-100k/u.data')

4.2 算法性能对比

运行各算法并记录评估结果:

算法命中率(HR@10)平均倒数排名(MRR)RMSE训练时间(s)
余弦相似度0.3420.1560.8921.2
皮尔逊系数0.3650.1720.8653.8
Jaccard0.2810.121N/A0.9
欧氏距离0.3120.1420.9121.5
Slope One0.3780.1850.8432.4

关键发现:

  1. Slope One在评分预测准确度(RMSE)上表现最佳
  2. 皮尔逊系数在排序质量(MRR)上优于基础余弦相似度
  3. Jaccard虽然计算效率高,但仅适用于二元场景
  4. 综合来看,改进的余弦相似度在精度和效率间取得了较好平衡

5. 工程优化技巧

5.1 稀疏矩阵优化

利用scipy.sparse加速计算:

from scipy.sparse import lil_matrix def sparse_cosine_sim(matrix): # 归一化每行 norms = np.sqrt(matrix.multiply(matrix).sum(axis=1)) matrix = matrix.multiply(1 / norms) # 计算相似度 return matrix.dot(matrix.T)

5.2 近似最近邻(ANN)

当物品数量超过1万时,使用近似算法:

from sklearn.neighbors import NearestNeighbors def ann_sim(matrix, n_neighbors=100): # 使用LSH森林加速 nbrs = NearestNeighbors(n_neighbors=n_neighbors, algorithm='lsh', metric='cosine').fit(matrix.T) distances, indices = nbrs.kneighbors(matrix.T) # 构建稀疏相似矩阵 n_items = matrix.shape[1] sim_matrix = lil_matrix((n_items, n_items)) for i in range(n_items): sim_matrix[i, indices[i]] = 1 - distances[i] return sim_matrix.tocsr()

5.3 多线程计算

利用joblib并行化:

from joblib import Parallel, delayed def parallel_sim(matrix, n_jobs=4): n_items = matrix.shape[1] def compute_row(i): return cosine_similarity(matrix[:,i].T, matrix.T) results = Parallel(n_jobs=n_jobs)( delayed(compute_row)(i) for i in range(n_items)) return np.vstack(results)

在实际项目中,相似度算法的选择需要结合业务场景和数据特性。对于电商推荐,Jaccard系数可能更适合处理点击流数据;而对于内容平台,基于TF-IDF的余弦相似度能更好捕捉文本语义。

相关新闻

  • 第五章第二节:循环结构(while/do-while/for)
  • 医美仪器配件采购:兼顾性价比与量产稳定性选型思路
  • Windows和Office智能激活终极指南:5分钟完成永久激活

最新新闻

  • 2026年低残粉咖啡刀盘哪家产品比较好:佛山隆易科技专业做刀盘更权威
  • VLA策略失败检测:时序对比学习实现工业级静默失效拦截
  • 足球分析软件技术架构解析:从足球数据分析到赛事预测模型实现
  • 多参考视觉地点识别:面向动态城市的判别性投影方法
  • CNN 卷积神经网络 5 大核心层实战解析:从 AlexNet 到 ResNet 的代码演进
  • 财政厅最新规定:主观评审因素不得采用 “好、较好、一般” 等模糊表述!

日新闻

  • PROPKA 3深度解析:蛋白质pKa预测的实战指南与算法原理
  • 微信小程序 globalData 监听:基于 Object.defineProperty 的 3 种实现方案对比
  • MySQL 8.0 数据清洗实战:3类异常值识别与 UPDATE/DELETE 批量处理

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号