news 2026/10/21 23:16:16

基于协同过滤的租房推荐系统设计与实现——Python+Django实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于协同过滤的租房推荐系统设计与实现——Python+Django实战解析

每年到了毕业设计选题季节,最常被问到的就是“做什么题目既好过又能学到东西”。如果你正琢磨着把Python、推荐算法、Web框架凑到一个项目里,那“基于协同过滤的租房推荐系统”这个方向确实值得认真考虑一下。它既有算法含量的体现,又有Web工程的可视化呈现,数据层面还能撑起“大数据分析”的描述,一套组合拳打下来,无论用于课程设计还是毕业设计,从开题到答辩都拿得出手。

这篇文章我就从零开始拆解这个系统的完整实现思路。说句实在话,这类项目网上同名源码不少,但真正把协同过滤算法讲清楚、把Django工程细节写到位的并不多。为了让你少踩几个坑,我会把需求拆分、算法核心、模型设计、可视化接入以及常见的报错和排查经验一并整理出来,你可以把它当成一份可以直接动手跟做的实操笔记。

1. 项目定位与整体设计思路

1.1 为什么选“租房推荐”作为毕设方向

租房的本质是“在特定价格区间和地理范围内找一套合适的房子”,这个场景非常适合套用推荐系统。大多数同学选电商推荐或电影推荐,这些题目太常见,答辩老师看一眼目录就知道是抄的框架。租房推荐有几个天然优势:

  • 房源数据好解释,字段直观,包括价格、户型、区域、面积、朝向、楼层、标签。
  • 用户行为数据丰富,一个租客在平台上的搜索、浏览、收藏、预约看房、最终下单,每个动作都能映射成评分数据。
  • 推荐结果容易验证,系统推荐出来的楼盘如果落在用户关注的价格段和区域附近,合理性一眼就能看出来。

另外一个重要原因是,租房市场天然带有强地域属性与价格敏感特征,这为协同过滤算法提供了天然的稀疏但高密度局部数据结构。你可以在答辩时说“房源数据具有长尾分布和地域聚集特征”,这句话本身就是一个加分项。

1.2 功能模块与技术选型拆解

一个完整的租房推荐系统,核心模块可以划分为四层:

  • 数据层:用户表、房源表、行为记录表(评分/收藏/浏览)、相似度结果缓存表。
  • 算法层:构建用户-房源评分矩阵,通过协同过滤算法计算相似度,生成TopN推荐列表。
  • 应用层:Django Web框架,包含用户注册登录、房源展示、搜索筛选、详情页、收藏、在线评分、推荐结果展示。
  • 可视化层:后台统计面板,通过图表展示房源分布、价格区间、推荐热门、用户活跃度等数据指标。

技术选型上,Python语言、Django框架、MySQL或SQLite数据库、Pandas做数据处理、Scikit-learn或手写协同过滤算法,再加上ECharts做前端图表展示,这套组合在易用性和答辩可讲性之间达到了很好的平衡,妥妥是一个五脏俱全的小型数据应用项目。

之所以不用FastAPI或Flask,是因为Django自带Admin后台、ORM和用户认证体系,这些功能在毕业设计中几乎是刚性的需求。与其自己搭轮子实现登录和后台管理,不如直接依赖框架自带能力,把精力集中在算法层和业务层上。

1.3 推荐链路与数据流转

整个系统推荐链路的业务流程是这样走的:

  1. 用户注册并登录系统,完善自己的偏好信息,比如预算区间、意向区域、期望户型。
  2. 用户的每一次浏览、收藏、评分行为都会落到行为记录表。
  3. 算法模块定时或在用户请求推荐时,构建评分矩阵,计算用户与用户之间的相似度。
  4. 根据相似用户的评分历史,预测当前用户对未看过的房源的评分。
  5. 过滤掉用户已经评分或已经排除的房源,生成TopN推荐结果。
  6. 可视化模块读取统计聚合数据,生成图表展示在后台面板。

这条链路保证了系统的完整性,从数据采集、算法推导到结果展示全部打通,而且每一个环节都有对应的代码文件和表结构支撑,答辩时讲解起来很清晰。

2. 协同过滤算法核心实现

2.1 用户评分矩阵的构建

协同过滤的基础是评分矩阵,行是用户,列是房源,值代表用户对房源的评分。如果用户没有对某套房源产生过行为,对应位置默认为0或空值。实际开发中,用户不可能对大量房源评分,直接让用户打分体验很差,所以一般用行为映射评分。

