资讯动态

基于协同过滤的租房推荐系统:Python+Django全栈实现与踩坑记录

发布时间:2026/10/21 6:02:48 来源:尧图企业网站定制
把“毕业设计”做成一个能打的东西基于协同过滤的租房推荐系统全记录每年的毕业设计季我都能看到大量同质化的管理系统、商城网站题目。说实话这类题目不是不能做但答辩时很难讲出亮点。相比之下带推荐算法、带可视化、带数据分析的题目天然就比增删改查高一个层次也好讲故事。今天这篇就完整复盘一下我做“基于Python与Django的协同过滤租房推荐系统”的全过程从选题思路、算法选型、数据处理到后端实现、可视化展示再到测评踩坑基本把我踩过的坑和觉得值得参考的做法都写出来了。这个题目覆盖了Django框架、协同过滤推荐算法、可视化展示和大数据预处理几个模块工作量足够撑起一篇合格的毕业设计技术栈又不会冷门到没人指导。不管你是正在选题的学生还是想快速上手“推荐系统Web框架”这套组合的开发者这篇文章应该都能给你一些直接可用的思路。我会尽量把代码思路、数据结构、算法实现过程讲清楚而不是只贴一段跑不通的代码。1. 为什么选“租房推荐”当毕业设计题目先想清楚这几个问题1.1 选题的性价比分析毕业设计最怕什么最怕题目看着高大上实际做不出来也怕题目太简单答辩被追问两句就露馅。租房推荐这个方向恰好卡在了一个很舒服的位置。首先业务场景足够贴近生活。房源推荐、用户找房、智能匹配这些概念评委一听就懂不需要额外解释行业背景。其次数据获取的难度适中。房源数据不像金融、医疗数据那样敏感自己构造一套足够真实的数据集并不难也可以从公开数据集中找思路。再次推荐算法在本科阶段属于“跳一跳够得着”的难度协同过滤的数学基础就是相似度计算不需要深度学习那样的复杂网络结构但又能讲出完整的推荐链路。从工作量角度看这个题目天然包含四个模块数据部分采集或构造、清洗、预处理、算法部分协同过滤的两种经典思路、后端部分Django提供接口和页面渲染、可视化部分房源分布、推荐结果解释、用户行为分析随便展开哪一个都能写出两三章的内容。1.2 技术栈搭配的合理性技术栈选的是 Python 3.9 Django 3.2 SQLite/MySQL ECharts 可视化。Python 是算法实现的默认语言Django 负责把算法包装成可用的 Web 服务ECharts 负责把分析结果变成图表。有人会问为什么不直接用 FlaskFlask 确实更轻量但毕业设计里 Django 有个很实际的优势自带 Admin 后台、ORM、表单、认证体系。答辩现场演示时Django 后台可以直接管理房源数据和用户数据视觉效果更完整也减少了手动写管理页面的工作量。另外Django 的 ORM 在操作数据时比裸写 SQL 更安全不容易出现注入问题。数据库我建议用 MySQL 或 PostgreSQL本地开发用 SQLite 也够。不过考虑到答辩现场的演示环境可能是临时搭建的SQLite 文件数据库反而是最稳的选择拷过去就能跑。我自己最终用了 MySQL但代码里通过 Django 的 settings 配置切换数据源非常方便这部分后面会讲到。1.3 这个项目要解决的核心问题把题目拆开看真正要回答的问题就三个如何根据用户的历史行为收藏、浏览、租住从大量房源中找出他可能感兴趣的房源如何让推荐结果“说得清楚”即为什么推荐这套房这关系到可视化如何展示。如何评估推荐效果证明这个系统不是随便猜的这三个问题分别对应推荐算法的输入、输出和评测也是整篇论文的逻辑主线。我强烈建议所有做推荐系统选题的同学动工前先把这三个问题写进开题报告里后面所有工作都是在为这三个问题找答案。2. 协同过滤到底怎么在房源场景落地从原理到算法选型2.1 两种协同过滤的直观理解协同过滤的核心假设很简单和你行为相似的人喜欢的房子大概率你也喜欢或者你喜欢的那套房和另一套房在历史行为上经常被一起关注那你也很可能喜欢那另一套房。前者叫基于用户的协同过滤User-based CF后者叫基于物品的协同过滤Item-based CF。用租房场景举例子可能更容易理解。用户A收藏了小区X的两套房收藏了小区Y的一套房用户B收藏了小区X的一套房。系统通过用户A和用户B在“小区X”上的共同行为判断他们偏好相似于是把小区Y的房源推荐给用户B。这是UserCF的逻辑。另一条线一套房C被收藏的用户同时收藏了房源D次数多了就认为C和D是“相似物品”。用户A收藏了C系统就把D也推荐给他。这是ItemCF的逻辑。2.2 场景适配UserCF和ItemCF怎么选理论上两种都能做但落地时要考虑数据规模和实时性。UserCF 适合用户少、物品多的场景推荐结果偏重“社会热度”喜欢发掘新东西。但租房场景里用户量级通常远小于房源量级而且用户行为非常稀疏多数用户一辈子也就租过几次房收藏几十套房已经算活跃导致用户相似度矩阵极其稀疏。ItemCF 适合物品数量相对少、用户行为相对稳定的场景推荐结果偏重“相似偏好”解释性也更强。“因为您收藏了A小区的一居室所以推荐同小区的另一套一居室”——这种推荐理由用户一眼就能看懂。房源本身是相对长尾的物品但一个城市里可租房源的总量有限同一地段、同一户型的房源有天然的相似性所以 ItemCF 在租房场景里表现得比 UserCF 更稳定。我的系统最终以 ItemCF 为主同时保留了 UserCF 的对比实验用于论文里的效果对比。2.3 相似度计算的具体选择相似度计算是整个协同过滤的心脏。常用的有杰卡德相似系数、余弦相似度和皮尔逊相关系数。杰卡德相似系数适合只关注“是否共同出现”的场景比如判断两套房是否经常被同一批用户收藏。余弦相似度把用户对房源的评分看成向量计算向量夹角适合评分数据。皮尔逊相关系数则在余弦相似度的基础上做了均值中心化能缓解用户评分尺度不同的问题。房源交互数据大多数情况下是隐式反馈即“收藏了就是1没收藏就是0”没有真实的评分语义。这种情况下我会优先用杰卡德相似系数或者改进后的余弦相似度在向量里做0/1统计。如果数据集里模拟了评分比如用户对房源打分1到5再用皮尔逊。这个选择逻辑建议写进论文能体现你理解这些公式背后的适用条件。2.4 推荐得分怎么算ItemCF 的核心流程分两步离线计算物品之间的相似度矩阵得到“相似物品表”。在线推荐时根据用户历史交互过的物品累加相似物品表中对应物品的相似度得到每个候选房源的得分取 Top-N 输出。得分公式大致是score(user, item) sum(similarity(item, item_h) * preference(user, item_h))其中preference(user, item_h)表示用户对这个历史房源的偏好权重收藏是1点击是0.5租住是2。给不同行为配不同权重是提升推荐效果最直接的小技巧。很多入门项目只用0/1我实测加了权重之后推荐列表的相关性明显提升。3. 房源数据从哪里来数据集构造、清洗与特征工程3.1 数据字段设计租房数据字段不需要太复杂但要覆盖推荐的输入输出和可视化分析。我设计的核心字段如下房源表房源ID、标题、小区名称、租金、户型几室几厅、面积、朝向、楼层、区域、地铁站距离、描述文本、标签精装/近地铁/南向、发布时间、图片URL。用户表用户ID、用户名、注册时间、偏好标签、常驻区域。行为表用户ID、房源ID、行为类型浏览/收藏/租住、行为时间。行为表是推荐算法的核心输入房源表的字段决定特征多样性和可视化的丰富度。建议把“小区名称”和“区域”分开存别合成一个字段否则后面做区域热度统计的时候会非常痛苦。3.2 数据构造不用纠结没数据重点是逻辑合理没有真实房源数据是大多数学生做这个题目的第一道坎。我试过找公开数据集但很多房产平台的爬取行为有法律风险不建议碰。最终我用的是自动生成加人工规则约束的方式生成了约3000套房源、500个用户、数万条行为数据。构造数据不是随机乱造。要让推荐算法跑起来有意义数据必须内嵌“可被学习的规律”。比如随机生成3000套房源用户行为纯随机那推荐结果必然是一团糟答辩时一跑结果全乱场面会很难看。我的做法是预先定义一些用户偏好模板比如“预算5000以内、喜欢南向、靠近地铁”然后让行为生成器按模板分配用户对这类型房源的收藏概率其他房源只有少量随机行为。这样既模拟了真实场景又保证了数据里有明显的偏好结构算法能学出来测评指标也好看。这个“内嵌规律”的思路请大家务必重视它直接决定你的推荐效果。3.3 数据预处理的几个关键步骤原始行为数据不能直接喂给算法至少要经过三步处理去重同一用户对同一房源多次浏览只保留最大权重的那条行为。过滤交互次数过少的用户和房源单独拎出来处理。比如交互少于3次的用户相似度计算里基本贡献不了有效信息放到冷启动测试集里单独分析。时间切分把行为按时间切分为训练集和测试集保证测试集的用户行为晚于训练集模拟“用过去预测未来”而不是随机打乱。这一点在答辩时很容易被问到。清洗完的数据我会另存成 CSV下一步直接用 Python 读取做矩阵运算这样把数据处理和 Django 解耦调试起来更快。4. Django 后端怎么组织模型设计、推荐服务与接口层4.1 项目结构规划用 Django 写推荐系统最忌讳把所有逻辑塞进 views.py。我的项目结构是这样划分的house_project/ ├── manage.py ├── config/ # settings, urls ├── apps/ │ ├── houses/ # 房源模块模型、视图、序列化 │ ├── users/ # 用户模块 │ ├── behaviors/ # 行为模块收藏、浏览记录 │ └── rec/ # 推荐模块算法核心、推荐接口 └── data/ # 预处理脚本、生成好的 CSV推荐算法单独放在 rec 模块不跟业务模块混在一起。这样做的原因是推荐逻辑是相对独立的纯计算过程单元测试、替换算法都很方便。我做了一个简单的推荐接口抽象ItemCF、UserCF 都实现同一个接口后面扩展基于内容的推荐时也顺手。4.2 ORM 模型设计要点Django 的 ORM 模型对应上面说的三张核心表这里给出简化版代码思路# apps/houses/models.py from django.db import models class House(models.Model): title models.CharField(max_length255) community models.CharField(max_length128, db_indexTrue) district models.CharField(max_length32, db_indexTrue) price models.IntegerField() rooms models.CharField(max_length16) # 例如 3室2厅 area models.FloatField() orientation models.CharField(max_length8) # 南向/北向等 metro_distance models.IntegerField() # 距最近地铁站米数 tags models.CharField(max_length255, blankTrue) created_at models.DateTimeField(auto_now_addTrue)设计上注意几点需要在 where 条件里做筛选的字段如小区、区域、租金区间一定要加db_indexTrue既能提升查询效率也方便后面做可视化交互筛选。价格用整数存月租金不要用 FloatField避免浮点精度问题。行为表建议重点设计它是协同过滤的输入源。# apps/behaviors/models.py class Behavior(models.Model): USER_ID user_id HOUSE_ID house_id BEHAVIOR_TYPES [ (view, 浏览), (collect, 收藏), (rent, 租住), ] user models.ForeignKey(User, on_deletemodels.CASCADE) house models.ForeignKey(House, on_deletemodels.CASCADE) behavior_type models.CharField(max_length16, choicesBEHAVIOR_TYPES) weight models.FloatField(default1.0) # 浏览0.5 收藏1.0 租住2.0 created_at models.DateTimeField(auto_now_addTrue)为什么额外加一个 weight 字段而不是直接用 behavior_type 判断权重因为如果后续想调整权重只改数据不改代码而且可以把“偏好衰减”做进去——越近的行为权重越高。这个设计在答辩时也能讲出深度。4.3 推荐接口的实现逻辑推荐接口的核心思路是加载离线计算好的物品相似度矩阵查询用户最近行为计算候选房源得分返回 Top-N。这里给出简化版本的推荐服务代码# apps/rec/services.py import pandas as pd import numpy as np from collections import defaultdict class ItemCFRecommender: def __init__(self, sim_matrix_path, top_k10): self.sim_matrix pd.read_csv(sim_matrix_path, index_col0) self.top_k top_k def recommend_for_user(self, user_behavior_house_ids, preference_dict): user_behavior_house_ids: 用户交互过的房源id列表 preference_dict: {house_id: weight} score defaultdict(float) for house_id in user_behavior_house_ids: if house_id not in self.sim_matrix.index: continue sim_series self.sim_matrix[house_id].drop(labels[house_id]) for cand_id, sim_val in sim_series.items(): if cand_id in user_behavior_house_ids: continue score[cand_id] sim_val * preference_dict.get(house_id, 1.0) ranked sorted(score.items(), keylambda x: x[1], reverseTrue) return [house_id for house_id, _ in ranked[:self.top_k]]注意这里做了一个过滤已经交互过的房源不要重复推荐这在业务上非常有必要否则用户收藏过的房子还会再被推回来。在 Django view 层调用推荐服务时不要直接操作相似度矩阵而是通过 query 参数传入用户IDservice 内部查行为表。这样接口语义清晰也方便下游可视化页面调用。4.4 接口返回结构与前端约定推荐接口我建议返回结构化 JSON而不是渲染好 HTML。前端用 Aajx 请求 JSON再根据数据用 ECharts 渲染图表这样前后端职责清楚后期想改成小程序或者 App 也能复用。{ user_id: 1001, recommendations: [ { house_id: 5032, title: 某某小区南向一居室, price: 4500, score: 3.72, reason: 与您收藏的房源相似同小区/同户型, tags: [近地铁, 精装] } ], algorithm: item_cf, cost_ms: 12 }reason 字段是我特意加的它把“为什么推荐”变成了可展示的内容这直接为可视化部分提供了解释性素材。cost_ms 则是顺手统计的响应耗时答辩时可以拿出来讲性能。5. 可视化展示让推荐结果“看得见、说得清”5.1 可视化的四个维度这一题的关键词里带了“可视化”那就不能只是画个饼图凑数。我设计了四个可视化模块每一个都对应论文中的一个分析问题房源分布地图按区域展示房源数量、平均租金用地图或散点图呈现回答“房源长什么样”。用户行为概览展示行为类型分布、每日新增行为量回答“数据够不够支撑推荐”。推荐结果对比展示不同算法的推荐命中率、Top-N准确率以柱状图和折线图呈现回答“哪个算法更有效”。单个推荐解释针对指定用户展示交互过的房源和推荐房源之间的相似关系图回答“推荐的理由是什么”。这四个维度做下来可视化部分的内容量已经非常扎实完全不用硬凑字数。5.2 前端选型与交互设计图表库用 ECharts理由很简单生态好、中文资料多、图表类型丰富尤其适合地图和关系图。后端把聚合好的数据通过 Django 接口输出前端只负责渲染。推荐解释这个模块我用 ECharts 的关系图graph展示中心节点是用户左边节点是用户收藏过的房源右边节点是推荐出来的房源连线表示相似度或者交互关系。这个图答辩演示时效果非常好评委一眼就能理解协同过滤的推荐链路。ECharts 的前端代码模板大概是这样的// 假设 api 返回图表数据 fetch(/api/v1/recommend/explain?user_id1001) .then(res res.json()) .then(data { const chart echarts.init(document.getElementById(rec-graph)); chart.setOption({ series: [{ type: graph, layout: force, data: data.nodes, links: data.links, }] }); });需要提醒的是force 布局在节点数超过100时会卡展示时最好手动限制节点数量只显示用户最近交互的5套房和推荐结果5套房。5.3 Django 模板和静态资源部署可视化页面可以用 Django 模板渲染也可以做成单页 HTML 静态接口。我用的方案是 django-echarts 结合方式首页用 Django 模板展示房源列表和推荐结果表格数据统计页用独立的 HTML 页面加载 ECharts接口直接访问 Django 的 JSON API。开发时记得在 settings.py 里配置静态文件的访问路径不然图表库加载不出来这一步常见但容易被忽略。6. 实测踩坑记录相似度计算、冷启动、评测指标那些坎6.1 相似度矩阵的内存和计算问题房源数量到3000这个量级时物品相似度矩阵是 3000 x 3000看起来不大但如果你老老实实用两层循环去计算速度慢得让人怀疑人生。一个实用技巧是利用 Pandas 的向量化运算把“共现矩阵”一次性算出来不要在 Python 循环里做两两配对。大体思路是先把用户行为转成 scipy 的稀疏矩阵行为矩阵形状是用户数, 房源数然后物品相似度矩阵 行为矩阵转置乘行为矩阵再除以范数归一化。这一步直接让计算时间从分钟级降到秒级。from scipy.sparse import csr_matrix # user_item: 稀疏矩阵行是用户列是房源值是行为权重 # 物品共现矩阵 item_cooccur user_item.T user_item item_cooccur item_cooccur.toarray()这个矩阵的对角线是每个房源被交互的总次数非对角线的位置 (i, j) 是房源 i 和房源 j 被同一用户交互的共现次数。像这样的实现细节建议写进论文“算法实现”中比贴教科书公式更能体现工作量。6.2 冷启动怎么处理新的用户没有行为数据协同过滤直接失效。我的处理方案有两层第一层对没有行为的新用户返回“热门房源”策略即按收藏总量、浏览总量排序加上区域热度修正。第二层在页面上强制引导用户先选择偏好标签预算范围、户型、是否近地铁系统用这些标签匹配房源特征相当于一个简单的基于内容的推荐产生初始行为后再切回协同过滤。答辩被问“冷启动如何处理”时这两个方案基本能覆盖问题的标准答案。6.3 推荐评测指标的坑测评最容易踩的坑就是用了随机划分的数据集导致“测试集的用户已经出现在训练集里”这属于数据泄露。推荐系统测评推荐用时间划分前80%时间窗口作训练后20%作测试。我用的指标是召回率、精确率和覆盖率。召回率 Top-N 的公式是测试集中该用户真实交互的房源里有多少比例出现在推荐列表里。精确率反过来算推荐列表里有多大比例被用户真实交互。覆盖率算的是推荐系统推荐过的房源占总房源的比例衡量系统是只推头部热门还是覆盖长尾。实操中我发现一个现象ItemCF 的精确率不一定比热门推荐高多少但覆盖率会好很多。这个观察很值得写进论文的“实验结果与分析”部分因为它说明自定义的推荐算法不是花架子确实在探索多样性上有效果。6.4 Django 推荐算法部署时容易翻车的细节每次启动时重新计算相似度矩阵启动会慢而且没有必要。建议把相似度矩阵存成 CSV启动时加载即可只有数据更新时才重新计算。Django 的 ORM 查询在行为表数据量大的时候默认懒加载会把性能拖垮。使用select_related或prefetch_related提前加载关联对象。接口层必须做超时保护。协同过滤服务如果遇到极端稀疏或者相似度矩阵缺失直接返回热门推荐兜底不要抛异常。数据库里的行为数据修改后离线相似度矩阵需要同步更新。简单做法是每次更新数据后执行一个管理命令python manage.py rec_update把计算结果刷新到 CSVWeb 进程重启时自动加载新文件。7. 写在最后的一点个人经验做过这个项目之后我的一个强烈感受是毕业设计选题真的不要贪大也不要嫌小关键是能不能形成“数据-算法-系统-评估”的完整闭环。租房推荐系统能闭环所以它适合作为毕业设计同样是推荐系统如果只写一个推荐算法脚本而没有任何 Web 界面和可视化工作量又明显偏少。两者结合刚刚好。最后分享一个实用小技巧给相似度矩阵和推荐结果做一份可导出的静态报告用图片或 PDF 保存下来放在论文附录里。答辩时如果系统现场演示出现环境问题这份报告能直接兜底帮你把评分保住。真实答辩环节出状况的概率比你想象的高这份无接触的备份材料值得提前准备。如果你也在做推荐相关系统的毕业设计希望这篇整理能帮你少走一点弯路也祝你的代码和论文都能顺利过关。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