资讯动态

机器学习房价预测实战:高德API与MongoDB及sklearn建模

发布时间:2026/10/9 6:28:33 来源:尧图企业网站定制
简介资源包为一套基于机器学习进行房价和二手房价格预测的完整大作业方案针对高校人工智能、数据科学相关课程的学生及初学者可用于课程设计、毕业设计或参赛参考。内容涵盖数据清洗与预处理、特征选择、模型训练评估及预测可视化等完整流程配套项目文档与脚本可直接参考或复现。压缩包内共24个文件包括14张用于展示数据分布与模型效果的PNG图片、5个Python脚本以及Word文档和Markdown说明等整体约1.29MB结构清晰便于快速定位所需模块。目前已有952人学习下载。Python脚本覆盖数据获取、加载、模型训练与测试等关键环节README提供详细使用说明文档则梳理了项目整体实现思路多张图片直观呈现预测结果方便读者理解并在此基础上扩展改进。1. 机器学习房价预测这个压缩包能替你省下什么期末周被人工智能大作业卡住的人看到“房价预测”四个字应该都会点进来。这份资源不是那种只给一个 Jupyter Notebook 的半成品而是一个把取数、存储、建模、评估串成完整链路的机器学习房价预测项目用高德 API 抓真实二手房/小区数据存在 MongoDB 里再通过 sklearn 的线性回归、决策树、SVR 做价格预测。它能解决的最直接问题是你不用满世界找房价数据集也不用从零去调高德 API、MongoDB 和模型参数。对正在赶人工智能大作业的初学者照着脚本改特征就能交差对想入门机器学习的人这份代码本身就是一条“数据采集到模型评估”的活教材。我拿到这个包后也不是一次跑通的中间踩了好几个坑下面把文件结构、运行顺序和避坑记录都拉出来讲一遍。2. 文件拆解与运行顺序先摸清数据链路再动手2.1 压缩包里都有什么拿到 zip 后我习惯先展开看一遍文件名而不是直接跑脚本。这个包里的文件分三类文档、取数脚本、训练脚本。先放个清单方便你对号入座。文件/目录我理解的作用housepriceforecasts 期末项目.docx项目说明文档包含背景、算法解释和总结README.md运行说明第一步应该看它test_gaode_api.py测试高德 API 连通性和 Key 是否有效get_data_to_mongo.py调高德 API 抓数据清洗后写入 MongoDBload_data_and_train.py从 MongoDB 读数据做特征工程并训练模型test_sklearn_1.py / test_sklearn_2.py两个 sklearn 试验脚本用于对比模型demo.jpg 和多张编号图片运行结果截图和可视化截图LICENSE开源许可说明使用边界666.zip额外的打包文件先不动它为什么值得先看这份清单因为很多下载资源里夹着大量无关文件不摸清结构就直接跑很容易把“配置测试脚本”当成“正式脚本”。比如 test_gaode_api.py 是探针get_data_to_mongo.py 是正式取数两者任务完全不同。先用表格理清职责后面遇到报错时能快速定位是哪个环节的锅。这份资源的数据链路从文件命名就能还原高德 API 取 POI 数据 → 写入 MongoDB → load_data_and_train.py 读取并训练。MongoDB 在这里承担了“数据落地”的角色比直接存 CSV 更适合 POI 这种半结构化 JSON 数据字段分布不均匀同一小区记录可能缺地址、缺价格MongoDB 对稀疏字段包容性更强。后期按小区增量更新数据也顺手不用每次全量重跑。2.2 正确的运行顺序测试脚本优先级最高一个常见的翻车点是不看 README先跑 get_data_to_mongo.py然后发现 Key 过期或者 MongoDB 没启动白白浪费时间。我拿到包以后会按这个顺序跑# 1. 先看说明文档 less README.md # 2. 测试高德 API 连通性 python test_gaode_api.py # 3. 抓数据入库 python get_data_to_mongo.py # 4. 从 MongoDB 读数据并训练 python load_data_and_train.py把 test_gaode_api.py 放在最前面是因为房价预测的数据源一旦断了后面所有脚本都是空转。这个文件虽然挂了 test 前缀但从命名看就是作者留下的环境探针跑通它等于确认三件事Python 环境正常、高德 Key 有效、网络能访问高德接口。跑之前用pip list检查依赖至少要有 requests、pymongo、pandas、sklearn缺什么补什么。提示如果 MongoDB 没启动get_data_to_mongo.py 会直接抛 ConnectionFailure。这是这个项目里最常见的启动问题后面避坑章节专门讲。整个链路各环节解耦取数脚本挂了不影响你单独调试训练脚本想换数据源也只需要替换 get_data_to_mongo.py 的输出训练端不用大改。这种拆分方式对一个期末项目来说足够清晰也是答辩时可以说出口的“工程性”亮点。2.3 把项目改成自己的Key、城市、特征三步替换资源能跑通只是第一步交大作业时必须变成“你自己的实验”。我见过太多直接把原 Key 暴露在代码里交上去的案例这既不安全也不像自主完成。最简单的改造分三步第一步去高德开放平台申请自己的 Key替换 test_gaode_api.py 和 get_data_to_mongo.py 里的 API_KEY。第二步把 city 参数从示例城市改成你所在的城市同时注意 load_data_and_train.py 里如果硬编码了市中心经纬度也要同步改。第三步根据你实际拿到的数据字段增加或删减特征列。比如高德 POI 里可能包含商圈、交通枢纽等信息你可以用“到最近地铁站距离”作为新特征这比直接丢经纬度更贴近房价逻辑。这三步做完运行的还是同一套代码骨架但结果变成基于你自己的数据答辩时能讲清楚每一步为什么改。这也是这份资源作为“项目源码”最有价值的地方它提供的是流程不是答案。3. 高德API取数与MongoDB存储把数据变成能训练的样子3.1 高德 API 参数怎么配这个项目的数据源很明显是高德 POI 搜索。高德 Web 服务 API 里最常用的是“关键词搜索”接口。房价预测场景下一般搜“小区”“住宅”这类 POI再用 city 参数限制范围。下面是我常用的写法和 test_gaode_api.py 应该是同一个套路import requests API_KEY 你的高德Key url https://restapi.amap.com/v3/place/text params { key: API_KEY, city: 北京市, keywords: 小区, types: 120400, # 房地产 POI 类目 offset: 25, page: 1, extensions: all } resp requests.get(url, paramsparams).json() print(resp.get(count), resp.get(pois, [])[:1])这段代码里key 是你从高德开放平台申请的密钥city 可以写成“010”这类 citycodekeywords 决定搜索内容types 可以过滤 POI 类别offset 是每页条数page 是页码。extensionsall会返回更详细的字段包括地址、经纬度、类型如果只是基础验证用extensionsbase更快。第一次跑我建议把原始返回完整打印出来看结构而不是直接翻页这样能快速确认字段名到底叫什么。跑通单页后把函数包成fetch_poi(keywords, city, page)然后循环翻页。高德 POI 搜索对每页条数有上限旧接口通常最多 25 条所以需要按页拉取all_pois [] page 1 while True: params[page] page data requests.get(url, paramsparams).json() pois data.get(pois, []) if not pois: break all_pois.extend(pois) page 1 if len(pois) params[offset]: break print(总共抓取, len(all_pois), 条POI)这个循环的逻辑是先请求第 1 页如果当前页 pois 是空数组说明已经翻越了接口能返回的最大页数直接退出如果本页条数小于 offset说明这是最后一页。要注意接口的 count 字段显示匹配总数却不代表能全部翻完所以循环里不要写while page math.ceil(count / offset)否则最后几页可能一直返回空。另外高德对 QPS 有配额抓几千条时每次请求之间最好sleep 0.1不然容易触发限流。3.2 清洗 POI 字段并写入 MongoDB高德返回的字段里location是“经度,纬度”拼在一个字符串里price这类字段可能缺失。如果直接把整个文档丢进 MongoDB 也不是不行但后续 pandas 读取会很别扭嵌套 dict 让df[price]取不到。我一般会先把 POI 拍平转成一行一条的平铺字段。import re def extract_price(raw): if not raw: return None m re.search(r\d, str(raw)) return float(m.group()) if m else None def parse_poi(poi): loc poi.get(location, , ) lng, lat loc.split(,, 1) return { name: poi.get(name), lng: float(lng), lat: float(lat), city: poi.get(cityname), district: poi.get(adname), address: poi.get(address), type: poi.get(type), price: extract_price(poi.get(price)) }extract_price用正则从“均价 50000 元/每平”这种文本里抽取数字避免 price 字段变成字符串。parse_poi把 location 按逗号拆成经纬度去掉 MongoDB 不喜欢的嵌套结构。这个步骤看着繁琐却是后面能顺利做特征工程的必要条件。如果跳过清洗load_data_and_train.py 里处理缺失值和类型转换的代码会越写越长。写入 MongoDB注意用去重逻辑from pymongo import MongoClient client MongoClient(mongodb://localhost:27017/) db client[houseprice] col db[poi_records] for poi in parsed_list: filter_doc {name: poi[name], lng: poi[lng], lat: poi[lat]} col.update_one(filter_doc, {$set: poi}, upsertTrue)这里刻意用了update_one加upsertTrue而不是insert_one。原因是同一小区可能被多个关键词命中脚本也可能被重复执行按“名称经纬度”作为唯一键去重可以避免生成大量重复文档。Python 的 MongoDB 驱动里没有insert_many的 upsert 选项所以用循环逐条更新几千条数据时速度可接受。3.3 MongoDB 集合命名和后续读取约定建议把集合名固定为poi_records后面 load_data_and_train.py 读取时也用它。如果压缩包里 get_data_to_mongo.py 用的集合名不一样改一下读取脚本里的collection_name即可。MongoDB 不用提前建表第一次插入时自动创建集合。几千条到几万条的数据规模查询性能完全没问题如果抓了几十万条记得给name、lng建联合索引不然按名称去重时会很慢。这里也解释一下“为什么选 MongoDB 而不是 CSV”POI 数据是半结构化的每条记录字段不统一用 MongoDB 存 JSON 最省事后续增量更新只需要重跑取数脚本upsert 会自动合并新数据。对期末项目来说能在答辩里讲出“我用 MongoDB 做数据落地不是为了花哨而是为了去重和增量更新”本身就是加分项。如果你只是本地跑着玩CSV 也可以但这份资源既然带了 get_data_to_mongo.py就说明作者想把整条链路跑通不要轻易把它降级成 CSV 方案。4. 特征工程与sklearn建模从DataFrame到RMSE那几步4.1 从 MongoDB 读数据转成 DataFrame训练脚本 load_data_and_train.py 的第一步很明确把刚才存进 MongoDB 的 POI 记录读出来转成 pandas 的 DataFrame。常见写法import pandas as pd from pymongo import MongoClient client MongoClient(mongodb://localhost:27017/) db client[houseprice] col db[poi_records] records list(col.find({}, {_id: 0})) df pd.DataFrame(records) df df.drop_duplicates(subset[name, lng, lat]) print(df.shape)find({}, {_id: 0})的意思是返回全量文档但不包含 MongoDB 自动生成的_id字段。为什么排除_id因为它和房价完全无关如果混进特征矩阵线性回归会把它的数值当成某种模式学进去迁移到新数据时完全失效。drop_duplicates是上一章 upsert 之外的二次防线因为手动改过 MongoDB 数据后可能留下重复记录。读出来之后先看每列的数据类型和缺失率再决定清洗策略。价格列如果有中文文本要用pd.to_numeric(errorscoerce)转成数值转换不了的值会变成 NaN后续用dropna处理。df[price] pd.to_numeric(df[price], errorscoerce) df df.dropna(subset[price])这一步是整个数据清洗里最关键的取舍缺失价格的样本没有训练目标只能丢掉。如果价格字段大量缺失就要回头检查抓取脚本是不是少传了extensionsall因为基础返回里不包含扩展字段。4.2 特征选择相关性分析和 PCA 怎么用摘要里提到“特征选择与提取可能包括相关性分析、主成分分析PCA”。手把手做这个项目时我的建议是先做相关性分析再做 PCA 尝试但不要盲目压缩特征。先看热力图import matplotlib.pyplot as plt import seaborn as sns feature_cols [lng, lat, price] if area in df.columns: feature_cols.append(area) if bedrooms in df.columns: feature_cols.append(bedrooms) corr df[feature_cols].corr() sns.heatmap(corr, annotTrue, fmt.2f) plt.show()相关性热力图能直观看出每个特征和 price 之间的线性相关性。如果 lng、lat 单独看与 price 相关度很小不要急着删因为组合出的“到市中心距离”可能很有价值。我在上一章加了dist_to_center特征就是基于这种组合思路。PCA 的适用场景是有多个强相关特征比如同时存在“距离地铁站”“距离公交站”“距离学校”三列彼此高度共线这时可以用 PCA 降维。对简单的房价预测作业特征数量通常不超过 10 个直接用原始特征或者相关性筛选就够了。PCA 之后特征变成不可解释的主成分答辩时老师问“这个特征代表什么”反而不容易答好。所以我的经验是PCA 可以作为对比实验放进去但主模型尽量用可解释特征。4.3 模型训练与参数选择的实际顺序test_sklearn_1.py 和 test_sklearn_2.py 从命名上看应该是作者在做不同模型对比这也是机器学习大作业的标准动作至少跑一个线性模型、一个非线性模型再加一个更“高级”的模型。下面这段代码把三个模型放到一起from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.tree import DecisionTreeRegressor from sklearn.svm import SVR from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error, mean_absolute_error X df[[lng, lat, dist_to_center]].values y df[price].values X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42) models { linear: LinearRegression(), tree: DecisionTreeRegressor(max_depth6, random_state42), svr: SVR(C20, gammascale), } for name, model in models.items(): if name svr: scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) model.fit(X_train_scaled, y_train) pred model.predict(X_test_scaled) else: model.fit(X_train, y_train) pred model.predict(X_test) rmse mean_squared_error(y_test, pred, squaredFalse) mae mean_absolute_error(y_test, pred) print(f{name}: RMSE{rmse:.2f}, MAE{mae:.2f})这里有几个参数值得单独说明。DecisionTreeRegressor(max_depth6)限制树深是为了防止决策树把训练集记住后面避坑章节展开。SVR(C20, gammascale)里 C 是惩罚系数越大越容易过拟合gammascale会根据特征数量自动缩放比写死 0.1 更稳。SVR 必须用StandardScaler做标准化因为 SVR 的核函数基于样本距离量纲不一致会让 C 和 gamma 的含义完全失效。mean_squared_error(..., squaredFalse)返回的是 RMSE新版本 sklearn 推荐这样写。如果版本较老会报参数不识别改用np.sqrt(mean_squared_error(y_test, pred))。RMSE 和 MAE 是摘要里明确提到的评估指标RMSE 对大误差更敏感MAE 更接近实际误差水平两个都打印方便回答老师“模型误差有多大”。4.4 交叉验证单次划分不够稳用 train_test_split 一次性划分有运气成分。如果 random_state 导致测试集恰好落在低价区模型表现就会虚高或者虚低。期末答辩被追问泛化能力时建议拿出交叉验证from sklearn.model_selection import cross_val_score import numpy as np scores cross_val_score(LinearRegression(), X, y, cv5, scoringneg_mean_squared_error) rmse_scores np.sqrt(-scores) print(五折RMSE均值: %.2f标准差: %.2f % (rmse_scores.mean(), rmse_scores.std()))这里有个容易懵的点sklearn 的scoring约定是越大越好所以neg_mean_squared_error返回的是负的 MSE需要先取负号再开根号得到 RMSE。五折交叉验证把数据切成五份轮流拿一份做测试其余做训练最后看均值和标准差。如果均值比单次划分高很多说明你之前那次的 random_state 选得太“幸运”了如果标准差大说明模型在不同数据子集上不稳定需要再看特征或换模型。5. 避坑与排查五个让房价预测翻车的真实场景5.1 数据链路相关的坑API 与存储坑一高德 API 返回 count 很大但 pois 是空列表现象test_gaode_api.py 打印出 count 有几百甚至几千但 pois 是空数组翻页翻不出数据。原因count 是总命中数但 Web 服务 API 对 POI 搜索有最大可翻页限制当前页码一旦超过最大页接口就会返回空。另一个常见原因是关键词太宽泛命中率高但被 QPS 限流返回错误码。解决先打印单页原始 JSON确认status是否为 1、infocode是否为 10000。如果 status 异常优先检查 Key 和配额剩余量。翻页循环里用“每页条数是否小于 offset”作为退出条件而不是依赖 count。先把 page 改成 1 只请求第一页如果第一页正常而翻页崩多半就是翻页逻辑的问题。另外给每次请求加time.sleep(0.1)触发限流时会好很多。坑二MongoDB 连不上pymongo 抛 ConnectionFailure现象get_data_to_mongo.py 跑完高德请求后在 MongoClient 这一步报错提示 127.0.0.1:27017 拒绝连接。原因本地没启动 mongod 服务或者 MongoDB 根本没安装。pymongo 只能连已经启动的实例不会像 SQLite 那样自动建文件。解决先检查服务状态Ubuntu 用systemctl status mongodmacOS 用brew services listWindows 在服务管理器里看 MongoDB 服务是否启动。临时跑一次就用mongod --dbpath /data/db注意 dbpath 目录要先创建并给权限。启动后再跑 get_data_to_mongo.py通常就通了。Windows 下如果不想每次手动启服务可以用mongod --install注册成系统服务。5.2 模型与数据清洗相关的坑脏数据和模型失控坑三price 字段是文本pandas 读出来是 object现象load_data_and_train.py 里df[price].dtype显示 objectdf[price].corr(df[area])直接报错训练出来的模型预测价格明显偏小。原因高德 POI 的 price 字段可能是“均价 50000 元/平方米”这类文本或者有的记录根本没有价格。pandas 会把带文本的整列当成字符串。解决用正则提取数字再转 float。我常用的写法是import re df[price_num] df[price].astype(str).str.extract(r(\d\.?\d*))[0] df[price_num] pd.to_numeric(df[price_num], errorscoerce) df df.dropna(subset[price_num])执行逻辑先把 price 列强制转成字符串正则\d\.?\d*匹配整数或小数extract取出第一个数字最后 to_numeric 把非数字变成 NaN 并丢弃。处理完后再用df[price_num]做目标变量原来的 price 字段可以留着当原始数据。这个坑不解决后面 RMSE 再低都是假的。坑四SVR 训练结果极差RMSE 比线性回归还大现象LinearRegression 的 RMSE 是 5000SVR 跑出来 RMSE 是 30000甚至预测值几乎都落在同一个数附近。原因SVR 使用径向基核函数对特征尺度极其敏感。lng、lat 是 0-180 量级price 是数万量级如果不做标准化核函数距离计算会被数值大的维度主导SVR 基本学不到有效结构。解决对特征做 StandardScaler必要时对目标值也做缩放。第 4 章的代码里对 X 标准化目标 y 保持原样如果效果还不好试试把 y 也取对数y_log np.log1p(y)训练完用np.expm1(pred)还原。这样能把右偏的价格分布拉正SVR 在高维空间拟合时更容易收敛。坑五决策树训练集 R² 接近 1测试集直接崩现象DecisionTreeRegressor 默认参数下训练集 R² 0.99测试集 R² 不到 0.5明显的过拟合。原因决策树不限制深度时会一直生长到每个叶子只剩一个样本把训练数据完全记住。房价这种数据噪声很多等于把偶然波动都学进去了。解决给决策树设置max_depth限制树深我一般从 6 开始调再设min_samples_leaf10保证每个叶子至少有 10 个样本提高稳定性。这两个参数可以用 GridSearchCV 一起找但期末项目手动试几组就够。别忘了用交叉验证验证参数别只看一次划分。三个模型跑完后把 RMSE 和 MAE 列一张对比表放进实验报告符合大作业“算法解释实验对比”的评分点。5.3 通用排查顺序先环境、再数据、最后模型要是前面五个坑都没命中可以按“环境—数据—模型”的顺序排查。环境层高德 Key 是否有效、MongoDB 是否启动、Python 依赖是否装全。数据层打印df.shape、df.dtypes、df.isna().sum()确认数据量和字段类型符合预期。模型层先用 LinearRegression 跑通 baseline再换非线性模型避免一上来就调 SVR 参数调得满头大汗。print(df.shape) print(df.dtypes) print(df.isna().sum())这三行代码是数据前必看的体检报告。shape 异常比如 0 行说明取数脚本没抓到任何东西dtype 异常说明清洗没做好isna().sum() 告诉你哪些列缺失严重缺失率超过 50% 的直接考虑扔掉。我排查项目时 90% 的问题都出在数据和环境层真正需要调模型参数的反而是少数。6. 模型验证小技巧残差图和学习曲线的用法6.1 残差图看模型假设是否成立交叉验证只能告诉你误差有多大不能告诉你去哪优化。残差图是更直接的诊断工具import matplotlib.pyplot as plt residual y_test - pred plt.scatter(pred, residual, alpha0.5) plt.axhline(0, colorr, linestyle--) plt.xlabel(预测价格) plt.ylabel(残差) plt.show()如果残差随着预测值变大呈扇形扩散说明高价区预测方差大可以考虑对价格取对数如果残差整体偏高或偏低说明模型存在系统性偏差可能是漏了关键特征。这个图打印出来后答辩时能直接指着说“我通过残差图发现模型在高端价格区间有偏差所以把目标值做了 log 变换”。6.2 学习曲线判断加数据还是加特征另一个我必看的图是学习曲线from sklearn.model_selection import learning_curve import numpy as np train_sizes, train_scores, val_scores learning_curve( LinearRegression(), X, y, cv5, train_sizesnp.linspace(0.2, 1.0, 5), scoringneg_mean_squared_error ) train_rmse np.sqrt(-train_scores.mean(axis1)) val_rmse np.sqrt(-val_scores.mean(axis1))如果训练集 RMSE 和验证集 RMSE 之间的差距大且验证集曲线还在下降说明当前是过拟合增加训练数据或正则化更有效如果两条曲线最终都停在较高位置说明欠拟合该加特征或换更复杂的模型。这个判断比单纯看数字更直观也是我每次跑完模型强制走一遍的验证步骤。整套跑下来建议你再看一眼包里的 demo.jpg 和编号图片那就是作者当时跑出来的预测对比和热力图README 和 docx 里有更细的运行说明。压缩包里的 test 脚本和训练脚本足够当骨架把高德 Key 和 MongoDB 服务准备好按第 2 章的顺序跑通再换城市、换特征就是一份站得住的期末项目。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