我的做法是定义这样一套映射规则:

  • 浏览房源一次:得1分,浏览重复只计一次。
  • 收藏房源:得3分。
  • 预约看房:得5分。
  • 完成租房(模拟动作):得10分,也可以归一化为5分制。

这样做的好处是把原始的稀疏行为日志转化成了有语义的评分数据。如果你觉得这套规则说服力不够,还可以加一个时间衰减因子,用户昨天的行为比一个月前行为权重高,更贴近实际场景。

构建评分矩阵时,需要注意数据量的问题。假设系统里有10个用户和200套房源,评分矩阵就是10×200,数据量很小。如果你自己伪造了1000个用户和500套房子,矩阵规模也就50万级别,内存完全可以承受。需要注意的是,真实生产环境下推荐系统面临的是千万级甚至亿级矩阵,但毕业设计不需要处理那类规模,你可以在答辩时提一句“本系统针对小规模数据做了优化,大规模数据场景可采用矩阵分解或引入Spark、Flink等分布式计算框架”,点到即止,反而显得你有架构视野。

2.2 余弦相似度与UserCF计算流程

协同过滤分为基于用户和基于物品两大类,这里我先把基于用户的UserCF讲透。

UserCF的思路归纳起来是“人以群分”。两个用户如果对同一批房子的评分很接近,那么他们就是相似用户,我们可以把A用户喜欢的房源推荐给B用户。

相似度计算最常用的是余弦相似度,公式是:用户u和用户v在评分向量上的余弦夹角值。实现起来并不复杂:

import numpy as np def cosine_similarity(user_vector, other_vector): # 只取双方都有评分的维度 mask = (user_vector > 0) & (other_vector > 0) if not mask.any(): return 0.0 u = user_vector[mask] v = other_vector[mask] dot = np.dot(u, v) norm_u = np.linalg.norm(u) norm_v = np.linalg.norm(v) if norm_u == 0 or norm_v == 0: return 0.0 return dot / (norm_u * norm_v)

拿到用户相似度之后,预测用户u对房源p的评分,做法是找到与u最相似的K个用户,这些用户对p有过评分,然后计算加权平均分。

def predict_score(user_id, house_id, sim_matrix, score_matrix, top_k=5): sim_scores = sim_matrix[user_id] similar_users = np.argsort(sim_scores)[-top_k:] total_sim = 0 weighted_sum = 0 for v in similar_users: if score_matrix[v, house_id] > 0 and sim_scores[v] > 0: weighted_sum += sim_scores[v] * score_matrix[v, house_id] total_sim += sim_scores[v] if total_sim == 0: return 0 return weighted_sum / total_sim

经过这步计算,每一个用户对所有未看过的房源都会得到一个预测评分。选出最高分的N套房子,再进行过滤,比如去掉用户明确排除的户型、超过预算价格的房子,剩下的就是推荐列表。

2.3 ItemCF与UserCF的取舍

既然有了UserCF,那什么时候用ItemCF?这里我说一下两者的实际差异。

  • UserCF比较适合用户量偏少、房源较多的小型系统,它的推荐结果偏“个性化”,能看到相似用户的新偏好。
  • ItemCF更适合用户量大、物品相对稳定的场景,它计算的是“物品与物品之间的相似度”,推荐时可以结合用户已有行为快速给出“看了A房的人也看了B房”这类结果。

在租房场景里,用户是频繁变化的群体,而房源数据相对稳定,从理论上看ItemCF确实有优势。但我在实际开发中综合考量后,还是选用了UserCF,原因是毕业设计的数据规模下UserCF实现更直观,算法流程也更容易在答辩时用图表讲清楚。如果你想让项目更丰富,可以同时实现两种算法,在接口里设置一个算法切换开关,对比推荐效果,这属于加分项,时间充裕的同学建议做一下。

2.4 冷启动问题的实际解法

协同过滤有个天然缺陷,就是冷启动问题。新用户没有任何行为记录,评分矩阵该用户行全是0,相似用户根本找不到,推荐结果自然为空。房源同理,新上架的房源因为没有用户评分,永远不会被推荐出去。

我在项目中用了几条比较实用的对策:

  • 针对新用户:注册阶段强制选择偏好标签,包括预算范围、意向区域、期望户型,推荐阶段先用这些标签做规则匹配,生成“猜你喜欢”的初始列表。
  • 针对新房源:设置一个“新盘专区”,或者给刚上架30天的房源加固定热度加成。
  • 兜底策略:如果协同过滤计算出的推荐列表为空,自动返回全站热门房源Top10,按浏览量加收藏量排序。

