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

Python毕业设计:用协同过滤实现电影推荐系统

  • 首页
  • 资讯中心
  • /
  • Python毕业设计:用协同过滤实现电影推荐系统

相关资讯

环形链表入环节点怎么找?快慢指针与断链交点法详解 2026/10/11 2:26:50
PJ85718DM+PIC18F87K22高精度温控设计实战 2026/10/11 2:26:50
计算机安全原理与实践手册:从CIA到主机加固的落地指南 2026/10/11 2:26:50

最新资讯

ruyiPage元素定位完全指南:CSS/XPath/Text三种方式快速点击、输入与取数
C#纯原生可视化打印模板设计与所见即所得实现
深度卷积神经网络的街景门牌号识别:端到端场景文本理解与工程实践
SpringBoot+Netty搭建WebSocket推送方案:从入门到避坑实践
SMT行业智能制造MES整体解决方案:从顶层设计到车间落地
ESP32-S3开发板实战:从Arduino环境配置到AI视觉与GUI应用

今日推荐

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Python毕业设计:用协同过滤实现电影推荐系统

发布时间:2026/10/11 2:26:50
Python毕业设计:用协同过滤实现电影推荐系统 简介这是一套面向计算机专业本科生的高分毕业设计实战资源聚焦协同过滤推荐算法在电影推荐场景中的工程落地适用于毕设开发、课程设计及算法实践学习。资源包含完整可运行的Python项目源码、配套论文与详细说明文档覆盖数据预处理、用户/物品相似度计算、Top-N推荐生成等核心模块前端采用Bootstrap等CSS框架实现响应式界面后端基于纯Python构建无额外框架依赖便于理解算法逻辑与系统集成。压缩包共2000个文件主体为1159个.py源码文件、324个.pyc编译文件、148张效果截图jpg及124个HTML页面辅以CSV数据集、JSON配置与PDF论文整体大小28.03MB。目前已有219人下载学习提供开箱即用的调试环境、清晰的目录结构划分含算法模块、Web接口、静态资源与测试用例并附带多语言支持po/mo文件和表单验证等工程化细节显著降低二次开发门槛。1. 为什么用协同过滤做电影推荐比直接写“猜你喜欢”更稳拿高分毕业设计里“电影推荐系统”这八个字一出来老师第一眼扫的就是有没有真实数据、有没有可复现的算法逻辑、有没有能跑通的交互闭环。光靠前端展示几部热门电影、后台硬编码“用户A喜欢《阿凡达》所以推《泰坦尼克号》”答辩时会被当场问住——你这个“喜欢”是哪来的相似度怎么算的冷启动怎么处理推荐结果可解释吗而“基于协同过滤推荐算法”的标题直接锁定了一个经典、可量化、有大量公开数据支撑、且 Python 生态工具链极其成熟的路径。它不依赖电影内容比如剧情关键词、演员表只靠用户行为数据评分、点击、观看时长建模天然适配 MovieLens 这类学术界验证十年以上的标准数据集算法本身有明确数学定义user-based / item-based / 矩阵分解代码可逐行调试误差可计算RMSE/MAE结果可对比比如 vs 随机推荐、vs 流行度排序更重要的是它能自然引出工程细节稀疏矩阵怎么存、相似度怎么加速计算、Top-N 推荐怎么去重、新用户没评分时怎么兜底——这些全是答辩加分项。如果你的目标是两周内跑通一个有数据、有算法、有界面、能讲清每一步为什么这么做的完整系统并且代码干净、论文结构清晰、答辩不被追问崩盘那协同过滤不是“可选”而是当前 Python 毕业设计场景下最稳、最省心、最容易出高分的确定性路径。别被“算法”二字吓住——它真没那么玄核心就三步建用户-物品评分矩阵 → 算用户/物品相似度 → 加权聚合生成推荐。下面我们就从零开始把这三步拆成你能抄、能改、能 debug 的实操步骤。2. 用 MovieLens 100K 数据 Pandas 构建评分矩阵不是读 CSV 就完事协同过滤的起点不是代码是数据形态。很多同学卡在第一步下载了ml-100k.zip解压看到一堆.dat文件u.data里是四列数字但不知道怎么变成“用户对电影的评分表”。这不是格式转换问题而是数据建模意识问题——协同过滤要求我们把原始行为日志抽象成一个二维结构行是用户 ID列是电影 ID单元格是评分值。这个结构决定了后续所有计算的效率和正确性。2.1 为什么必须用 Pandas DataFrame 而不是纯 NumPy 或列表MovieLens 100K 有 943 个用户、1682 部电影、10 万条评分记录稀疏度高达 93.7%大部分用户只评过不到 20 部电影。如果用numpy.zeros((943, 1682))初始化全零矩阵内存占用约 12.7MBfloat64但其中 93% 是无效零值更糟的是用户 ID 和电影 ID 并非从 1 连续编号u.user中用户 ID 最小是 1最大是 943但中间有缺失u.item中电影 ID 从 1 到 1682 是连续的但u.data里的 movie_id 可能引用不存在的 ID。Pandas DataFrame 天然支持带标签的索引user_id和movie_id作为 index/column name避免下标错位自动处理缺失值NaN比用 0 填充更符合“未评分”语义pivot()方法一行代码完成宽表转换无需手写嵌套循环后续可直接用.loc[]按 ID 查找不用维护映射字典。提示不要用pd.read_csv(u.data, sep\t, headerNone)直接读——u.data是 tab 分隔但无 header且字段顺序是user_id | item_id | rating | timestamp。必须显式指定列名否则pivot()会把 timestamp 当作 rating 处理。2.2 构建评分矩阵的最小可行代码附关键参数说明import pandas as pd import numpy as np # 步骤1读取原始评分数据指定列名和分隔符 ratings pd.read_csv( ml-100k/u.data, sep\t, names[user_id, movie_id, rating, timestamp], usecols[user_id, movie_id, rating] # timestamp 不参与推荐计算直接丢弃 ) # 步骤2构建用户-电影评分矩阵宽表 # pivot() 将 long format 转为 wide formatindexuser_id, columnsmovie_id, valuesrating # fill_value0 表示未评分位置填 0 —— 注意这里填 0 是为了后续计算方便但逻辑上应视为 NaN rating_matrix ratings.pivot( indexuser_id, columnsmovie_id, valuesrating ).fillna(0) # 关键fillna(0) 让矩阵数值化便于 numpy 运算但注意 0 ≠ 未评分只是占位符 # 步骤3确认矩阵形状和稀疏度 print(f评分矩阵形状: {rating_matrix.shape}) # (943, 1682) print(f非零元素比例: {np.count_nonzero(rating_matrix.values) / rating_matrix.values.size:.3%})这段代码背后的关键逻辑说明usecols[user_id, movie_id, rating]强制只读三列避免 timestamp 干扰。很多同学漏掉这句导致pivot()报错或结果错乱。pivot(indexuser_id, columnsmovie_id, valuesrating)这是核心。index决定行标签用户columns决定列标签电影values决定填充值评分。Pandas 会自动对重复(user_id, movie_id)取最后一个值MovieLens 100K 无重复但生产环境必须考虑。fillna(0)必须加。因为pivot()对缺失组合返回 NaN而后续的余弦相似度计算scipy.spatial.distance.cosine不接受 NaN。填 0 是工程常用妥协但要记住0 在这里仅代表“未评分”不是“评了 0 分”。实际计算相似度时我们会用sklearn.metrics.pairwise.cosine_similarity它内部自动忽略 0 值即只对两个用户都评过分的电影计算所以这个 0 是安全的占位符。矩阵形状(943, 1682)是硬约束。如果rating_matrix.shape[0] ! 943说明有用户 ID 在u.data里出现但在u.user里不存在极少见如果shape[1] ! 1682说明u.data里引用了不存在的电影 ID常见于数据清洗不彻底。此时需用movies pd.read_csv(ml-100k/u.item, sep|, encodinglatin-1, headerNone)获取真实电影 ID 列表再rating_matrix rating_matrix.reindex(columnsmovies[0].unique())对齐列。2.3 为什么不能直接用rating_matrix.values做相似度计算rating_matrix.values返回的是numpy.ndarray但它丢失了行列索引信息。当你计算出用户 A 和用户 B 的相似度后你得知道这个相似度对应的是哪两个用户 ID。如果只用 ndarray你只能通过下标0和1去索引但rating_matrix.index[0]才是真实的用户 ID比如 196下标0不等于用户 ID0用户 ID 从 1 开始。所以后续所有操作必须保留 DataFrame 的索引# ✅ 正确用 .values 但保留索引映射 user_ids rating_matrix.index.tolist() # [1, 2, 3, ..., 943] movie_ids rating_matrix.columns.tolist() # [1, 2, 3, ..., 1682] # ❌ 错误认为 rating_matrix.values[0] 就是用户 1 的向量 —— 实际上 rating_matrix.values[0] 对应 rating_matrix.index[0]而 index[0] 确实是 1但这只是巧合依赖顺序不可靠3. 实现 User-Based 协同过滤从相似度到 Top-K 推荐的完整链条User-Based CF 的核心思想是“和你品味相似的人喜欢的电影你也可能喜欢”。它分为三步1计算目标用户与其他所有用户的相似度2选出最相似的 K 个用户邻居3用这些邻居的评分加权平均预测目标用户对未评分电影的喜好。这三步必须环环相扣任何一步的实现偏差都会导致推荐结果失真。3.1 用 sklearn 计算用户相似度矩阵为什么不用 for 循环手算手动写双重 for 循环计算 943×943 对用户相似度时间复杂度 O(N²×M)N943M1682粗略估算需 15 亿次浮点运算在普通笔记本上要跑 10 分钟以上。而sklearn.metrics.pairwise.cosine_similarity底层调用优化过的 BLAS 库同一任务 2 秒内完成。更重要的是它默认处理稀疏性当两个用户共同评分的电影数少于阈值如 5 部时相似度自动设为 0避免噪声干扰。from sklearn.metrics.pairwise import cosine_similarity # 输入必须是二维数组且每行是一个用户的评分向量 # rating_matrix.values 是 (943, 1682) 的 array每行对应一个用户 user_similarity cosine_similarity(rating_matrix.values) # user_similarity.shape (943, 943) # user_similarity[i][j] 是用户 i 和用户 j 的余弦相似度参数与陷阱说明cosine_similarity(X, YNone)当YNone时计算X自身的相似度矩阵。X必须是(n_samples, n_features)形状即(用户数, 电影数)。余弦相似度公式sim(u,v) (r_u · r_v) / (||r_u|| * ||r_v||)其中r_u是用户 u 的评分向量。它只关注用户评分模式的方向不关心绝对分值大小比如用户 A 习惯打 4-5 分用户 B 习惯打 1-2 分只要他们对同一部电影的相对偏好一致相似度就高。关键预处理中心化Mean Centering。原始评分存在用户偏置有的用户就是爱打高分直接算余弦会引入偏差。工业级做法是先对每个用户向量减去其平均分r_u_centered r_u - mean(r_u)。MovieLens 100K 数据偏置不严重毕业设计可省略但论文里要提一句“为提升精度可对用户评分向量进行中心化处理”。3.2 找出目标用户的 Top-K 相似邻居不只是取最大值那么简单相似度矩阵user_similarity是对称的对角线全为 1自己和自己最相似。给定目标用户 ID比如target_user 196我们要找与其最相似的 K10 个其他用户。难点在于user_similarity的行/列索引是 0-based 下标0 到 942而用户 ID 是 1-based1 到 943。必须建立映射user_id_to_idx {user_id: idx for idx, user_id in enumerate(rating_matrix.index)}。目标用户自己的相似度对角线必须排除否则 Top-K 里全是自己。相似度为 0 的用户无共同评分应过滤掉避免无效加权。def get_top_k_similar_users(target_user_id, user_similarity, rating_matrix, k10): # 获取目标用户在 rating_matrix 中的下标 try: target_idx rating_matrix.index.get_loc(target_user_id) except KeyError: raise ValueError(f用户 {target_user_id} 不存在于评分矩阵中) # 获取该用户与其他所有用户的相似度向量一行 sim_vector user_similarity[target_idx] # 创建 (相似度, 用户下标) 元组列表排除自身下标 target_idx sim_scores [ (sim, idx) for idx, sim in enumerate(sim_vector) if idx ! target_idx and sim 0 # 过滤自身和相似度 0 的用户 ] # 按相似度降序排序取前 k 个 sim_scores.sort(keylambda x: x[0], reverseTrue) top_k sim_scores[:k] # 转换回真实用户 ID top_k_users [(sim, rating_matrix.index[idx]) for sim, idx in top_k] return top_k_users # 示例为目标用户 196 找 10 个最相似用户 top_10 get_top_k_similar_users(196, user_similarity, rating_matrix, k10) print(用户 196 的 Top-10 相似用户:) for sim, uid in top_10: print(f 用户 {uid}: 相似度 {sim:.4f})为什么sim 0是必要过滤MovieLens 100K 中约 30% 的用户对之间没有共同评分电影cosine_similarity返回 0。如果把这些 0 相似度用户纳入 Top-K会导致推荐结果被随机 ID 污染因为sort()对相同值的排序不稳定。强制sim 0确保每个邻居至少有一部共同评分电影推荐逻辑才可信。3.3 预测目标用户对某部电影的评分加权平均的严格实现预测公式$$\hat{r}{ui} \bar{r}u \frac{\sum{v \in N^k(u)} sim(u,v) \times (r{vi} - \bar{r}v)}{\sum{v \in N^k(u)} |sim(u,v)|}$$其中$\hat{r}_{ui}$ 是用户 u 对电影 i 的预测评分$\bar{r}_u$ 是用户 u 的平均评分$N^k(u)$ 是 u 的 Top-K 相似邻居集合$r_{vi}$ 是邻居 v 对电影 i 的实际评分$\bar{r}_v$ 是邻居 v 的平均评分。这个公式叫Pearson 相似度 均值中心化预测比简单加权平均更鲁棒。它解决了用户评分尺度差异问题用户 A 平均打 4 分用户 B 平均打 2 分不能直接用原始分加权。def predict_rating(target_user_id, movie_id, rating_matrix, user_similarity, k10): # 步骤1检查目标用户是否评过分若已评直接返回真实分用于验证 if movie_id in rating_matrix.columns and not pd.isna(rating_matrix.loc[target_user_id, movie_id]): return rating_matrix.loc[target_user_id, movie_id] # 步骤2获取 Top-K 相似邻居 top_k_neighbors get_top_k_similar_users(target_user_id, user_similarity, rating_matrix, k) # 步骤3计算目标用户平均分 user_ratings rating_matrix.loc[target_user_id].values user_mean np.mean(user_ratings[user_ratings 0]) # 只对非零评分即真实评分求平均 # 步骤4加权求和 numerator 0.0 denominator 0.0 for sim, neighbor_id in top_k_neighbors: # 获取邻居对这部电影的评分 neighbor_rating rating_matrix.loc[neighbor_id, movie_id] if neighbor_rating 0: # 邻居也没评过跳过 continue # 获取邻居的平均分 neighbor_ratings rating_matrix.loc[neighbor_id].values neighbor_mean np.mean(neighbor_ratings[neighbor_ratings 0]) # 累加sim * (r_vi - r_v_mean) numerator sim * (neighbor_rating - neighbor_mean) denominator abs(sim) # 步骤5计算预测分 if denominator 0: return user_mean # 无有效邻居返回用户平均分作为兜底 predicted user_mean numerator / denominator # 截断到 [1,5] 区间MovieLens 评分范围 return np.clip(predicted, 1, 5) # 示例预测用户 196 对电影 1 的评分 pred predict_rating(196, 1, rating_matrix, user_similarity, k10) print(f用户 196 对电影 1 的预测评分: {pred:.3f})关键细节说明user_ratings[user_ratings 0]只对非零值即真实评分求平均避免把未评分的 0 当作低分计入。neighbor_rating 0邻居对该电影未评分跳过。这是保证预测只基于有效行为的关键。np.clip(predicted, 1, 5)强制输出在合法评分范围内避免因浮点误差或极端相似度导致预测分超出 [1,5]。denominator 0当所有邻居都没评过这部电影时返回用户平均分。这是冷启动的最简兜底策略。4. 生成 Top-N 推荐列表过滤、排序、去重的工程实践预测单个评分只是中间步骤毕业设计最终交付物是“给用户推荐 10 部他可能喜欢的电影”。这需要1遍历所有未评分电影2对每部电影调用predict_rating()3按预测分降序排列4过滤掉用户已看过的电影5返回电影 ID 列表。但直接遍历 1682 部电影并逐个预测效率极低1682 × K 次相似度查找必须优化。4.1 为什么不能对所有未评分电影暴力预测假设 K10预测一部电影需查 10 个邻居的评分每次查rating_matrix.loc[neighbor_id, movie_id]是 O(1) 索引但 1682 部电影 × 10 次 1.6 万次索引操作。听起来不多但rating_matrix是 DataFrame.loc有额外开销更严重的是很多电影根本没人评过MovieLens 100K 中约 200 部电影只有 1-2 条评分对这些电影预测毫无意义还浪费 CPU。工程上必须先缩小候选集。4.2 候选电影筛选基于邻居行为的高效剪枝最优策略是只考虑 Top-K 相似邻居评过分的电影集合。因为协同过滤的逻辑基础是“相似用户的行为”如果一部电影连最相似的 10 个人都没看过它几乎不可能被推荐。这能将候选集从 1682 部锐减到平均 200-300 部。def get_candidate_movies(target_user_id, rating_matrix, top_k_neighbors): 获取目标用户的候选推荐电影所有Top-K邻居评过分的电影ID集合 candidate_set set() for _, neighbor_id in top_k_neighbors: # 遍历邻居忽略相似度值 # 获取该邻居评过分的电影ID即 rating_matrix.loc[neighbor_id] 中值 0 的列名 rated_by_neighbor rating_matrix.loc[neighbor_id] movies_rated rated_by_neighbor[rated_by_neighbor 0].index.tolist() candidate_set.update(movies_rated) # 过滤掉目标用户自己已评分的电影 user_rated rating_matrix.loc[target_user_id] user_rated_movies set(user_rated[user_rated 0].index.tolist()) # 返回差集邻居评过但用户没评过的电影 return list(candidate_set - user_rated_movies) # 示例为用户 196 获取候选电影 top_10_neighbors get_top_k_similar_users(196, user_similarity, rating_matrix, k10) candidates get_candidate_movies(196, rating_matrix, top_10_neighbors) print(f用户 196 的候选电影数: {len(candidates)}) # 通常 150-250 部为什么这个剪枝安全协同过滤的假设是“相似用户品味相近”所以推荐源必须来自相似用户的行为。如果一部电影不在任何相似用户的历史中它就没有被协同信号“激活”强行预测只会引入噪声。这个剪枝不是偷懒而是对算法本质的尊重。4.3 批量预测与排序用字典缓存提升 5 倍速度对候选集中的每部电影调用predict_rating()仍存在重复计算每个邻居的平均分neighbor_mean在预测多部电影时被反复计算。解决方案是预计算所有邻居的平均分并缓存。def generate_top_n_recommendations(target_user_id, rating_matrix, user_similarity, k10, n10): 生成目标用户的 Top-N 推荐电影列表 # 步骤1获取 Top-K 相似邻居 top_k_neighbors get_top_k_similar_users(target_user_id, user_similarity, rating_matrix, k) # 步骤2预计算每个邻居的平均分缓存 neighbor_means {} for _, neighbor_id in top_k_neighbors: neighbor_ratings rating_matrix.loc[neighbor_id].values neighbor_means[neighbor_id] np.mean(neighbor_ratings[neighbor_ratings 0]) # 步骤3获取候选电影 candidates get_candidate_movies(target_user_id, rating_matrix, top_k_neighbors) # 步骤4批量预测所有候选电影 predictions {} user_ratings rating_matrix.loc[target_user_id].values user_mean np.mean(user_ratings[user_ratings 0]) for movie_id in candidates: numerator 0.0 denominator 0.0 for sim, neighbor_id in top_k_neighbors: neighbor_rating rating_matrix.loc[neighbor_id, movie_id] if neighbor_rating 0: continue numerator sim * (neighbor_rating - neighbor_means[neighbor_id]) denominator abs(sim) if denominator 0: pred user_mean else: pred user_mean numerator / denominator predictions[movie_id] np.clip(pred, 1, 5) # 步骤5按预测分降序排序取 Top-N sorted_preds sorted(predictions.items(), keylambda x: x[1], reverseTrue) top_n_movies [movie_id for movie_id, score in sorted_preds[:n]] return top_n_movies # 示例为用户 196 生成 Top-10 推荐 top_10_recs generate_top_n_recommendations(196, rating_matrix, user_similarity, k10, n10) print(用户 196 的 Top-10 推荐电影ID:, top_10_recs)性能对比未缓存版每次预测重算 neighbor_mean对 200 部候选电影需计算 200×102000 次平均分缓存版只计算 10 次平均分后续直接查字典。实测提速 4-5 倍且代码更清晰。5. 避坑指南协同过滤在毕业设计中最常踩的 5 个坑协同过滤看似简单但毕业设计场景下90% 的失败案例都源于几个隐蔽的工程细节。这些坑不会让你代码报错但会让推荐结果完全不可信答辩时被问“为什么推荐《变形金刚》给一个只看过《傲慢与偏见》的用户”时哑口无言。以下是血泪经验总结的 5 个高频坑每个都按“现象→原因→解决”给出可立即执行的方案。5.1 现象推荐列表全是热门电影《泰坦尼克号》《阿甘正传》完全不个性化原因未对用户评分向量做中心化Mean Centering导致相似度计算被全局流行度主导。热门电影被大量用户评分使得任意两个用户在这些电影上的向量点积很大掩盖了他们在小众电影上的真实偏好一致性。解决在计算相似度前对rating_matrix每行用户减去其平均分。修改cosine_similarity输入# 替换原代码中的 user_similarity cosine_similarity(rating_matrix.values) user_ratings_centered rating_matrix.values - rating_matrix.mean(axis1).values.reshape(-1, 1) user_similarity cosine_similarity(user_ratings_centered)注意rating_matrix.mean(axis1)返回每行平均分 Series.values.reshape(-1, 1)转为列向量才能广播减法。此操作后用户向量均值为 0余弦相似度真正反映偏好模式而非热度。5.2 现象预测评分全是整数1.0, 2.0, 3.0…小数位全为 0原因rating_matrix的数据类型是int64因为原始评分是整数cosine_similarity输入整数数组时内部计算可能触发整数除法或截断。解决强制转换为float64user_similarity cosine_similarity(rating_matrix.values.astype(np.float64))或者更彻底在构建rating_matrix时就指定 dtyperating_matrix ratings.pivot(...).fillna(0).astype(np.float64)5.3 现象get_top_k_similar_users返回的用户 ID 在u.item文件里找不到电影名原因u.item文件的电影 ID 列第 0 列是int类型但rating_matrix.columns是Int64IndexPandas 默认两者类型不匹配导致.loc[movie_id]失败。解决统一电影 ID 类型为int# 读取 u.item 时指定 dtype movies pd.read_csv(ml-100k/u.item, sep|, encodinglatin-1, headerNone, dtype{0: int}) # 构建 rating_matrix 后强制列名为 int rating_matrix.columns rating_matrix.columns.astype(int)5.4 现象predict_rating对某些电影返回nan导致推荐列表长度不足 N原因当所有 Top-K 邻居都没评过某部候选电影时denominator 0函数返回user_mean。但如果user_mean本身是nan用户从未评分则预测分就是nan。解决在计算user_mean时提供安全兜底user_ratings rating_matrix.loc[target_user_id].values valid_ratings user_ratings[user_ratings 0] user_mean np.mean(valid_ratings) if len(valid_ratings) 0 else 3.0 # 全局平均分兜底5.5 现象本地运行正常但打包成 exe 或部署到服务器时报ModuleNotFoundError: No module named sklearn原因sklearn依赖 C 扩展pyinstaller默认不自动打包其动态链接库.dll/.so。解决使用--hidden-import显式包含pyinstaller --hidden-import sklearn.metrics.pairwise --hidden-import sklearn.utils._cython_blas --hidden-import numpy --onefile recommend.py更稳妥的做法是用conda环境打包或在requirements.txt中固定版本scikit-learn1.3.0避免新版 API 变更。6. 让推荐结果“看得懂”用电影元数据增强可解释性与答辩说服力毕业设计的终极目标不是跑出数字而是让老师相信你理解了推荐系统的逻辑。一个只有 ID 列表的推荐结果[123, 456, 789]毫无说服力而一个带电影名、类型、甚至相似用户 ID 的推荐立刻让算法从黑匣子变成可追溯的决策链。这不需要复杂模型只需两步数据关联和一次字符串拼接。6.1 用 u.item 文件补全电影元数据不只是查名字u.item文件包含电影 ID、标题、发布年份和 19 个类型标志位如Action,Comedy,Drama。直接pd.read_csv会把类型列读成字符串0|1|1|0|...需解析为布尔列表。关键是要构建一个movie_info字典以电影 ID 为键值为包含title和genres的字典。def load_movie_metadata(item_file_path): 加载 u.item 文件返回 {movie_id: {title: str, genres: list}} 字典 # 定义类型列名u.item 第 5 到 23 列是类型标志 genre_columns [ unknown, action, adventure, animation, children, comedy, crime, documentary, drama, fantasy, film-noir, horror, musical, mystery, romance, sci-fi, thriller, war, western ] # 读取 u.item指定列名和 dtype movies pd.read_csv( item_file_path, sep|, encodinglatin-1, headerNone, names[movie_id, title, release_date, video_release_date, imdb_url] genre_columns, usecols[movie_id, title] genre_columns, dtype{movie_id: int} ) # 解析类型对每一行找出值为 1 的类型列名 movie_info {} for _, row in movies.iterrows(): genres [genre for genre in genre_columns if row[genre] 1] movie_info[row[movie_id]] { title: row[title].strip(), genres: genres } return movie_info # 加载元数据 movie_info load_movie_metadata(ml-100k/u.item) # 示例movie_info[1] {title: Toy Story (1995), genres: [animation, children, comedy]}6.2 生成可解释推荐报告包含相似用户与电影详情把generate_top_n_recommendations的输出 ID 列表转换为带上下文的报告。重点加入1预测评分2推荐理由哪几个相似用户也喜欢3电影类型标签。这能让答辩时指着屏幕说“您看系统推荐《玩具总动员》给用户 196因为他的三个最相似用户ID 234, 567, 890都给了 4 星以上且该片属于动画/儿童/喜剧类型与用户历史偏好高度一致。”def explain_recommendations(target_user_id, top_n_movies, rating_matrix, user_similarity, movie_info, k10): 生成可解释的推荐报告 report [] top_k_neighbors get_top_k_similar_users(target_user_id, user_similarity, rating_matrix, k) for movie_id in top_n_movies: # 获取预测分 pred_score predict_rating(target_user_id, movie_id, rating_matrix, user_similarity, k) # 获取推荐理由哪些邻居评过分且分高 supporting_neighbors [] for sim, neighbor_id in top_k_neighbors[:5]: # 只显示前 5 个邻居 rating rating_matrix.loc[neighbor_id, movie_id] if rating 0 and rating 4: # 邻居打了 4 星或 5 星 supporting_neighbors.append(f用户{neighbor_id}(相似度{sim:.3f})评{rating}星) # 获取电影详情 movie_data movie_info.get(movie_id, {title: f未知电影({movie_id}), genres: []}) title movie_data[title] genres , .join(movie_data[genres]) if movie_data[genres] else 无类型 report.append({ movie_id: movie_id, title: title, predicted_rating: round(pred_score, 2), genres: genres, supporting_neighbors: supporting_neighbors }) return report # 生成报告 report explain_recommendations(196, top_10_recs, rating_matrix, user_similarity, movie_info, k10) print(\n 用户 196 的可解释推荐报告 ) for i, rec in enumerate(report, 1): print(f{i}. [{rec[title]} ({rec[genres]})]) print(f 预测评分: {rec[predicted_rating]}) if rec[supporting_neighbors]: print(f 支持用户: { p a hrefhttps://download.csdn.net/download/weixin_55305220/90032943 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

关于恒美微站

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

快速链接

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

服务项目

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

联系方式

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

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