资讯动态

Python一手房数据采集分析与预测系统:爬虫+Flask+机器学习实战解析

发布时间:2026/10/9 0:38:40 来源:尧图企业网站定制
毕业设计选题年年有人头大但“Python 一手房数据采集分析与预测系统”这个题绝对是这几年本科阶段最稳的组合之一。爬虫负责拿数据Flask 负责搭界面Scikit-learn 负责做预测三样东西拼在一起既避开“纯调库没深度”的质疑又不会因为技术太偏导致做不完。这篇文章我把这套系统的完整实现思路、技术选型逻辑、关键代码和踩坑经验全部拆开讲希望能给正在做同类题目的同学一点实实在在的参考。开篇先把系统的全貌说清楚它不是一个单点功能的小工具而是从数据源头到最终展示的一条完整链路。你首先要有一个爬虫定时或手动从房产信息平台上抓取一手房楼盘的基础数据抓下来的脏数据经过清洗和结构化存进数据库之后 Flask 后端把数据通过接口提供给前端页面用表格和图表做可视化展示最后再用 Scikit-learn 训练一个价格预测模型让用户输入楼盘特征返回一个参考均价。整个流程围绕“房价”这一个核心业务前后呼应非常适合作为毕业设计的项目主线。1. 毕业设计选题拆解这套系统到底在做什么1.1 标题关键词背后的真实需求“Python 一手房数据采集分析与预测系统”这个题目拆开来看就三个核心关键词数据采集、数据分析和房价预测。数据采集对应 Requests 爬虫数据分析对应 Flask 可视化房价预测对应 Scikit-learn 机器学习。很多同学第一眼看到这种题目会觉得它只是个拼盘但实际上这个拼盘拼得很有技巧。拿“一手房”和“二手房”的区别来说这就是一个典型的选题优化。二手房挂牌价格受楼层、朝向、装修、学区等个体因素影响极大同一个小区不同房源单价能差出好几千数据噪声非常大对机器学习的回归任务极不友好。而一手房数据通常按“楼盘”这个维度组织价格是均价或起价字段相对整齐户型、容积率、绿化率、物业费等属性也都是现成的结构化信息做回归预测时特征清晰、可解释性强。这个题目在选题阶段就已经通过“一手房”三个字规避了大量数据清洗的麻烦这在答辩时是可以说出口的加分项。再往深一层看这个题目还暗合了一个市场逻辑购房者在买期房时最关心的是“这个楼盘的价格到底值不值”。如果你能在批量采集周边竞品楼盘数据的基础上给出一个基于历史数据和项目参数的综合参考价那这个系统就不是单纯的展示工具而是带有决策支持含义的。这也是后面引入机器学习的意义所在不是为了让题目听起来高级而是业务上有真实需求。1.2 系统功能边界与整体使用流程这套系统的功能边界大致划分为五个模块爬虫采集模块、数据清洗模块、数据存储模块、可视化展示模块、房价预测模块。每个模块之间有明确的数据流向爬虫产出原始 HTML清洗模块把 HTML 转成结构化表格然后数据写入数据库Flask 从数据库读数据送给前端图表预测模块则独自分出一条线从历史数据中训练模型再接收用户输入做预估。从用户角度看系统使用流程一般是这样的启动 Flask 服务后前端首页展示整体数据看板包括各区县平均房价柱状图、楼盘价格区间分布图、户型面积段分布饼图等用户点击某个区县或某个楼盘可以看到详细字段数据预测页面提供表单用户输入预期区域、容积率、绿化率、物业费等参数点击按钮后后台调用已经训练好的模型返回一个参考均价和置信区间。整个过程不需要用户接触任何代码这也是毕业设计演示时的核心卖点。从软件工程角度看这个项目的数据流是单向且分层清晰的。采集层不依赖服务层服务层不关心数据从哪来各模块之间通过数据库或 JSON 接口解耦。这样的结构在答辩时很好讲每一层都能单独提问、单独验证老师问到任何细节你都能对应到具体的实现代码和数据结构。整个系统的复杂度也处在本科毕设的黄金区间——不是简单的小作业但也远没到做不完的程度。2. 技术选型背后的逻辑为什么是 Flask Requests Scikit-learn2.1 框架选择Flask 学习成本低部署又稳定Python 的 Web 框架里现在讨论热度最高的两个是 Flask 和 FastAPI。FastAPI 有自动生成的接口文档性能更好还支持异步看起来比 Flask 先进不少但它需要理解 Pydantic 模型、异步协程、依赖注入这些概念对刚开始接触 Web 开发的同学来说学习曲线明显偏高。房价格预测系统这种场景用户量就是几个评委老师并发请求低到可以忽略不计Flask 的同步模型完全没有任何压力。更重要的是 Flask 的整个技术栈对学生非常友好。自带 Jinja2 模板引擎不需要额外搭一套前后端分离的工程结构路由逻辑用一个装饰器就能写清楚配合 SQLite 或者 SQLAlchemy 操作数据库也有一套非常成熟的学习路径。部署时pip install flask装完就能python app.py直接跑起来这在毕业答辩的现场环境里是很大的优势。你永远不知道教室电脑的 Python 环境是什么样依赖越少翻车概率越低。另外Flask 有极其丰富的第三方扩展和现成教程ECharts 的图表示例、Bootstrap 的后台模板、数据库连接池的配置网上一搜一大把出了问题随手就能找到解决方案。对毕设时间紧张的同学来说生态成熟本身就是一种隐形的生产力。选 FastAPI 可能要花三成时间在处理异步和参数校验上而选 Flask 这部分时间可以全部省下来投入到爬虫和模型调参上。2.2 Requests 就是个够用的爬虫方案爬虫技术选型常见的有 Requests BeautifulSoup、Scrapy、Selenium再进阶一点是 Playwright。这个题目选 Requests 是完全合理的因为一手房楼盘列表页大多还是服务端渲染的传统页面不需要执行繁重的 JavaScript 才能拿到数据用 Requests 直接请求 HTML再用 BeautifulSoup 解析节点就能搞定。Scrapy 的爬虫性能确实强异步并发、中间件机制、管道处理一应俱全但它的框架约束也多写一个爬虫要先理解 Item、Spider、Pipeline 的概念对毕设来说有一点杀鸡用牛刀的意思。Selenium 和 Playwright 是应对前端动态渲染的如果数据源是 Vue 或 React 单页应用用它们也好使但速度和资源占用都不理想爬几万条数据能把电脑跑得风扇狂转。Requests 写个脚本循环遍历城区和页码解析列表把字段塞进 Dataframe简单直接出了问题也容易排查。这里面值得重视的反而是请求管理。Requests 的优势不是功能多而是薄、透明方便做请求频率控制、请求头伪装和异常重试。我在做这个项目时就强烈建议把请求封装成一个独立函数统一管理 User-Agent、Referer、超时时间和重试逻辑而不是在循环里裸调requests.get()。你后面会深刻体会到爬得慢一点没关系被反爬机制封了 IP 才是最大的麻烦。2.3 Scikit-learn 是最适合本科阶段的机器学习库房价预测本质上是一个回归任务用 Scikit-learn 是顺理成章的选择。PyTorch 和 TensorFlow 虽然这两年热度极高但神经网络训练需要配置 GPU、设计网络结构、处理收敛问题对一个以 Web 系统为主的毕业设计来说这套复杂度会严重挤占其他模块的时间。Scikit-learn 的 API 设计极其统一fit、predict、score三步走几十行代码就能完成模型训练和评估。更重要的是Scikit-learn 提供了很多适合表格数据的经典模型比如线性回归、决策树、随机森林、梯度提升树等。房价预测这种任务特征量不大、数据量也就是几千条神经网络未必比调好参的随机森林更强。XGBoost 和 LightGBM 的效果可能好但是对新手来说配置环境有额外的坑而且答辩时老师不大关心你是不是用了最强的模型更关心你是否理解模型的基本原理为什么选它结果怎么评估。随机森林作为 Bagging 集成学习的代表原理容易讲清楚特征重要性也能可视化输出是很适合做毕业设计核心算法的选择。3. 核心模块实操爬虫、清洗与存储的完整实现3.1 一手房数据爬虫的请求封装与解析爬虫模块是整个系统的数据源头。以城市房产信息平台为例一手房楼盘列表页通常按城区分页展示URL 结构一般是平台域名/城市拼音/loupan/pg{页码}/页面里的每个楼盘卡片包含名称、区县、均价、户型等信息点进详情页还有容积率、绿化率、物业费等更详细的字段。毕设的数据量不需要很大抓一个城市的上千条历史楼盘数据已经完全够用所以不需要分布式抓取单机跑就行。下面是一段我常用的请求封装代码重点是超时设置、请求头伪装和重试机制import requests import time from random import choice UA_LIST [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..., Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ..., ] def fetch_page(session, url, retry3): headers { User-Agent: choice(UA_LIST), Referer: url.split(/loupan)[0] /, Accept-Language: zh-CN,zh;q0.9, } for attempt in range(1, retry 1): try: resp session.get(url, headersheaders, timeout10) if resp.status_code 200: return resp.text elif resp.status_code 429: wait_time 10 * attempt print(f收到 429等待 {wait_time}s 后第 {attempt} 次重试) time.sleep(wait_time) else: time.sleep(2) except requests.RequestException as e: print(f请求异常: {e}) time.sleep(2) return None session requests.Session() html fetch_page(session, https://example.com/beijing/loupan/pg1/)这段代码有几个细节需要注意。第一使用requests.Session()保持连接复用比反复创建独立连接更高效也能减少被服务端识别为爬虫的特征。第二不同的 User-Agent 要随机切换避免同一指纹请求过多。第三遇到 429 状态码代表的“请求过多”千万不能硬刚做指数退避的重试逻辑才是正确做法。我曾经图省事不写重试结果跑到半程被断掉前两小时的数据全部作废只能重新爬教训很深刻。解析部分用 BeautifulSoup 就能完成。先定位楼盘列表容器再按卡片节点逐个提取字段from bs4 import BeautifulSoup def parse_list_html(html): soup BeautifulSoup(html, html.parser) items [] for card in soup.select(div.loupan-card): name_el card.select_one(a.lp-name) price_el card.select_one(span.price) area_el card.select_one(span.area) if not name_el or not price_el: continue items.append({ 楼盘名称: name_el.text.strip(), 价格: price_el.text.strip(), 面积段: area_el.text.strip() if area_el else , 链接: name_el.get(href), }) return items实际抓的时候会遇到同一个选择器因为页面结构微调而失效的情况所以解析代码必须有容错空间元素不存在时用条件判断兜底避免一个 None 引发整批数据丢失。解析字段建议完全对齐后面入库和建模需要的字段能省下大量二次处理的精力。3.2 字段清洗、类型转换与去重策略爬下来的原始数据一定是不干净的。楼盘均价往往带“元/㎡”、户型面积可能写成“85-120㎡建面”、开盘时间可能是“2023-06-18”这些字段计算机不能直接用于计算和建模必须清洗成标准格式。清洗逻辑我建议单独写成函数用 Pandas 统一处理方便复现和调试import pandas as pd def clean_price(text): # 从 均价 45000元/㎡ 提取 45000 if pd.isna(text): return None import re match re.search(r(\d(?:\.\d)?), str(text)) return float(match.group(1)) if match else None def clean_area_range(text): # 从 85-120㎡ 提取最小值 85 和最大值 120 if pd.isna(text): return None nums re.findall(r\d, str(text)) if len(nums) 2: return int(nums[0]), int(nums[1]) return None, None df[均价] df[价格文本].apply(clean_price) df[面积_min], df[面积_max] zip(*df[面积段].apply(clean_area_range))清洗过程中最容易忽略的是隐藏字符和全角字符。中文网站页面上经常有\xa0这种不间断空格肉眼看不出来但写入 JSON 或数据库时会引发奇怪的报错。我习惯解析完文本先做一次text.replace(\xa0, ).strip()把这类问题提前抹掉。另外数据去重也不是直接drop_duplicates()就完事一手房楼盘有分期开发的情况同一个项目名称可能被平台拆成多期所以我会以“楼盘名称 区县”作为去重键再做一次drop_duplicates(subset[楼盘名称, 所在区县])操作。价格字段为空的记录要单独处理要么人工补采要么直接删除不能让空值进入模型。3.3 存储设计SQLite 还是 MySQL数据量在几千条级别时SQLite 是性价比最高的选择。不需要单独安装数据库服务端Python 标准库自带sqlite3存成单文件路径配置也简单移动设备时一整个目录拷走就行。很多同学上来就上 MySQL结果本地没装、密码忘配、编码出乱码浪费大量时间在数据库环境上。毕设场景用 SQLite 完全够甚至算一个优点演示时只需要演示代码目录不需要额外展示数据库配置过程。如果你确实想用 MySQL我的建议是直接用 SQLAlchemy ORM 定义数据模型这样从 SQLite 切换到 MySQL 时只需要改连接字符串表结构不用动。举一个模型定义的例子from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() class House(db.Model): __tablename__ house id db.Column(db.Integer, primary_keyTrue) name db.Column(db.String(128), uniqueTrue) district db.Column(db.String(64)) avg_price db.Column(db.Float) plot_ratio db.Column(db.Float) # 容积率 green_ratio db.Column(db.Float) # 绿化率 property_fee db.Column(db.Float) # 物业费 min_area db.Column(db.Float) max_area db.Column(db.Float) open_date db.Column(db.String(32)) url db.Column(db.String(256))数据库设计时不需要搞复杂的表关系和索引一个主表存楼盘核心字段就够了预测模型的输入特征也是从这张表来。索引在district字段上建一个就够了因为可视化页面经常按区县做分组查询。数据量小过度设计索引反而增加了代码复杂度。4. Flask 后端与可视化展示的实现要点4.1 后端接口设计图表数据的前后端分离思路Flask 项目的页面渲染有两种做法一种是后端用 Jinja2 模板直接把数据塞进 HTML另一种是后端只提供 JSON 接口前端用 JavaScript 异步请求再渲染图表。我更推荐第二种因为图表库如 ECharts 天然就是option配置对象直接接收 JSON 数据更新图表非常顺滑而且前后端分离也让代码层次更清晰Flask 的主体就回归到接口中转的角色。举一个区县均价接口的例子from flask import Flask, jsonify, request, render_template from sqlalchemy import func app Flask(__name__) app.route(/api/district_price) def district_price(): district request.args.get(district, ) query db.session.query( House.district, func.avg(House.avg_price).label(avg_price), func.count(House.id).label(count) ) if district: query query.filter(House.district district) result query.group_by(House.district).all() data { categories: [row.district for row in result], prices: [round(row.avg_price, 2) for row in result], counts: [row.count for row in result], } return jsonify(data)设计接口的时候千万不要一个接口把所有数据全返回然后前端自己过滤。按“页面区块”拆接口每个接口只返回一个图表需要的数据这样前端代码更简短后端也更容易做局部缓存。比如首页需要四个图表就设计四个接口区县均价比、户型面积段分布、物业费分布、价格前十楼盘排行。每个接口都在路由注释里写明用途答辩时讲起来也清楚。4.2 可视化模块ECharts 图表的数据组织方式前端可视化我选了 ECharts原因是它图表类型丰富、中文文档完善、开箱即用。在 Flask 项目中只需在templates目录下放置一个 HTML 模板通过 CDN 引入 ECharts 脚本然后写几个fetch调用数据接口更新图表配置。下面是一段典型的区县均价柱状图代码!DOCTYPE html html langzh-CN head meta charsetUTF-8 title数据分析看板/title script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script style .chart { width: 100%; height: 400px; margin-bottom: 24px; } /style /head body h2各区县一手房均价对比/h2 div idchart_price classchart/div script async function loadPriceChart() { const resp await fetch(/api/district_price); const data await resp.json(); const chart echarts.init(document.getElementById(chart_price)); chart.setOption({ title: { text: 各区县均价 }, tooltip: { trigger: axis }, xAxis: { type: category, data: data.categories }, yAxis: { type: value, name: 元/平方米 }, series: [{ type: bar, data: data.prices, itemStyle: { color: #4A90D9 } }] }); window.addEventListener(resize, () chart.resize()); } loadPriceChart(); /script /body /html图表的配置要贴近业务的真实表达。柱状图适合区县之间横向对比饼图适合看户型面积段的占比散点图适合观察“均价 vs 绿化率”或“均价 vs 容积率”的相关性折线图适合看不同月份开盘楼盘的均价走势。我在实际项目里最重要的一个图表是散点趋势图它把机器学习预测出来的参考价和实际均价放一起做对比直观展示模型效果这个图在答辩时几乎必被问到建议优先做好。4.3 后端与模板联调的常见问题Flask 项目联调时最容易踩的坑是接口返回了数据但前端图表不显示。排查顺序一般是先用浏览器直接访问接口地址确认 JSON 是否正常再打开浏览器开发者工具看fetch请求是否报错最后检查图表容器的高度是不是为 0。ECharts 的图表容器如果父级没有设置高度init后画布是空的页面上看起来就像图表失效。我给每个.chart容器都强制设置了高度就能完全避免这种问题。另一个常见问题是前端请求跨域。Flask 开发的调试模式下默认监听127.0.0.1:5000如果你把页面直接用文件方式打开访问接口就会碰到 CORS 报错。解决方法要么老老实实用 Flask 自己渲染模板页面要么在 Flask 全局配置 CORS 中间件。对毕设项目来说我不建议引入额外的跨域配置统一走 Flask 渲染流程是最稳妥的。5. Scikit-learn 房价预测模型的构建与评估5.1 特征选择与标签定义房价预测模型的输入特征要从业务逻辑出发定义不能把原始字段全部丢进模型。一手房价格的主要影响因素通常有所在区县城市内部地段差异、容积率居住密度、绿化率环境品质、物业费服务档次、户型面积段定位刚需还是改善、开盘时间市场周期。其中区县是类别变量可以做哑变量编码或标签编码开盘年份也可以拆出来作为一个数值特征用来捕捉房价的时间趋势。我的做法是构造下面的特征 DataFramefeatures [district_encoded, plot_ratio, green_ratio, property_fee, min_area, max_area, open_year] X df[features] y df[avg_price]为什么不用楼盘名、链接这种字段因为它们是唯一标识符不能泛化模型学到的是“某个楼盘的名称对应某个价格”里没有任何可迁移的规律放进特征等于变相过拟合。区县的编码方式上我测试过两种方案标签编码效果不如哑变量编码因为区县之间根本没有顺序关系随机森林能处理这种非线性但会浪费树的分裂次数用pd.get_dummies()生成哑变量更稳妥。5.2 模型训练与超参数调优数据集划分要强调随机性和固定随机种子这样才能保证实验结果可复现。我习惯用train_test_split按照 8比2 划分训练集和测试集参数random_state42是网上一搜一大把的约定但不要小看这个固定种子它决定了答辩时老师看到的结果和你在本地开发时完全一致。下面给出一个完整的模型对比流程把线性回归、决策树、随机森林、梯度提升树放在一起对比效果from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) models { LinearRegression: LinearRegression(), DecisionTree: DecisionTreeRegressor(max_depth8, random_state42), RandomForest: RandomForestRegressor( n_estimators200, max_depth12, min_samples_leaf2, random_state42 ), GBDT: GradientBoostingRegressor(random_state42), } for name, model in models.items(): model.fit(X_train, y_train) pred model.predict(X_test) print(f{name}: MAE{mean_absolute_error(y_test, pred):.2f} fRMSE{mean_squared_error(y_test, pred, squaredFalse):.2f} fR2{r2_score(y_test, pred):.3f})跑完之后一般会发现随机森林在表格数据上表现稳定梯度提升树效果可能更好但训练慢一点。对于数千条数据的毕设项目随机森林的参数设置不需要过于复杂n_estimators在 200 左右就基本够用再加大收益很小训练时间却明显增长。调参的核心也不是越高越好而是在效果和可解释性之间找平衡。5.3 评价指标怎么解读才靠谱房价预测的评估不能只看 R2。R2 反映的是模型解释了多少方差但房价预测的更实际意义是“我的预测平均差多少钱”。所以我建议报告 MAE、RMSE 和 R2 三个指标MAE 表示预测值和真实值的平均绝对误差比如 MAE 等于 1800含义就是平均预测偏离 1800 元/平方米RMSE 对异常值更敏感如果 RMSE 明显大于 MAE说明有一部分楼盘的预测误差非常大R2 越接近 1 说明模型拟合程度越高但当 R2 达到 0.9 以上时就要警惕是否过拟合了。模型训练完成后要保存成文件Flask 启动时加载。用joblib是最省事的方式import joblib joblib.dump(best_model, house_price_model.joblib) # 在 Flask 中加载模型 model joblib.load(house_price_model.joblib) app.route(/api/predict, methods[POST]) def predict_price(): data request.get_json() features [data[district_encoded], data[plot_ratio], data[green_ratio], data[property_fee], data[min_area], data[max_area], data[open_year]] pred model.predict([features])[0] return jsonify({predicted_price: round(pred, 2)})模型文件不要放在static目录因为不需要被外界直接访问放项目根目录或者单独一个model目录使用相对路径加载这样整个项目移机时不会因为路径写死而报错。模型训练脚本和 Flask 应用代码建议分开训练是离线过程接口调用是在线过程毕设论文里也可以展示这种离线训练、在线预测的标准架构。6. 实操中踩过的坑与排查实录6.1 429 状态码与爬虫请求频率控制爬虫跑了不到十分钟突然打印一行exceeded retry limit, last status: 429 too many requests这是我在实践里遇到最频繁的问题。429 代表服务端限流了原因基本就是请求频率太高。解决思路有两条一是主动降低速度在网络请求循环里加time.sleep()把请求间隔控制在 3 到 5 秒二是完善退避重试逻辑遇到 429 时先等长一点时间再重试而不是立即重新请求。实践中更好的做法是按页面批次随机休眠不是固定间隔。固定 3 秒的请求间隔在服务端看来是极其规律的很容易被识别为机器行为。用random.uniform(2, 5)随机化请求间隔再搭配随机换 User-Agent整体请求看起来更接近真实用户。此外爬虫最好做成可断点续跑的形式把已经爬到的数据按页号记录进度失败后下次运行从断点继续不需要全部重头来。6.2 页面结构变化导致解析失败一手房平台的页面结构调整是家常便饭。今天能跑通的 CSS 选择器过两周可能就抓不到内容因为页面的 class 命名变化了或者某个字段从文字变成了图标。要应对这种不确定性解析代码必须尽量写“宽容”一些优先选择语义稳定的标签属性同时做好空值兜底。比如楼盘名称节点抓不到时这一条数据起码还能保留其他字段不要因为一个字段为 None 就把整条数据丢弃。另外我只建议把爬虫定位成“毕设演示模块”不要幻想它是一个可以长期稳定运行的自动化程序。房价平台的数据结构更新是持续的答辩前能跑通一次、抓到足够建模的数据量就已经满足毕设要求。你可以在论文里写这套爬虫的设计思路和容错策略而不是承诺它具备工业级稳定性这个定位要摆正。6.3 预测偏差过大时的排查思路当模型预测结果和真实市场价格差得离谱时大多数情况不是模型的问题而是数据的问题。首先要看训练集里有没有脏数据比如价格字段混入了“租金”或“首付”含义的文本清洗函数提取错数字其次要看特征是否包含太多缺失值某列缺失率超过 50% 就不要硬填了直接删掉该列最后看训练集和预测时的数据分布是否一致比如训练集里容积率范围是 1.0 到 4.5你预测时输入一个容积率 5.0 的极端值模型自然给出不靠谱的结果。排查时最快的验证方法是先挑测试集里几条已知结果的数据把模型预测结果打印出来和真实值做对比。如果不匹配集中在某个区县就重点检查该区县的数据质量和样本数量如果所有样本都不匹配就去检查特征编码是否前后一致。毕设项目的模型不需要达到商用级别的准度但至少要保证误差方向合理、分布均匀这本身就是一个可以说得清的分析结论。6.4 模型特征重要性怎么看随机森林训练完成后可以打印特征重要性判断哪些特征对房价的影响最大。这个结果不仅是一段代码输出更是论文里的重要图表import matplotlib.pyplot as plt importance best_model.feature_importances_ feat_names X.columns plt.barh(feat_names, importance) plt.xlabel(特征重要性) plt.tight_layout() plt.savefig(feature_importance.png, dpi200)实践下来通常会发现min_area、max_area和property_fee的重要性偏高这符合“以面积定定位、以物业费看档次”的市场逻辑。但如果某个明显应该重要的特征重要性很低就要反思是不是特征编码有问题或者该特征在数据里的方差太小。特征重要性图在答辩时非常提气因为它把“机器学习黑盒”变成了一个可解释的分析结论能直接支撑论文里的业务讨论章节。7. 项目扩展方向与毕业答辩的若干建议7.1 低成本可落地的扩展方向如果你的毕设时间和精力有余有几个扩展方向性价比很高。第一个是把单一城市的爬虫扩展为多城市对比比如北上广深加成都杭州在可视化页面增加城市切换功能这样一来系统从“一个城市的数据看板”升级成“跨城市楼市对比平台”业务价值更强。第二个是在预测模块增加用户反馈机制预测后收集用户对结果“偏高/偏低/合适”的评价积累一批修正样本为后续模型迭代做准备。第三个是结合时间序列做开盘价走势预测用历史月份均价训练一个季节性模型这会让系统具备“短期走势预判”能力。这些扩展都不需要引入新的重型技术栈在现有代码上做增量开发就能实现。需要注意的是毕业设计的核心永远是“完整可运行”千万不要因为加功能导致主线代码不稳定宁可在基础功能稳定后把扩展作为论文的“未来展望”章节来写也不要冒险在答辩前临时塞新功能翻车。7.2 答辩时怎么把项目讲明白答辩的十分钟陈述我建议按“问题 - 数据 - 技术 - 结果”四段式来组织。先讲清楚你想解决的问题也就是购房者难以判断新楼盘定价是否合理再介绍你采集了多少数据、覆盖哪些区县、数据质量情况如何然后讲技术方案为何选择 Requests、Flask、Scikit-learn 这个组合最后亮出模型评估结果和可视化看板重点解释特征重要性说明的房价逻辑。老师大概率会问的问题集中在这样几个方向为什么用随机森林而不用线性回归、数据量这么小模型会不会过拟合、爬虫的合法性边界在哪里、如果数据源改版了怎么处理。这些问题在文中各自的章节都有对应答案复习时对照着过一遍回答时注意先给结论再展开细节保持思路清晰。另外准备好一份 README 文档写清楚如何安装依赖、如何启动爬虫、如何运行 Flask、如何重新训练模型这既是论文附件的一部分也方便评委老师现场验证。我个人在实际操作中的感受是这套系统最大的价值不在于某个单点的技术有多深而在于它把所有模块串成了一个能自圆其说的完整故事。数据从哪来、怎么处理、展示什么、预测什么、结论是什么每一步都有依据每一步都能被追问。你自己做一遍之后对爬虫、Web 服务和机器学习的理解会连成一片这在找实习或者后续深造时都是很有说服力的项目经历。如果时间允许最好把爬虫脚本、清洗脚本、模型训练脚本分别做成独立可复用的命令行工具以后哪怕是换一个领域的数据也只需要替换解析和特征工程部分就能快速复用到新项目上。

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

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

免费获取报价 →
↑