这些策略不复杂,但能保证任何用户打开推荐页面都有内容可看,测评时不会出现空白页面,这在验收时的体验分提升上是决定性的。

3. Django工程落地与关键编码细节

3.1 数据模型设计与表结构

Django的ORM让数据建模变得非常直观。我的models.py中自定义了用户表、房源表、用户行为表,外加一个用于存储相似度矩阵的缓存表。

from django.db import models from django.contrib.auth.models import User class House(models.Model): title = models.CharField(max_length=128) price = models.IntegerField() # 月租金,单位元 area = models.FloatField() # 面积,单位平方米 region = models.CharField(max_length=32) # 所属区域 layout = models.CharField(max_length=32) # 户型,如 2室1厅 orientation = models.CharField(max_length=16) # 朝向 tags = models.CharField(max_length=200, blank=True) # 标签,逗号分隔 image = models.ImageField(upload_to='houses/', blank=True) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) class UserBehavior(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) house = models.ForeignKey(House, on_delete=models.CASCADE) action_type = models.CharField(max_length=16) # view/favorite/appoint/rent score = models.FloatField(default=0) created_at = models.DateTimeField(auto_now_add=True)

把用户行为做成一张独立的表,既是日志又参与评分计算,设计上比较干净。第一次初始化系统时,你可以写一个数据迁移脚本,把房源Excel表批量导入数据库,用户行为数据可以用脚本模拟添加几千条,保证算法有数据可跑。

3.2 推荐逻辑与用户行为采集落地

推荐模块我单独放在一个名为recommend的App中,向外暴露一个get_recommendations(user_id)的接口函数。内部流程是:

  1. 从UserBehavior表取全量行为数据,构造评分矩阵。
  2. 计算用户相似度矩阵(如果缓存表存在且版本未变,直接读取缓存,避免重复计算)。
  3. 对当前用户执行预测评分。
  4. 排除用户已经互动过的房源,按预测评分排序,取TopN。

用户点击房源详情时,要在views.py里记录浏览行为,这一步骤很关键但经常被忽略。我的做法是在详情页视图函数里,针对登录用户写入一条action_type为view的记录,并在同一视图里取一次推荐结果,追加到模板上下文。这样用户看完详情页直接在页面下方看到“为您推荐的其他房源”,链路完整且用户体验顺滑。

注意:用户行为写入时,同一个用户对同一套房源多次浏览,应该做去重,否则评分矩阵会被刷爆,推荐结果也会偏向浏览频次高的房源,失去真实参考价值。

3.3 管理后台与数据初始化

Django自带的Admin后台是个隐藏的效率神器。我自定义了Admin配置,把房源表、用户行为表、算法参数表都注册进去,表头列表页可以直接进行搜索和筛选,还可以用导入导出插件导入初始房源数据。

在Admin里调整算法参数非常方便,比如你想要修改TopN的N值,或者修改最小相似用户数阈值,只需要在系统设置页面改配置项,不需要改代码重启服务。这个功能实现起来也不难:

class SystemConfig(models.Model): key = models.CharField(max_length=64, unique=True) value = models.CharField(max_length=256)

管理员在后台修改参数后,推荐模块读取配置再执行计算,整个算法流程就变成了可以动态调节的配置化引擎。答辩现场演示时,你可以现场把N值从5改成8,然后刷新推荐页面观察结果变化,这种互动效果非常有说服力。

3.4 数据处理与Pandas的高效操作

在构建评分矩阵时,纯Python写循环虽然能跑通,但代码冗长又容易出错。我的建议是引入Pandas辅助处理。

从UserBehavior表取出全部数据后,转成DataFrame,做pivot操作就能直接得到用户-房源评分矩阵:

import pandas as pd from .models import UserBehavior def build_score_matrix(): queryset = UserBehavior.objects.values('user_id', 'house_id', 'score') df = pd.DataFrame(list(queryset)) # 如果有重复记录,取最大值 df = df.groupby(['user_id', 'house_id']).agg({'score': 'max'}).reset_index() matrix = df.pivot(index='user_id', columns='house_id', values='score').fillna(0) return matrix

