
简介面向计算机相关专业毕业设计这套项目围绕基于用户行为的社交网络推荐算法展开。内容涵盖社交网络特征分析、用户关注/转发/点赞/评论等行为建模以及推荐模型设计原型系统实现了用户与物品商品、音乐、视频等的增加、删除、搜索、评价、排序、推荐等管理功能。压缩包共229个文件以94个js和72个vue为主辅以css、json、eslintrc等配置文件对应前后端分离的api与frontend模块整体约408KB结构紧凑易读。已有23人下载学习适合需要快速搭建推荐系统原型、理解用户行为推荐流程的毕设学生。包内附带README配置说明与演示网址可帮助完成环境配置与功能验证有效节省从零搭建项目的时间。1. 这套基于用户行为的社交网络推荐毕设到底在解决什么问题第一次拆开这个 zip 的时候我的第一反应是这不是那种只给你一堆推荐算法公式的毕业设计。它把“基于用户行为的社交网络推荐”拆成了两条可走通的主线一条是推荐模型本身另一条是能对用户、物品做增删改查并接上推荐结果的原型系统。演示地址在浏览器里打开后能看到用户行为点赞、评论、转发、评分到推荐列表的完整链路这个闭环比单独跑一个算法脚本要值钱得多。适合两类人一类是刚开始做推荐方向毕业设计、想知道用户行为数据怎么落到推荐模型里的学生另一类是已经会用协同过滤但一直没想清楚关注、转发这些行为如何参与建模的从业者。整个项目不是靠单一模型打天下而是把数据、权重、接口、页面串成了一条线这恰好是很多初学者的盲区。2. 推荐模型设计与用户行为特征从协同过滤到行为权重2.1 社交网络中的显式反馈与隐式反馈社交网络里的用户行为可以分成两类显式反馈和隐式反馈。评分、评价是最典型的显式反馈用户明确告诉系统“我喜欢这个物品”点赞、评论、转发、查看详情、停留时长则更多是隐式反馈用户没有直接打分但通过操作表达了对内容的倾向。关注行为在社交网络里也很特殊它代表一种长期偏好类似于“我认可这个人/这个作者”。这套毕设里的行为数据覆盖了点赞、评论、转发、查看和电影评分覆盖度比一般电商推荐要多一层社交关系维度。实际建模时我们不能把两类反馈扔进同一个模型里直接相加因为量纲不一样。评分通常是 1~5 的离散值点赞是 0/1转发频率可能差异巨大。比较常见的处理办法是先把每个行为做频次归一化再按行为类型赋予权重最后合并成用户对物品的兴趣分数。这个分数就替代了传统协同过滤里的“评分”也让题目里强调的“用户行为”真正变成了模型输入。2.2 行为权重打分点赞、评论、转发、评分怎么合并合并公式我用这类项目里最常用的线性加权方式score(u,i) w_like * like_count w_comment * comment_count w_retweet * retweet_count w_rate * rate_score / 5其中 like_count、comment_count、retweet_count 可以取该用户在该物品上的行为次数rate_score 是 1~5 的评分。为了防止数值溢出可以先把前三项除以该用户所有行为的最大值做归一化。下面是我在这类毕设里常用的一个预处理函数import numpy as np def compute_user_item_score(records, weightsNone): records: list of dict, 每个元素是一个用户对一个物品的行为 每个 dict 至少包含 user_id, item_id, like, comment, retweet, rating weights: 行为权重默认使用 [1, 2, 3, 4] if weights is None: weights [1.0, 2.0, 3.0, 4.0] w_like, w_comment, w_retweet, w_rate weights merged {} for r in records: key (r[user_id], r[item_id]) if key not in merged: merged[key] [0, 0, 0, 0] merged[key][0] r.get(like, 0) merged[key][1] r.get(comment, 0) merged[key][2] r.get(retweet, 0) merged[key][3] max(merged[key][3], r.get(rating, 0)) scores {} for (uid, iid), acts in merged.items(): s (w_like * acts[0] w_comment * acts[1] w_retweet * acts[2] w_rate * acts[3] / 5.0) scores[(uid, iid)] s return scores这段代码的逻辑是先把同一个用户对同一个物品的多次行为做聚合点赞和评论累加评分取最高一次再用权重向量合并成最终兴趣分数。权重前三个是行为次数第四个评分除以 5 是为了把 1~5 的评分压到 0~1 区间避免评分一项因为数值大直接主导结果。实际调参时评论和转发通常比点赞更能体现真实兴趣所以默认权重我给了 [1, 2, 3, 4]。下面是一份可参考的行为权重配置不同场景可以调行为类型权重说明点赞1成本最低最多作为弱信号评论2需要用户组织语言偏好信息更明确转发3带社交传播属性表示认同评分4显式反馈直接对应兴趣强度2.3 基于用户的协同过滤与相似度计算有了上面的用户-物品兴趣分数矩阵之后下一步就是选推荐算法。这套毕设题目里明确提到“社交网络推荐”所以最常见的做法是基于用户的协同过滤UserCF。UserCF 的核心思想是找到与当前用户行为最相似的一批用户把那些相似用户喜欢的、但当前用户没见过的物品推荐出来。用户相似度计算常用余弦相似度。假设用户 u 和 v 的兴趣分数向量分别是 A 和 B计算公式是cos(u,v) (A·B) / (||A|| * ||B||)用 Python 实现的话可以直接手写而不依赖太重的外部库def cosine_similarity(vec1, vec2): common set(vec1.keys()) set(vec2.keys()) dot sum(vec1[k] * vec2[k] for k in common) norm1 np.sqrt(sum(v ** 2 for v in vec1.values())) norm2 np.sqrt(sum(v ** 2 for v in vec2.values())) if norm1 0 or norm2 0: return 0.0 return dot / (norm1 * norm2)这个函数接受两个稀疏向量只计算两个用户都有评分的物品维度最终得到 [-1, 1] 的相似度。需要注意如果两个用户没有共同行为过的物品dot 就是 0相似度直接变成 0这在冷启动阶段很常见。后面第 5 章会讲怎么用造数据帮系统度过冷启动。拿到相似度之后推荐流程一般是对目标用户 u计算他与其他用户的相似度取 Top-K 个邻居然后找出这些邻居行为过的、u 未行为的物品按邻居相似度加权求和作为预测推荐分数。代码层面核心就是矩阵填零和排序这里不再展开。需要提醒的是UserCF 在社交网络场景下更新成本低因为用户数量远小于物品数量时计算矩阵更轻量一旦用户量起来就要考虑切换到 ItemCF 或向量化召回。3. 原型系统落地前端工程与后端API的配置3.1 文件结构里的工程配置.babelrc / .editorconfig / reset.css 在干嘛解压这份 zip 之后你会看到一份很典型的前端工程文件集合.babelrc、.editorconfig、App.css、index.css、iconfont.css、reset.css 等。不像演示用的单页 HTML说明作者是用 webpack Babel 在管理前端代码。.babelrc 是 Babel 的配置文件作用是把 ES6 语法转译成浏览器兼容的版本JSX 的转换也在这里指定。.editorconfig 则是给编辑器用的统一缩进风格和换行符防止多人协作时 diff 乱掉。reset.css 负责把浏览器默认样式清掉iconfont.css 是字体图标样式App.css 和 index.css 是业务样式和全局样式。这套分层虽然简单但对毕设来说够用。我第一次跑这个项目时直接在 api/frontend 两个目录间反复切换后来发现 README.md 里其实把启动顺序写得很清楚建议拿到任何源码包都先读它再动手。我一般会先用命令看下目录结构cd graduation-social-recommend tree -L 2 -I node_modules如果系统没有 tree也可以用 find . -maxdepth 2 -type d 查看目录。看到 api 和 frontend 两个平级目录就能判断后端接口服务和前端静态页面是分开部署的这种方式在毕设演示环境里很常见不会因为前端打包问题把后端业务拖崩。3.2 后端API与前端联调README.md 里的配置项这份项目的 README.md 里标出了必须改的配置项包括后端服务端口、数据库连接和前端请求接口地址。因为后端代码不在压缩包正文里完整展开我这里按最常见的 Flask/Express 类型接口给你梳理一套可复用的配置流程。后端的端口如果默认是 5000前端 dev server 默认是 3000那么代理设置就是重中之重。常见做法是在 frontend 的 package.json 里加一个 proxy 字段把 /api 请求转发到后端地址。配置示例{ name: social-recommend-frontend, proxy: http://localhost:5000 }然后在启动脚本里加上环境参数。下面是我在这些毕设项目里常用的启动命令# 后端启动监听 0.0.0.0:5000 cd api pip install -r requirements.txt python run.py --host 0.0.0.0 --port 5000 # 前端启动监听 0.0.0.0:3000 cd ../frontend npm install npm run dev注意这里的 pip install 和 npm install 都必须在你已经配好 Python 环境变量的前提下执行。Python 里如果同时装了多个版本建议用 venvNode 版本别太新有些旧项目在 Node 18 上跑 babel 会报 One-line 的 OpenSSL 错误把 Node 换到 16 LTS 能省不少时间。下面是一个典型环境配置表你可以对照 README.md 里的实际字段名修改配置项示例值作用API_HOST0.0.0.0后端监听地址API_PORT5000后端服务端口DB_URImysql://root:123456localhost:3306/recommend数据库连接字符串JWT_SECRET自定义随机字符串用户登录状态签名FRONTEND_PROXYhttp://localhost:5000前端开发代理地址如果登录接口返回 401先检查 JWT_SECRET 是否和前端约定的一致如果数据库连不上优先看 DB_URI 里用户名密码是否带特殊字符特殊字符需要 URL 编码。3.3 用户与物品管理的核心接口题目里要求对用户、物品信息做增加、删除、搜索、评价、排序、推荐。我拆到接口层就是下面这几组。用 curl 验证后端最直接# 新增物品 curl -X POST http://localhost:5000/api/items \ -H Content-Type: application/json \ -H Authorization: Bearer token \ -d {name: 《社交网络结构分析》, category: 论文, tags: [推荐算法]} # 删除用户 curl -X DELETE http://localhost:5000/api/users/1001 # 搜索物品 curl -G http://localhost:5000/api/items/search \ --data-urlencode q推荐算法 \ --data-urlencode page1 \ --data-urlencode size10 # 获取用户对某物品的评价 curl -X GET http://localhost:5000/api/users/1001/rating?item_id2001这些命令的思路是POST /api/items 负责新增物品物品名和分类字段不要求唯一所以同一件物品可以提交多次实际业务里应该在代码层做幂等控制DELETE /api/users/1001 是物理删除还是逻辑删除取决于代码实现毕设里通常直接删表记录搜索接口用 GET query 参数中文必须做 URL 编码curl 的 --data-urlencode 就是干这个的评价接口返回的是用户对单条物品的评分记录供推荐模块读取。我碰到过一个坑删除接口没有校验该用户是否已有行为记录结果删掉用户后推荐模块计算相似度时还拿着旧的 userId 查行为表直接报外键错误。正确做法是删用户时先删关联行为或者在行为表里做软删除标记。这一条在答辩时讲出来老师会认为你考虑过数据一致性。4. 推荐结果如何接到管理后台排序、搜索与评价4.1 推荐接口与物品列表的融合模型算完最终要在管理后台里展示。这套毕设的前端页面里有用户列表、物品列表和推荐区推荐区不是单独一页而是嵌入在物品列表的顶部。这样设计是为了让演示效果更直观你搜索“电影”后推荐区会根据当前用户的行为实时给出结果。前端拿到推荐结果最简单的方式是调用一个类似 /api/recommend/{user_id} 的接口后端返回 item 列表。下面是一段常见的 React 组件代码import { useEffect, useState } from react; function RecommendList({ userId }) { const [items, setItems] useState([]); useEffect(() { fetch(/api/recommend/${userId}) .then(res res.json()) .then(data setItems(data.items || [])) .catch(err console.error(推荐接口请求失败, err)); }, [userId]); return ( div classNamerecommend-list {items.map(item ( div key{item.id} classNamerecommend-item span{item.name}/span span推荐分{item.score.toFixed(2)}/span /div ))} /div ); } export default RecommendList;这段代码的关键在于 useEffect 依赖了 userId也就是说当用户切换时推荐列表会自动重新请求这是演示中最容易出效果的交互。fetch 默认不带登录态如果接口做了 JWT 校验你需要手动添加上 Authorization 头我一般会在封装的 request 函数里统一处理而不是在每个组件里加。4.2 搜索和排序参数怎么传物品搜索接口除了关键词还接受 sort、order、page、size 这几个参数。sort 支持 score、rating、hot 三种排序方式score 是推荐算法算出来的综合分rating 是平均评分hot 是行为总数。注意这里的 score 和推荐分不一定相同搜索列表里的 score 是全站综合热度推荐列表里的 score 是针对当前用户个性化算出来的两者不能混用。下面是建议的请求参数表参数类型可选值说明qstring任意关键词搜索名称或标签sortstringscore / rating / hot排序字段orderstringasc / desc排序方向pageint1 开始页码sizeint默认 10最大 50每页条数用 fetch 拼接参数的完整写法是const baseUrl /api/items/search; const params new URLSearchParams({ q: 电影, sort: score, order: desc, page: 1, size: 10 }); fetch(${baseUrl}?${params.toString()}) .then(res res.json()) .then(data { console.log(data.total, data.items); });URLSearchParams 会自动处理中文编码手动拼字符串容易漏掉 encodeURIComponent。后端接收到参数后排序字段建议用白名单校验否则直接拼进 SQL 会导致注入风险。比如 sort 只允许 score、rating、hot 之一order 只允许 asc、desc。4.3 评价数据回流与模型再训练评价是推荐闭环里很重要的一环。用户在管理后台给物品打分之后这条记录会写进行为表但推荐模型不会立刻更新。常规做法是新增评价接口先把数据落到数据库再通过定时任务每隔几分钟离线刷新用户-物品行为表。新增评价的 SQL 类似于INSERT INTO user_item_behavior (user_id, item_id, behavior_type, score) VALUES (1001, 2001, rating, 4); -- 定时任务刷新用户-物品兴趣分数 REFRESH MATERIALIZED VIEW user_item_score_mv;这里 behavior_type 字段区分点赞、评论、转发、评分score 字段对点赞存 1对评分存 1~5对评论和转发存行为次数。用物化视图存用户-物品兴趣分数可以有效避免每次推荐都扫描原始行为表毕设数据量不大但逻辑上是正确的。有一个细节要注意评分行为可以被同一用户多次提交如果你不想让用户刷分表结构里最好给 (user_id, item_id, behavior_type) 加唯一约束评分记录用 ON DUPLICATE KEY UPDATE 更新最新值。不然后台连续点几次“提交评价”模型里的评分直接翻倍演示结果会非常奇怪。5. 从毕设到可演示数据构造、效果验证与zip压缩包排错5.1 冷启动阶段造数据新系统没有行为数据推荐模块返回空列表这在答辩演示最容易冷场。我一般会在项目里加一个 mock 脚本import random import csv users [fu{i} for i in range(1, 50)] items [fi{i} for i in range(1, 200)] with open(mock_behavior.csv, w, newline) as f: writer csv.writer(f) writer.writerow([user_id, item_id, like, comment, retweet, rating]) for _ in range(2000): user random.choice(users) item random.choice(items) writer.writerow([user, item, random.randint(0, 1), random.randint(0, 5), random.randint(0, 3), random.choice([0, 3, 4, 5])])这段脚本生成 50 个用户对 200 个物品的 2000 条行为随机中带着分布rating 只在 0/3/4/5 中取值避免出现太多 1 分和 2 分让推荐结果看起来更真实。5.2 离线评估准确率、召回率与推荐结果验证验证推荐效果要能说清指标。对于评分类行为可以用 RMSE对 Top-N 推荐用准确率和召回率。每次只留 20% 行为做测试剩下的 80% 参与训练然后计算def evaluate(train, test, recommend_func, topn10): hit 0 total 0 for uid in test: rec set(recommend_func(uid, topn)) real set(item for _, item in test[uid]) hit len(rec real) total min(topn, len(real)) precision hit / (len(test) * topn) recall hit / max(1, total) return precision, recall这里 precision 是推荐列表里命中真实行为的比例recall 是真实行为中有多少被推荐出来了。还有一个经验值Top-10 的 precision 如果能到 0.05 以上在冷启动数据里已经算可用。5.3 zip压缩包常见问题解压报错与乱码处理再好的源码包也怕下载环节出问题。如果你解压时报 error read zip archive优先重新下载一次并检查文件大小和页面标注是否一致。压缩包在 Windows 上解压出现中文乱码是因为 zip 内部编码不是 UTF-8用 7-Zip 打开后在右键菜单里选择“以 UTF-8 编码打开”基本能解决。毕设包里嵌套的 node_modules 如果丢失不要硬找直接删掉之后在 frontend 目录里重新执行 npm install比强行修复压缩包更快。建议把 5.2 的 evaluate 函数接到后端一个 /api/debug/evaluate 接口里能在浏览器里直接看到每次调参后的指标变化答辩时效果会好很多。本文还有配套的精品资源点击获取