Python房产数据智能推荐系统:Django与协同过滤的实现

发布时间:2026/10/21 10:21:06
Python房产数据智能推荐系统:Django与协同过滤的实现 最近不少做毕业设计的同学跑来问我能不能推荐一个“既有算法含量、又有界面展示、还好答辩”的题目。我一般会指向一个组合Python房产数据智能推荐系统。这个题目有意思的地方在于它不是单纯做一个网站或者单纯训练一个模型而是把数据爬取、清洗分析、协同过滤推荐、可视化展示全部串了起来用的是Django框架再配上百度地图做位置展示整体完成度非常高。无论你是想拿来当毕设还是想自己练手做一个完整的全栈数据项目这套思路都值得花时间吃透。我最初接触类似项目时总以为推荐系统是算法工程师才能碰的东西真正动手才发现只要理解了协同过滤的核心逻辑用Python实现一遍并没有想象中那么难。真正让我觉得花时间的反而是数据处理和系统集成这些“脏活累活”。这篇文章会从整体设计讲到具体实现再把我踩过的坑、排查问题的思路一并整理出来希望能帮你少走弯路。1. 项目整体设计与技术选型为什么是Django 协同过滤 百度地图1.1 核心需求拆解这个系统到底要做什么先给这个项目定个位。房产数据智能推荐系统本质上是一个带推荐引擎的信息展示平台。用户进来可以看到房源列表、房源详情系统根据用户的行为浏览、收藏、点击或者用户的画像偏好区域、价格区间、户型来推荐可能感兴趣的房源。管理员端可以维护房源数据、查看统计图表。从毕业设计或者个人项目的角度这套系统覆盖了几个关键能力点数据层面要有足够多的房产数据字段比如小区名称、户型、面积、朝向、楼层、价格、区域、经纬度、周边配套等。算法层面要有一个能跑通的推荐逻辑协同过滤是最经典也最好解释的选择。展示层面前端要有列表、详情、推荐结果页还要有数据可视化大屏或者统计图表。地图层面房产天然带地理位置属性接入百度地图展示房源位置和周边信息会显得非常实用。把这些能力点翻译成技术选型就是后面说的这套方案。1.2 技术选型背后的逻辑每个组件解决什么问题我见过不少同学一上来就选前后端分离、微服务、深度学习FM模型结果做到中期发现根本hold不住。这个项目我建议的定位是“经典技术栈 核心亮点”而不是“大而全”。Django框架自带ORM、Admin后台、模板引擎、用户认证做这种带数据管理的系统效率极高。你不需要自己写数据库连接、不用重复造登录注册的轮子可以把精力放在推荐算法和可视化上。协同过滤推荐算法这是项目的“算法担当”。相比深度学习模型协同过滤逻辑清晰、计算量可控、解释性强。面试或者答辩时你可以把相似度计算、推荐列表生成的过程讲得很清楚。百度地图JavaScript API房产信息不能只是一堆文字地图能直观展示房源位置、周边配套甚至可以做范围检索。相比静态图片地图交互会让整个系统的体验感提升一大截。ECharts可视化用于展示房价分布、区域均价对比、户型占比、价格区间分布等图表。这些都是从数据库里聚合出来的真实数据视觉冲击力强也最容易在答辩现场抓眼球。1.3 系统功能模块划分四表三端一个算法我习惯在写代码前先把系统拆成模块这样后面填代码的时候心里不慌。整个项目可以分为以下几个核心模块模块核心功能涉及技术点用户模块注册、登录、会话管理、收藏房源Django内置User扩展房源管理模块房源数据的增删改查、导入导出Django ORM、Admin推荐模块基于用户行为计算相似用户、生成推荐房源列表协同过滤、皮尔逊/余弦相似度可视化模块区域房价柱状图、户型占比饼图、价格热力图、地图标点ECharts、百度地图搜索筛选模块按价格、区域、户型、朝向筛选房源关键词搜索ORM查询、Q对象数据库至少需要这几张表用户表、房源表、用户行为表浏览/收藏/评分、推荐结果表可实时计算也可预计算存储。表结构设计是后面一切逻辑的基础我通常建议把行为表和房源表的索引建好不然后期数据量一大查询会越来越慢。2. 数据准备与预处理推荐系统的地基是数据不是算法2.1 房源数据字段设计与采集思路推荐算法是“数据喂出来的”数据质量直接影响推荐效果。房产数据可以从公开的房产网站上采集模拟数据也可以用Faker库生成测试数据。为了保证系统能跑通我建议至少包含以下字段房源ID、小区名称、所在区域、具体地址、经纬度户型几室几厅、面积、朝向、楼层、装修情况总价、单价、建造年限房源描述文本、封面图URL、发布时间周边配套标签数组如“近地铁”“学区”“商圈”如果使用模拟数据一定要让数据分布尽量符合真实规律。比如中心区域单价高、面积小郊区单价低、面积大一居室面积集中在40-70三居室集中在90-140。这种“人为的真实感”能让可视化图表和推荐结果看起来更靠谱。2.2 数据清洗与特征工程从原始数据到模型输入假设你手上拿到了3000条房源数据直接扔进数据库是不行的。常见的清洗步骤有去重同一小区、同一户型、同一面积、同一总价的房源很可能是重复项用Pandasdrop_duplicates先处理一遍。缺失值处理面积、总价不能为空如果缺失可以选择删除或者用同小区同类户型的中位数填充。经纬度缺失的房源地图上无法展示建议要么补齐、要么剔除。格式统一价格字段可能是字符串500万要转成数值500面积可能存在89.5平要转成浮点数。这部分最繁琐但是不做的话后面排序、筛选、画图全是坑。价格计算单价总价/面积这个字段经常用来做区域对比和异常值检测。如果某个房源单价是周边均价的3倍以上大概率是数据录错了。特征工程方面不需要做得太复杂。我一般把特征分为两类用户可感知的显式特征区域、户型、面积、朝向、价格和计算得到的隐式特征区域热度、户型偏好度、价格段偏好。显式特征用于筛选搜索隐式特征用于推荐算法里的评分预测。2.3 用户行为数据的构造没有真实行为怎么训练协同过滤很多学生在自己电脑上做这个项目没有真实用户行为数据。这是阻挡推荐系统落地的一个大坎。解决思路有两种用爬虫模拟行为某些平台的“看过此房的人也看过”可以作为浏览行为来源但这种方式数据量不稳定不推荐。用代码生成行为数据写一个脚本模拟若干用户每个用户对若干房源产生浏览、收藏行为。生成逻辑要符合常识比如用户浏览房源时会倾向于同一区域或相近价格区间收藏行为比浏览行为更稀疏。我实际做的时候生成了50个模拟用户每个用户平均浏览过50-100套房源、收藏过5-15套房源。行为数据表结构大致是user_id、house_id、behavior_type浏览器、收藏、score浏览为0/1收藏为5也可以设置更细的评分、timestamp。这样协同过滤算法就有米下锅了。3. 协同过滤推荐算法的实现从相似度到推荐列表3.1 基于用户的协同过滤找到和你口味相似的人协同过滤的核心假设是如果用户A和用户B在历史行为上相似那么A喜欢的物品B也有可能喜欢。基于用户的协同过滤UserCF分两步计算用户之间的相似度。找出与目标用户最相似的K个用户把这K个用户喜欢的、目标用户没看过的物品推荐出去。计算相似度的方式有很多最常用的是余弦相似度。把每个用户的物品行为向量化比如用户对所有房源的行为组成一个向量行为值有浏览、收藏、无行为然后计算两个向量之间的余弦夹角。夹角越小表示相似度越高。Python代码不算复杂最朴素的写法如下from sklearn.metrics.pairwise import cosine_similarity import numpy as np def user_based_recommend(user_id, behavior_matrix, top_k5): # behavior_matrix: DataFrame行是用户列是房源值是行为分 sim_matrix cosine_similarity(behavior_matrix) target_idx list(behavior_matrix.index).index(user_id) sim_scores list(enumerate(sim_matrix[target_idx])) # 排除自己取相似度最高的前top_k个用户 sim_scores sorted(sim_scores, keylambda x: x[1], reverseTrue) sim_scores [s for s in sim_scores if s[0] ! target_idx][:top_k] # 相似用户行为累加过滤掉目标用户已交互过的物品 rec_dict {} for idx, score in sim_scores: user_items behavior_matrix.iloc[idx] interacted behavior_matrix.iloc[target_idx] for item_id, val in user_items.items(): if val 0 and interacted[item_id] 0: rec_dict[item_id] rec_dict.get(item_id, 0) val * score # 按累加得分排序 rec_list sorted(rec_dict.items(), keylambda x: x[1], reverseTrue) return rec_list这个写法是算法原理的直接体现适合答辩讲解。不过实际项目里如果用户和房源数量都比较大稀疏矩阵会占用大量内存建议改用scipy.sparse矩阵存储或者用surprise库封装的算法。3.2 基于物品的协同过滤相似的房子才是更稳的推荐UserCF在用户量少、行为稀疏时效果并不好因为“相似用户”往往找不准。我推荐再实现一种基于物品的协同过滤ItemCF这也是电商系统里常用的方案。思路是如果很多用户都同时浏览/收藏了房源A和房源B那么A和B是相似的推荐时取出用户最近交互过的房源找到与它们最相似的房源推荐给用户。实现上分成两步训练阶段离线计算房源相似度矩阵推荐阶段在线查表。房源相似度计算同样可以用余弦相似度只是把行为矩阵转置一下行是房源列是用户。def item_based_recommend(user_history, item_sim_matrix, top_n10): # user_history: {house_id: score,...} rec_score {} for item, score in user_history.items(): sim_items item_sim_matrix[item] for sim_item, sim_val in sim_items.items(): if sim_item not in user_history: rec_score[sim_item] rec_score.get(sim_item, 0) score * sim_val return sorted(rec_score.items(), keylambda x: x[1], reverseTrue)[:top_n]在实际系统中我两种算法都做了然后做一个加权融合如果用户行为比较丰富以UserCF的结果为主如果行为稀疏则以ItemCF为主。这个决策逻辑本身也是可以写进论文的亮点。3.3 相似度公式的选择与计算细节余弦还是皮尔逊写协同过滤的时候选相似度计算公式是一个很关键的环节。我对比过几种常见公式余弦相似度计算两个向量的夹角不考虑用户评分尺度的差异性。适用于行为数据是0/1或者标准化后的评分。皮尔逊相关系数先减去用户各自的平均分再算余弦能消除用户的评分偏好偏差。比如有的人习惯给高分、有的人习惯给低分皮尔逊处理这类情况更稳。杰卡德相似度交集/并集适合行为是集合是否购买、是否浏览的场景。房产推荐场景下我倾向于把行为先转成“0/1”或者“归一化分数”然后算余弦相似度。因为大多数用户行为只有浏览和收藏两种评分数据并不存在皮尔逊的优势发挥不出来。只有当你自己构造评分数据比如浏览1分、收藏2分、回访3分时皮尔逊才有价值。注意无论选择哪一种都要先把稀疏矩阵的0值处理清楚。如果用户和房源数量大千万记得用csr_matrix这类稀疏格式存储否则一个1000用户*3000房源的全量矩阵内存占用就已经很可观了。3.4 冷启动问题新用户和新房源怎么推荐推荐系统里绕不开冷启动问题。新用户没有任何行为协同过滤根本找不到相似用户新房源没有任何人浏览也不会被推荐。我用的处理方案是对新用户使用“热门推荐”也就是全站浏览/收藏量最高的房源。这个逻辑简单有效也是很多平台的默认做法。对新房源基于内容的推荐兜底比如根据区域、户型、价格区间计算与已有房源的相似度推荐给可能感兴趣的用户。在模拟数据里人为给每个新用户分配5-10条初始行为缓解冷启动的同时也方便演示算法效果。代码实现里只需要在推荐入口加一个判断def recommend_for_user(user_id): if not user_has_behavior(user_id): return get_hot_houses(limit10) # 正常协同过滤逻辑这个判断虽然不起眼但却是系统可用性的关键。3.5 推荐结果的排序与过滤拼出像样的推荐列表就算相似度算出来了也不能直接把top-N房源丢给前端。我一般会做三层过滤过滤掉用户已经浏览或收藏过的房源避免重复推荐。过滤掉已下架或不可售房源状态字段做控制。过滤掉相似度得分过低的房源设置一个最低阈值比如得分低于0.05的不要防止出现不相关结果。排序完成后推荐系统会返回一串房源ID。然后我用Django ORM把它们查出来连同推荐理由一起传给前端。比如“因为您浏览过滨江花园的房源所以为您推荐同区域的滨江华府”。这种解释功能做出来答辩的时候非常加分。4. Django系统集成与可视化让算法结果真正跑在网页上4.1 Django项目结构与数据模型设计整个Django项目我习惯按照下面的结构组织house_project/ ├── manage.py ├── house_recommend/ │ ├── settings.py │ ├── urls.py ├── apps/ │ ├── users/ # 用户模块 │ ├── houses/ # 房源管理 │ ├── recommend/ # 推荐模块 │ ├── stats/ # 统计可视化 ├── static/ ├── templates/ └── scripts/ ├── generate_data.py ├── build_sim_matrix.py关键的数据模型定义如下简化版from django.db import models class House(models.Model): title models.CharField(max_length200) district models.CharField(max_length50) # 区域 address models.CharField(max_length255) longitude models.FloatField() latitude models.FloatField() rooms models.CharField(max_length20) # 户型 area models.FloatField() direction models.CharField(max_length10) total_price models.FloatField(help_text总价单位万元) unit_price models.FloatField() image models.URLField(blankTrue) tags models.CharField(max_length255, blankTrue) created_at models.DateTimeField(auto_now_addTrue) class UserBehavior(models.Model): user models.ForeignKey(User, on_deletemodels.CASCADE) house models.ForeignKey(House, on_deletemodels.CASCADE) behavior_type models.CharField(max_length10) # browse/favorite score models.FloatField(default0) created_at models.DateTimeField(auto_now_addTrue)建表的时候一定要加数据库索引尤其是UserBehavior里user和house的联合索引否则推荐查询会随着数据量增加而明显变慢。另外unit_price这种导出字段不建议每次查询的时候临时计算生成数据时算好存进去展示会快很多。4.2 百度地图接入房源定位与周边信息展示百度地图在这个项目里承担两个作用一是房源详情页展示准确位置二是房源列表页用聚合标记点展示地图概况。接入方式不复杂。先到百度地图开放平台申请一个浏览器端AK密钥然后在模板中引入JavaScript API。script typetext/javascript srchttps://api.map.baidu.com/api?v3.0ak你的AK/script script var map new BMap.Map(allmap); var point new BMap.Point({{ house.longitude }}, {{ house.latitude }}); map.centerAndZoom(point, 16); var marker new BMap.Marker(point); map.addOverlay(marker); var infoWindow new BMap.InfoWindow(p{{ house.title }}/pp{{ house.address }}/p, { width: 200, title: 房源详情 }); marker.addEventListener(click, function(){ map.openInfoWindow(infoWindow, point); }); /script这里有个必须注意的细节百度地图使用的坐标系是BD-09而很多爬虫拿到的经纬度是GCJ-02或者WGS-84。如果不做坐标转换地图上的点会偏移几百米到几公里。我一开始没注意结果房源全部漂到了河对岸。解决办法是写一个小工具函数做BD-09、GCJ-02、WGS-84之间的转换网上的标准代码很多这里不贴了但一定要放到项目里。提示申请百度地图AK时注意设置域名白名单。本地调试用http://localhost:8000部署上线要改成实际域名。如果忘记设置地图在页面上会白屏或者报APP Referer校验失败。4.3 基于ECharts的数据可视化页面可视化模块我放在一个独立的“数据看板”页面用ECharts画四个图区域均价柱状图、房源价格区间分布图、户型占比饼图、月度房源发布趋势折线图。后端只需要提供JSON接口前端异步加载数据。Django视图里可以这样写from django.db.models import Avg, Count from django.http import JsonResponse from .models import House def district_price_api(request): data House.objects.values(district).annotate(avg_priceAvg(unit_price)).order_by(-avg_price) result [{district: item[district], avg_price: round(item[avg_price], 2)} for item in data] return JsonResponse({code: 0, data: result})前端用fetch或者axios拿到数据之后setOption更新图表。ECharts的配置项比较多但套路基本一致先初始化实例再指定x轴、y轴、series类型。第一次写的时候不要想着做太炫酷的3D效果把数据讲清楚更重要。整套可视化接口看起来简单但有一个很现实的好处它逼着你把数据库查询优化做到位。比如区域均价柱状图直接GROUP BY district就行但如果是“最近30天每天热门区域TOP5”这种图单次ORM查询是做不出来的需要用子查询或者先聚合再在Python里排序。做完这个需求你对ORM的group by、annotate、order by掌握程度会上一个台阶。4.4 前端页面与推荐链路打通从用户点击“为我推荐”到看到推荐结果完整链路大概是这样用户在首页点“智能推荐”按钮请求/recommend/?user_idxxx。Django视图从Session拿当前用户调用推荐模块。推荐模块读取用户行为数据计算相似度、生成候选集、过滤排序。返回房源列表模板渲染卡片展示“推荐理由”文本。用户点击房源进入详情页详情页记录一条新的“浏览”行为用户点收藏记录“收藏”行为。这些新行为又会影响下次推荐结果。把这个闭环做成动态的比一次性静态展示要高级得多。我在实际项目里用了一个小技巧把行为记录逻辑用middleware实现拦截所有房源详情页请求自动写浏览记录省得在每个视图里重复调用。前端页面我用的是朴素的Bootstrap 简单CSS没有用复杂的前端框架。原因是Django模板渲染配合Bootstrap足够应付房源列表、详情、看板这些页面而且不用维护前后端分离那种双工程体系。对毕设项目来说减少技术栈复杂性就是减少翻车概率。5. 常见问题与排查技巧实录5.1 协同过滤计算慢、内存爆炸怎么办如果你生成的数据量比较大比如5000个用户、10000个房源直接用cosine_similarity在稠密矩阵上计算会非常慢。我踩过这个坑一个5000x10000矩阵的内存开销是400MB本地电脑直接卡死。优化思路有三个数据稀疏化存储把行为矩阵转成scipy.sparse.csr_matrix只存非0值。离线预计算物品相似度矩阵不实时算而是用脚本定期计算结果存到数据库或者内存缓存里。推荐请求只读结果不做矩阵运算。降维剪枝只计算“活跃用户”或者“最近有行为的用户”忽略长时间不活跃的账号。from scipy.sparse import csr_matrix def build_behavior_matrix(behavior_data, users, houses): # 建立user和item到index的映射 user_idx {u: i for i, u in enumerate(users)} item_idx {i: j for j, i in enumerate(houses)} rows, cols, values [], [], [] for uid, hid, score in behavior_data: rows.append(user_idx[uid]) cols.append(item_idx[hid]) values.append(score) return csr_matrix((values, (rows, cols)), shape(len(users), len(houses)))5.2 推荐结果全是热销房源个性化不明显怎么办这是一个非常影响观感的问题如果你发现推荐列表里翻来覆去就是那几套热门房源说明你的算法退化成“全局热门推荐”了。原因通常是相似度计算太粗糙比如所有用户的行为集中在少数热门房源上导致大家看起来都“相似”。我试过的有效方法是行为权重差异化浏览记1分收藏记5分分享记8分同时给房源添加“新颖度惩罚因子”越热门的房源权重下降越多。具体做法是在最终得分乘以一个衰减系数比如hot_penalty 1 / log(1 house_click_count)。这样既保留了协同过滤的推荐能力又不会让结果千篇一律。5.3 百度地图不显示、白屏、点偏移这个问题我在前面提过这里再完整列一个排查清单现象可能原因解决办法地图完全不显示AK缺失或域名白名单未配置在百度地图开放平台检查AK配置控制台报“APP Referer校验失败”当前访问域名不在白名单添加http://localhost:8000或实际域名地图显示但标注偏了坐标系不一致WGS-84/GCJ-02转BD-09添加坐标转换函数多个marker只显示一个变量名覆盖每次循环用let声明marker变量另外百度地图API在本地调试时如果用file://协议打开页面也会有问题一定要通过Django的开发服务器访问。5.4 表格设计不合理导致后续扩展痛苦很多同学一开始设计数据库表时只考虑了房源表后面加推荐功能时发现行为数据没地方放。我的建议是从第一天就把behavior表建好哪怕里面暂时没有数据只要结构在后面写推荐逻辑的时候就不用来回迁移数据库。同理用户收藏关系表也建议提前建好收藏功能可以说每个房源项目都标配。还有一个和Django Admin相关的坑Admin后台默认会把外键显示成下拉框如果房源和区域数据量大下拉框会非常卡。解决办法是在Admin的raw_id_fields里指定外键字段改为输入框这个问题解决掉之后后台维护数据会顺畅很多。5.5 模拟数据不真实导致答辩被追问我见过有的同学生成的模拟数据完全违背常识户型面积7平米、单价500元一平、所有房源均价相同。这种数据一展示出来明眼人就知道是假的。构建模拟数据时我用了一个简单的规则组合区域热度决定价格基准比如核心区域基准单价8万/平边缘区域基准单价2万/平。面积和户型挂钩一居室45-70平两居室70-100平三居室100-140平。总价 单价 * 面积 随机噪声噪声幅度控制在5%-15%。楼层、朝向、装修这些字段随机生成但“近地铁”这类标签要与区域关联。这样生成出来的数据任何SQL查询、图表、推荐结果都是符合直觉的。答辩老师问到“你的数据是从哪来的”“数据分布是否合理”时你也能有理有据地回答。写在最后给正在做这个项目的同学一点私房建议这套系统如果只是照着我上面的代码一步一步抄大概三四天能跑通但如果想在答辩和简历里有话可讲我建议你额外做三件事。第一把离线预计算和在线推荐分离这个设计想清楚这不仅是性能优化更是工程思维的体现。第二在推荐结果页加上“推荐理由”展示哪怕是简简单单一句“因为你对XX区域感兴趣”都会让评委觉得你是真的理解了推荐逻辑而不是调了一个包。第三自己动手造一遍数据这个过程会让你对数据清洗、特征构建、模型输入之间的链路有非常深刻的体感这是任何现成数据集都换不来的经验。我始终觉得毕设项目的意义不在于算法有多前沿、框架有多新潮而在于你能否把一个完整的业务链路走通并且每一步都能讲清楚为什么这么选。房产数据智能推荐系统恰好提供了一个不高不低的平台数据量恰到好处、算法难度适中、展示效果又极其直观。哪怕最后你决定换一个题目方向在这套项目里练过的数据思维、建模思路和调试能力也能顺利迁移过去。真正动手做一遍你收获的远比一纸代码多得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询