运行效率上,这种方法处理几百个用户和几千套房源游刃有余,代码量也少,读起来逻辑非常清楚。答辩时如果老师问到“数据预处理怎么做的”,这个答案比手写双层循环更能说明问题。

4. 可视化面板与数据指标呈现

4.1 可视化要展示哪些核心指标

可视化部分是项目门面,也是很多人忽略的地方。我的观点是推荐系统核心不能只看算法准确率,还要通过可视化手段把数据特征和推荐效果呈现给用户和管理员。

前端首页交给用户看的主要是推荐列表,而后台数据看板我建议包含以下四类图表:

  • 房源区域分布图:柱状图展示各区房源数量与平均租金。
  • 户型比例图:饼图展示一居、两居、三居占比。
  • 租金区间统计:直方图展示500-1500、1500-2500、2500-4000等区间房源数。
  • 热度排行榜:展示收藏量最高和推荐命中率最高的Top10房源。

4.2 ECharts接入与数据聚合实现

ECharts是目前最稳妥的前端图表库选择,不需要额外引包路径,简单配置就能生成漂亮图表。在Django中接入方式也很顺手:

  1. 在页面模板中引入ECharts的CDN资源。
  2. 后端写一个返回JSON数据的视图接口,数据用Pandas聚合后转成列表。
  3. 前端用Ajax请求接口数据,动态渲染图表。

[
views.py中核心聚合逻辑]

def chart_data(request): data = House.objects.filter(is_active=True).values('region', 'price', 'layout') df = pd.DataFrame(list(data)) region_count = df.groupby('region').size().to_dict() price_bins = pd.cut(df['price'], bins=[0, 1500, 2500, 4000, 8000]) price_stat = price_bins.value_counts().to_dict() payload = { 'region': [{'name': k, 'value': v} for k, v in region_count.items()], 'price': [{'range': str(k), 'count': v} for k, v in price_stat.items()], } return JsonResponse(payload)

一个接口返回多组聚合数据,前端只请求一次就能完成所有图表渲染,比逐个接口请求更高效。

4.3 热词标签与词云点缀

除了常规统计图表,一个小的亮点是加入标签词云。房源表中有一个tags字段,记录“近地铁”“朝南”“精装”“独立卫浴”“可短租”“业主直租”等标签。后端对全部房源标签做分词统计,计算每个词频并输出给前端,生成词云图。

词云图放在首页底部或者数据分析页面,视觉冲击力很强,而且让“大数据”的感觉直观地呈现出来。配合房源标题里的热门关键词,还可以延伸出一个“当前城市找房热词”的模块。整个可视化部分做出来之后,系统的完整度和完成度会提升一个档次,答辩时的印象分自然就上去了。

5. 常见问题与排查经验实录

5.1 评分矩阵稀疏导致相似度全为零

这是最常遇到的问题。模拟数据时,如果用户量有50个,房源有300套,每个用户的行为记录只有三到五条,那么用户之间共同评过分的房源几乎没有,余弦相似度为0,推荐结果自然为空。

排查思路很简单:先打印评分矩阵的非零值分布,统计一下稀疏度。上线前尽量保证每个用户至少有5到10条行为记录。如果真实数据不足,可以写一个仿真脚本,模拟用户按偏好集中浏览某些区域的房源,人为构造一些相似群体。

5.2 推荐结果跑偏的调试技巧

如果推荐出来的房型和用户关注的区域完全不相关,先说结论:大概率是评分映射规则有问题。比如浏览行为的分数权重太低,收藏和预约的分数权重太高,导致少数几次收藏行为完全主导了推荐结果,将用户偏好带偏了。

换个角度说,用户收藏可能是顺手收藏,并不代表真正想租。调试时我习惯把各类行为的分数权重做成可调参数,在后台设置页面就能改,然后不断测试对比推荐列表的变化,调到合理范围为止。常见的一组能用的初始值是浏览1分、收藏4分、预约8分、成交10分。

5.3 推荐响应速度的优化

用户点击推荐页面时,如果实时计算全量相似度矩阵,响应时间可能会达到2到3秒甚至更久,体验不太好。

我给出的优化方案是双轨制:落地页第一次访问用户时,推荐结果用缓存表保存,之后定时刷新。比如每日凌晨2点更新一次推荐结果缓存。对于活跃用户的实时请求,只计算该用户与全量用户的相似度,其余用户间相似度矩阵从内存中读取。这种方法实测下来能把推荐接口的响应压缩到300毫秒以内,完全满足毕设演示要求。

