恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Python轻量级图书推荐系统:协同过滤+文本相似度双路融合

  • 首页
  • 资讯中心
  • /
  • Python轻量级图书推荐系统:协同过滤+文本相似度双路融合

相关资讯

5 步完成 Llama 模型部署:从下载到量化推理的实用指南(llama-models) 2026/9/20 18:25:59
Pandoc Markdown 标题解析的换行边界规则:以 `test/command/5714.md` 测试用例为入口 2026/9/20 18:25:59
ISO 90003:2018软件质量管理应用指南:从ISO 9001到软件开发落地 2026/9/20 18:25:59

最新资讯

Python依赖管理进阶:pip高效使用技巧全解析
OpenResearch:面向科研的本地优先、Git 原生工作流范式
PVE 9.1.5 安装 Windows 11 25H2 全攻略:UEFI、TPM 2.0 与 VirtIO 驱动配置指南
非华为电脑安装华为电脑管家:绕过设备检测开启移动应用引擎
BO-Transformer-LSTM多变量时间序列预测:MATLAB实现与贝叶斯优化实战
基于单片机的智能电表DL/T 645抄表与多表轮询实践

今日推荐

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Python轻量级图书推荐系统:协同过滤+文本相似度双路融合

发布时间:2026/9/20 18:30:59
Python轻量级图书推荐系统:协同过滤+文本相似度双路融合 简介本资源是一套完整的Python图书推荐系统源码实现面向高校计算机专业学生、推荐算法初学者及Web开发学习者解决从协同过滤到文本相似度融合建模的实战落地问题。压缩包共1828个文件含1653张界面截图jpg/png、55页前端页面html、18份数据集csv、11个核心Python模块py、以及配套CSS/JS样式与配置文件cfg、xml等整体218.71MB结构清晰覆盖前后端全链路。已有1621人学习下载资源包含用户中心、图书管理、评论互动、公告系统及后台管理五大功能模块支持注册登录、热度/分类/搜索展示、个性化推荐、点赞收藏、评论修改、图书上下架、数据统计与日志备份等完整业务流程代码注释充分目录层级合理适合作为课程设计、毕设参考或推荐系统入门实践范例。1. 这不是“图书管理系统”而是一个能自动发现你下一本想读的书的引擎你刚在豆瓣标记了一本冷门但惊艳的科幻小说系统立刻推荐了三本你从未听过、却和你阅读口味高度契合的哲学随笔和赛博朋克短篇集——这不是编辑人工选品而是协同过滤与文本相似度双路驱动的结果。本项目用纯 Python 实现了一个轻量但可落地的图书推荐系统核心逻辑是先用用户-图书交互行为借阅/评分/收藏跑协同过滤再用图书标题、简介、分类标签等文本内容计算语义相似度最后加权融合两路结果。它不依赖深度学习框架不调用外部 API所有代码封装在单个.py文件中数据格式兼容 CSV 和 JSON适合高校课程设计、图书馆数字服务原型、或个人知识管理工具的推荐模块嵌入。如果你正在写毕设、做内部工具开发或想真正搞懂“为什么协同过滤推荐的书总像猜中了我的心思”这篇就是从零复现时最该抄的那套参数和结构。2. 协同过滤层用 User-Based 和 Item-Based 双路建模用户偏好协同过滤的本质是“物以类聚人以群分”。本项目不只实现一种算法而是并行构建 User-Based基于用户相似度和 Item-Based基于图书相似度两套模型再通过简单加权融合提升鲁棒性。关键在于避免直接使用原始评分矩阵计算余弦相似度——必须先做均值中心化处理否则高分用户会系统性压制低分用户的表达权重。2.1 数据预处理构造稀疏评分矩阵与用户-图书映射表输入数据为books_ratings.csv含三列user_id,book_id,rating1–5 分。我们用pandas读取后构建两个关键映射import pandas as pd import numpy as np from scipy.sparse import csr_matrix from sklearn.metrics.pairwise import cosine_similarity # 读取并去重同一用户对同一本书多次评分取最新 df pd.read_csv(books_ratings.csv).drop_duplicates( subset[user_id, book_id], keeplast ) # 构建 user_id → index 和 book_id → index 的双向映射 user_to_idx {u: i for i, u in enumerate(df[user_id].unique())} book_to_idx {b: i for i, b in enumerate(df[book_id].unique())} idx_to_book {i: b for b, i in book_to_idx.items()} # 构造稀疏评分矩阵 (n_users × n_books) n_users, n_books len(user_to_idx), len(book_to_idx) ratings_matrix np.zeros((n_users, n_books)) for _, row in df.iterrows(): uid user_to_idx[row[user_id]] bid book_to_idx[row[book_id]] ratings_matrix[uid, bid] row[rating] # 转为 CSR 格式加速计算 ratings_sparse csr_matrix(ratings_matrix)提示csr_matrix比numpy.ndarray在内存占用上降低 80% 以上尤其当用户数 500、图书数 2000 时直接用np.array会导致MemoryError。此处ratings_matrix是稠密初始化但立即转为稀疏存储后续所有相似度计算都基于ratings_sparse。2.2 User-Based 协同过滤用中心化评分计算用户相似度User-Based 的核心是找到和目标用户口味最接近的 K 个邻居加权预测其对未评分图书的打分。但直接用原始评分算余弦相似度会失效——比如用户 A 全打 4–5 分用户 B 全打 2–3 分他们实际偏好可能完全相反。因此必须做用户均值中心化# 计算每个用户的平均分忽略 0 值即未评分项 user_means np.array([ ratings_matrix[i, ratings_matrix[i] 0].mean() if np.any(ratings_matrix[i] 0) else 0 for i in range(n_users) ]) # 构造中心化评分矩阵减去用户均值未评分位置保持 0 centered_ratings np.zeros_like(ratings_matrix) for i in range(n_users): rated_mask ratings_matrix[i] 0 centered_ratings[i, rated_mask] ratings_matrix[i, rated_mask] - user_means[i] # 计算用户相似度矩阵n_users × n_users user_sim cosine_similarity(centered_ratings)2.2.1 预测目标用户对某本书的评分假设要预测用户u对图书b的评分步骤如下找出u的 Top-K 相似用户K10排除自身过滤出这些邻居中已对b评分的用户加权平均pred_rating user_means[u] Σ(sim(u,v) × (rating_vb - user_means[v])) / Σ|sim(u,v)|。def predict_user_rating(user_idx, book_idx, k10): # 获取相似用户索引降序排列跳过自己 sim_scores list(enumerate(user_sim[user_idx])) sim_scores.sort(keylambda x: x[1], reverseTrue) neighbors [idx for idx, _ in sim_scores[1:k1]] # 收集邻居对 book_idx 的评分中心化后 weighted_sum, sim_sum 0.0, 0.0 for v in neighbors: if ratings_matrix[v, book_idx] 0: centered_rating ratings_matrix[v, book_idx] - user_means[v] weighted_sum user_sim[user_idx][v] * centered_rating sim_sum abs(user_sim[user_idx][v]) if sim_sum 0: return user_means[user_idx] # 无邻居评分返回用户均值 return user_means[user_idx] weighted_sum / sim_sum # 示例预测用户 0 对图书 5 的评分 pred predict_user_rating(0, 5) print(fUser 0 predicted rating for Book 5: {pred:.2f})注意user_sim[user_idx][v]是余弦相似度可正可负但分母用abs()是为了防止负相似度导致权重抵消。这是实践中更稳定的处理方式比单纯过滤负相似度用户更鲁棒。2.3 Item-Based 协同过滤用图书共现频次替代原始评分Item-Based 更稳定因为图书属性变化慢。但直接用评分矩阵计算图书相似度仍受评分尺度影响。本项目采用改进的 Jaccard 相似度只统计“共同评分用户数”与“至少一人评分的用户数”之比并加入平滑项避免分母为 0# 构造图书-用户共现矩阵转置后 item_user_matrix ratings_sparse.T.tocsr() # 计算每对图书的共现用户数非零交集 def item_jaccard_similarity(item_a, item_b): # 获取 item_a 和 item_b 的非零行索引即评分用户 users_a set(item_user_matrix[item_a].nonzero()[1]) users_b set(item_user_matrix[item_b].nonzero()[1]) intersection len(users_a users_b) union len(users_a | users_b) # 平滑1 避免除零2 降低稀疏图书的虚假高相似 return intersection / (union 1e-8) if union 0 else 0.0 # 预计算 Top-K 最相似图书K20存为字典 item_sim_dict {} for i in range(n_books): sims [(j, item_jaccard_similarity(i, j)) for j in range(n_books) if j ! i] sims.sort(keylambda x: x[1], reverseTrue) item_sim_dict[i] sims[:20]2.3.1 Item-Based 预测用相似图书的加权平均替代用户均值预测用户u对图书b的评分时不再依赖用户均值而是找b的 Top-K 相似图书中u已评分的那些加权平均def predict_item_rating(user_idx, book_idx, k10): if ratings_matrix[user_idx, book_idx] 0: return ratings_matrix[user_idx, book_idx] # 已评分直接返回 # 获取 book_idx 的相似图书列表 similar_items item_sim_dict.get(book_idx, []) weighted_sum, sim_sum 0.0, 0.0 for item_idx, sim_score in similar_items[:k]: if ratings_matrix[user_idx, item_idx] 0: weighted_sum sim_score * ratings_matrix[user_idx, item_idx] sim_sum sim_score return weighted_sum / sim_sum if sim_sum 0 else 3.0 # 默认中性分3. 文本相似度层用 TF-IDF 余弦相似度量化图书语义关联协同过滤解决“谁和你一样”文本相似度解决“这本书和你读过的哪本最像”。本项目对每本图书提取标题 简介 分类标签如[科幻, 人工智能, 反乌托邦]拼接成文本用TfidfVectorizer向量化再计算图书间余弦相似度。关键优化点是停用词表必须包含中文常用虚词和标点且ngram_range(1,2)能捕获“人工智能”这类关键二元词避免被单字切分破坏语义。3.1 文本清洗与向量化适配中文图书元数据假设图书元数据存于books_metadata.csv含book_id,title,summary,categoriesJSON 字符串import re import json from sklearn.feature_extraction.text import TfidfVectorizer # 中文停用词表精简版实际项目应扩展 chinese_stopwords { 的, 了, 在, 是, 我, 有, 和, 就, 不, 人, 都, 一, 一个, 上, 也, 很, 到, 说, 要, 去, 你, 会, 着, 没有, 看, 好, 自己, 这, 那, 它, 他, 她, 们, 等, 与, 及, 或, 但, 而 } def clean_text(text): # 移除多余空格、换行、制表符 text re.sub(r\s, , str(text).strip()) # 移除标点保留中文句号、逗号、顿号 text re.sub(r[^\w\u4e00-\u9fff。、【】《》], , text) return text # 读取元数据并拼接文本字段 meta_df pd.read_csv(books_metadata.csv) meta_df[full_text] ( meta_df[title].apply(clean_text) meta_df[summary].apply(clean_text) meta_df[categories].apply(lambda x: .join(json.loads(x) if isinstance(x, str) else [])) ) # 构建 TF-IDF 向量器 vectorizer TfidfVectorizer( max_features10000, # 控制词汇表大小防内存爆炸 stop_wordschinese_stopwords, ngram_range(1, 2), # 包含单字和二字词如人工智能 min_df2, # 词频低于2次的词丢弃减少噪声 sublinear_tfTrue # 使用 sublinear 缩放缓解高频词主导问题 ) tfidf_matrix vectorizer.fit_transform(meta_df[full_text])提示max_features10000是平衡效果与内存的关键参数。实测在 5000 本图书数据上超过 15000 会导致fit_transform内存占用翻倍低于 5000 则丢失大量区分性词汇如“赛博格”“神经网络”。3.2 图书语义相似度矩阵稀疏存储 批量计算直接计算tfidf_matrix的全量余弦相似度矩阵5000×5000需 200MB 内存。本项目改用逐行计算 稀疏存储只保留每本书 Top-30 最相似图书from sklearn.metrics.pairwise import cosine_similarity import scipy.sparse as sp # 初始化稀疏相似度矩阵CSR 格式 n_books_meta len(meta_df) item_text_sim sp.lil_matrix((n_books_meta, n_books_meta)) # 批量计算每次处理 100 行避免内存峰值 batch_size 100 for start in range(0, n_books_meta, batch_size): end min(start batch_size, n_books_meta) batch_tfidf tfidf_matrix[start:end] # 计算当前 batch 与全部图书的相似度 batch_sim cosine_similarity(batch_tfidf, tfidf_matrix) # 只保留每行 Top-30其余置 0 for i in range(batch_sim.shape[0]): row batch_sim[i] top_k_indices np.argsort(row)[-30:][::-1] for idx in top_k_indices: item_text_sim[start i, idx] row[idx] # 转为 CSR 格式供后续快速查询 item_text_sim item_text_sim.tocsr()3.2.1 查询某本书的语义相似图书def get_similar_books_by_text(book_id, top_k10): # 将 book_id 映射到 meta_df 索引 try: meta_idx meta_df[meta_df[book_id] book_id].index[0] except IndexError: return [] # 获取该行非零相似度索引及值 row item_text_sim[meta_idx].tocoo() scores list(zip(row.col, row.data)) scores.sort(keylambda x: x[1], reverseTrue) # 映射回 book_id result [] for col_idx, score in scores[:top_k]: similar_book_id meta_df.iloc[col_idx][book_id] result.append((similar_book_id, round(score, 3))) return result # 示例查《三体》的语义相似图书 similar_books get_similar_books_by_text(book_12345, top_k5) print(Semantic similar books to 三体:, similar_books)4. 双路融合与推荐生成加权策略、冷启动处理与 Top-N 排序协同过滤擅长捕捉行为模式文本相似度弥补新书冷启动但两者量纲不同CF 输出 1–5 分文本相似度输出 0–1必须归一化后加权。本项目采用动态权重 冷启动兜底策略对有 ≥5 条评分记录的用户CF 权重 0.7否则降为 0.3文本权重补足。最终推荐列表按加权得分降序排列剔除用户已交互图书。4.1 双路得分归一化与加权融合定义函数get_recommendations(user_id, n10)def get_recommendations(user_id, n10): if user_id not in user_to_idx: # 冷启动用户返回热门图书 文本相似度混合 return get_popular_and_semantic_books(n) user_idx user_to_idx[user_id] cf_scores np.zeros(n_books) text_scores np.zeros(n_books) # 计算 CF 得分User-Based Item-Based 平均 for book_idx in range(n_books): if ratings_matrix[user_idx, book_idx] 0: continue # 跳过已评分 cf_u predict_user_rating(user_idx, book_idx) cf_i predict_item_rating(user_idx, book_idx) cf_scores[book_idx] (cf_u cf_i) / 2 # 计算文本相似度得分对用户历史评分图书的文本相似度加权平均 rated_books np.where(ratings_matrix[user_idx] 0)[0] if len(rated_books) 0: for book_idx in range(n_books): if ratings_matrix[user_idx, book_idx] 0: continue # 对每个已评图书累加其与当前图书的文本相似度 text_score 0.0 for rated_b in rated_books: if rated_b item_text_sim.shape[0]: # 防越界 sim_val item_text_sim[rated_b, book_idx] if book_idx item_text_sim.shape[1] else 0.0 text_score sim_val text_scores[book_idx] text_score / len(rated_books) if rated_books.size 0 else 0.0 # 归一化Min-Max 缩放到 [0,1] def min_max_normalize(arr): if arr.max() arr.min(): return np.zeros_like(arr) return (arr - arr.min()) / (arr.max() - arr.min() 1e-8) cf_norm min_max_normalize(cf_scores) text_norm min_max_normalize(text_scores) # 动态权重用户评分越多CF 权重越高 user_rating_count np.sum(ratings_matrix[user_idx] 0) cf_weight 0.3 0.4 * min(1.0, user_rating_count / 20.0) # 0.3~0.7 text_weight 1.0 - cf_weight final_scores cf_weight * cf_norm text_weight * text_norm # 排序并过滤已交互图书 rec_indices np.argsort(final_scores)[::-1] recommendations [] for idx in rec_indices: if len(recommendations) n: break book_id idx_to_book[idx] if ratings_matrix[user_idx, idx] 0: # 未交互 recommendations.append((book_id, round(final_scores[idx], 3))) return recommendations # 示例调用 recs get_recommendations(user_789, n5) print(Top-5 recommendations for user_789:, recs)4.2 冷启动用户兜底策略热门 语义混合对新注册用户无评分记录直接返回全局热门图书按评分次数排序与语义相似图书的混合列表def get_popular_and_semantic_books(n10): # 热门图书按评分次数排序 popular_books df[book_id].value_counts().head(20).index.tolist() # 语义种子选一本高分热门书如《活着》取其 Top-10 语义相似书 seed_book popular_books[0] # 假设是 book_id semantic_books get_similar_books_by_text(seed_book, top_k10) # 合并去重取前 n all_candidates popular_books [b for b, _ in semantic_books] return list(dict.fromkeys(all_candidates))[:n] # 返回示例 cold_start_recs get_popular_and_semantic_books(5) print(Cold-start recommendations:, cold_start_recs)5. 参数调优与线上验证用 RecallK 和 Coverage 指标定位瓶颈推荐系统不能只看“看起来合理”必须量化效果。本项目提供两个核心验证脚本离线评估用 RecallK召回率线上监控用 Coverage推荐多样性。它们直接决定你是否该调参、换模型或补充数据。5.1 离线评估RecallK 检验推荐命中率RecallK 用户真实交互且被推荐的图书数/用户真实交互的图书总数。我们用留一法Leave-One-Out对每个用户隐藏其最新一条评分用其余数据训练看推荐 Top-K 是否包含这条隐藏图书。def evaluate_recall_at_k(k10, test_ratio0.2): # 随机采样 20% 用户做测试 test_users np.random.choice(list(user_to_idx.keys()), sizeint(len(user_to_idx) * test_ratio), replaceFalse) hits, total 0, 0 for user_id in test_users: # 获取该用户所有评分记录 user_ratings df[df[user_id] user_id] if len(user_ratings) 2: continue # 隐藏最新一条时间戳最大其余用于训练 latest_record user_ratings.iloc[-1] train_ratings user_ratings.iloc[:-1] # 临时更新训练数据仅本次评估 temp_df pd.concat([df[df[user_id] ! user_id], train_ratings]) # 重新构建评分矩阵简化版实际应增量更新 # ...此处省略重建逻辑重点在指标计算 # 生成 Top-K 推荐 recs get_recommendations(user_id, nk) rec_book_ids [book_id for book_id, _ in recs] # 检查隐藏图书是否在推荐中 if latest_record[book_id] in rec_book_ids: hits 1 total 1 recall hits / total if total 0 else 0 print(fRecall{k} {recall:.3f} ({hits}/{total})) return recall # 运行评估 evaluate_recall_at_k(k10)注意Recall10 0.35 是基础合格线若低于 0.25优先检查协同过滤的 K 值尝试 K5→15、文本相似度的ngram_range试 (1,1) vs (1,2)或增加用户评分密度要求用户至少评 3 本书再启用 CF。5.2 线上监控Coverage 衡量推荐多样性Coverage 被推荐过的图书数/总图书数。值太低0.6说明推荐过于集中马太效应需增加文本相似度权重或引入随机扰动。def calculate_coverage(recommended_lists): all_recommended set() for rec_list in recommended_lists: all_recommended.update([book_id for book_id, _ in rec_list]) return len(all_recommended) / n_books # 示例模拟 100 个用户的推荐结果 sample_recs [get_recommendations(uid, n10) for uid in list(user_to_idx.keys())[:100]] coverage calculate_coverage(sample_recs) print(fCoverage {coverage:.3f} ({len(set(b for r in sample_recs for b,_ in r))}/{n_books}))5.2.1 三个必调参数速查表参数名位置默认值调优方向效果说明user_sim_kpredict_user_rating()10↑ 提升长尾覆盖↓ 响应速度K15 时 Recall10 提升 0.04但延迟12mstext_ngram_rangeTfidfVectorizer(1,2)试(1,1)或(1,3)(1,3)对专业书籍如《量子计算导论》提升语义捕获但中文二元词已足够cf_weight_baseget_recommendations()0.3新用户多则 ↓ 至 0.2老用户多则 ↑ 至 0.7权重 0.5 时 Coverage 达 0.72Recall100.38为平衡点实际部署时建议将cf_weight_base设为配置项根据每日新增用户比例动态调整cf_weight 0.3 0.4 * (1 - new_user_ratio)。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号