关于缓存一个关键点:当用户产生新的收藏行为后,缓存可能已过期但还没到更新时机,推荐列表不会立刻反映最新偏好。我加了一个中间方案,在用户行为被写入的同时,如果该行为是分数较高的收藏或者看房,则自动清除该用户对应的推荐缓存,并在当前请求结束后异步更新该用户的推荐结果。

5.4 答辩演示时容易忽略的细节

讲几个演示时特别容易翻车的点,提前准备好能省掉很多尴尬。

第一,演示数据库里要有足够的模拟用户数据,至少不要只有你自己测试的两个账号,否则推荐结果很单调,展示不出算法效果。我建议预置30个模拟用户、200套房源、2000条行为记录,数据规模刚刚好。

第二,项目启动前先跑一次推荐结果生成脚本,检查一下有没有房源图片路径失效,或者模板中字段引用错误。很多时候演示现场出错不是算法问题,而是模板变量名写错这种低级问题。

第三,如果评委让你现场演示推荐系统效果,提前准备一个专门用来演示的账号,这个账号的行为记录已经造好,登录后推荐列表直接刷新可见,不需要现场临时找房源“养数据”。

第四,图片文件不要用超大原图,建议统一转换成WEBP格式或者压缩为800像素宽,既加快加载速度又能让界面整齐美观。室内实拍图配上统一的尺寸在演示时视觉效果最稳定。

最后再说一个防坑提示:整个项目在做数据迁移时,注意处理一下中文字段和数据库编码的问题。Django默认设置的编码正常,但如果你从Excel导入房源数据时读取的中文出现乱码,多半是文件编码和数据库连接配置不一致,统一设置UTF-8后重新导入即可。

整体来说,这个项目无论从技术完整度还是演示效果上看,都是毕业设计里性价比很高的方向。只要算法核心是自己写的,不是为了跑通而照搬,答辩时把UserCF的每一步推导讲明白,老师很难问倒你。在实际操作中我最深的体会是,真正把推荐结果调到合理、能看出个性化差异的阶段才算完成了一个闭环,单纯把代码跑通只是起点。如果你手头也正在搭这套系统,建议把重点放在评分规则的合理性和推荐结果的直观解释性上,这两点做到了,项目就立住了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 23:16:07

从模糊代号到运行系统:自研轻量资源监控工具rea的完整实践

很多朋友看到"rea"这个标题时,大概率会以为打错了字,或者觉得这是某个库的缩写。我要先坦白一件事——它最初真没有什么标准全称,只是某天我在终端里随手敲的三个字母,用来命名一个空目录。后来这个目录慢慢长成了一个完…

作者头像 李华
网站建设 2026/10/21 23:14:17

Docker实战笔记:镜像、容器、数据卷与Compose编排核心用法

要是你最近也跟我一样,被同一个问题反复折腾——新拉下来的代码在本地怎么都跑不起来,在同事电脑上一秒启动,部署到测试环境又冒出一堆新报错,那这篇记录Docker用法的文章你应该能看完。我早些年做项目部署时没少被这种“环境不一…

作者头像 李华
网站建设 2026/10/21 23:14:10

刷题笔记方法论:从记录到复盘的高效刷题指南

1. 刷题笔记的正确打开方式:从记录到复盘先说个扎心的现实:很多人刷题就是打开题库、看题、想了十分钟、没思路、看题解、恍然大悟、关掉页面,过两天再遇到同类型题目,大脑依旧一片空白。这种“眼睛会了手不会”的状态&#xff0c…

作者头像 李华
网站建设 2026/10/21 23:13:09

高效技能建设:从技能树规划到刻意练习的成长方法论

“skills”这个词,看起来就是一个普通的英文单词,但当它作为一个人职业生涯的关键词反复出现时,背后就不再是简单的“技能列表”,而是一整套关于如何学习、如何选择、如何成长的方法论。我在这个行业里摸爬滚打这么多年&#xff0…

作者头像 李华
网站建设 2026/10/21 23:12:23

IM二维码钓鱼攻击链分析:跨境业务安全盲区与防线构建

二维码钓鱼这两年根本不是新鲜词,邮件侧已经打了无数轮补丁。但最近我盯了几起发生在跨境业务场景里的案例,发现一个很刺眼的规律:骗子把二维码搬进了IM聊天窗口,而且专挑出海企业的业务群下手。邮件安全网关扫描不到IM里的图片&a…

作者头像 李华