新闻详情

新闻详情

首页 / 资讯中心 / 详情

广州二手房价预测:数据清洗、特征工程与模型调参全解析

发布时间:2026/9/28 6:00:59来源:尧图网络
广州二手房价预测:数据清洗、特征工程与模型调参全解析
简介这是一份面向数据分析学习者与房地产研究爱好者的广州市二手房价预测实践资源包含广州市二手房交易数据集和完整的Python建模代码围绕价格预测任务演示了从数据清洗、特征工程到模型训练评估的典型流程。压缩包共19个文件整体仅1.05MB以17张可视化图表为主配以1个Python脚本和1个CSV数据文件图表覆盖价格分布、相关性分析以及区域、朝向、楼层、面积等维度对总价的影响便于对照代码查看中间结果。已有984人学习下载。借助该资源可以掌握Pandas数据清洗与特征处理、Scikit-learn回归模型构建与验证、Matplotlib/Seaborn可视化呈现等关键技能还能参考代码注释和目录组织方式快速迁移到其他城市的房价预测项目。代码与数据配套完整适合入门级数据分析项目练习也可作为课程作业、毕业设计或求职作品集的参考资料。1. 二手房价预测拿到数据和代码之后第一件事不是跑模型在网上下载到一份「广州市二手房价预测——数据python代码.rar」解压之后通常是一份 CSV 和一个或者几个.py文件。很多人的第一反应是直接双击跑代码看到终端里滚出一堆 loss、R² 就觉得成功了——这是最容易翻车的起手式。二手房价预测不是一个「跑通即结束」的脚本任务而是一条从数据清洗、特征工程、模型选型到误差分析完整串起来的链路。这个压缩包的价值不在于那个预测结果数字而在于你能不能把里面的数据字段、代码逻辑拆开改成自己能维护、能解释、能复现的一套流程。这篇文章会沿着这条链路走一遍先讲清楚数据里有哪些坑再讲特征怎么加工最后落到模型评估和调参让你拿到类似的压缩包时不是在那份代码上补补丁而是知道每一步在干什么、为什么这么干。2. 先洗数据广州二手房数据里的缺失、异常与重复2.1 解压后第一件事摸清字段别急着 import拿到 rar 解压后先用 pandas 把数据读进来看一眼列名、行数、内存占用。二手房数据常见的字段包括小区名称、所在区域、板块、户型几室几厅、面积、朝向、楼层、装修情况、建筑年份、挂牌单价、挂牌总价、房源标题、发布时间等。不同爬虫来源的字段名差异很大有些叫price有些叫total_price有些叫unit_price必须先统一。建议先跑一段基础探查代码import pandas as pd df pd.read_csv(guangzhou_second_hand.csv, encodingutf-8) print(df.shape) print(df.info()) print(df.describe(includeall)) # 看每列缺失比例超过30%的列要单独评估 missing_ratio df.isnull().sum() / len(df) print(missing_ratio[missing_ratio 0.3])逻辑说明df.shape确认数据量级几百条和几万条的处理策略完全不同df.info()看每列 dtype如果单价列被读成了 object说明里面有脏字符比如4.5万这种东西missing_ratio是后续所有缺失值处理的依据。参数说明缺失比例阈值 0.3 并不是固定标准如果样本量够大超过 50% 的列可以直接删如果样本只有两三千条30% 缺失的列可能需要插补而不是删除。这个阶段最容易踩的坑是编码问题。二手房数据大多来自网页encodingutf-8可能会报错换gbk或gb18030重试。我一般会先在命令里试df.head()输出乱码说明编码不对。2.2 异常值处理广州房价里的3平米和单价1万二手房数据里异常值比缺失值更隐蔽。缺失值至少能看到 NaN异常值混在正常数据里直接进模型会把整个模型带偏。最典型的几种异常面积异常小比如 1.5 平米实际是车位或杂物房、单价异常低比如挂牌单价才 3000 元/平米正常广州行情不可能、总价和单价矛盾总价 100 万但面积 200 平米单价算出来才 5000明显某个字段错了。处理逻辑用条件筛选加可视化结合import matplotlib.pyplot as plt # 先看面积分布正常住宅集中在30-200平米 print(df[area].describe()) # 明显异常面积小于10平米或大于500平米 anomaly_area df[(df[area] 10) | (df[area] 500)] print(anomaly_area[[area, total_price, unit_price]].head()) # 单价异常广州二手住宅挂牌单价低于1万/平几乎不存在 anomaly_price df[df[unit_price] 10000] print(anomaly_price[[area, total_price, unit_price]].head()) # 可视化分布确认切割点是否合理 plt.hist(df[area].clip(0, 300), bins50) plt.show()逻辑说明分布直方图的价值在于帮你肉眼确认切割点比如面积在 250 平米附近出现断层那 250 作为上限就是合理的不要拍脑袋定一个 1000 平米的上限可能根本筛不掉问题样本。参数说明clip(0, 300)只是为了画图时不被极端值拉伸坐标轴实际过滤条件要单独写。我处理这类异常的原则是先看数量几百条里异常样本有 5 条以内直接删超过 20 条就要怀疑是字段解析问题而不是数据本身问题。2.3 楼层字段低楼层、中楼层、高楼层怎么变成数值广州二手房源信息里楼层字段通常是低楼层/中楼层/高楼层这种文本甚至有地下1层这种特殊值。直接把文本丢给模型是不行的Python 的 sklearn 库不支持中文字符串直接训练。常见做法是映射成有序数值低楼层1、中楼层2、高楼层3、底层0、顶层4。这里要注意的是底层和低楼层不是一回事底层通常指一楼采光、潮湿、隐私都有问题价格规律和低楼层不一样应该单独编码。floor_mapping { 底层: 0, 低楼层: 1, 中楼层: 2, 高楼层: 3, 顶层: 4 } df[floor_code] df[floor].map(floor_mapping) # 处理映射失败的情况如果有NaN说明有未预期文本 print(df[floor_code].isnull().sum()) print(df.loc[df[floor_code].isnull(), floor].value_counts())逻辑说明map是一个字典映射比replace更直观。第二步的排查意义重大只要出现 NaN说明原始数据里有字典外的值比如中楼层/共32层这种带后缀的写法需要先做字符串清洗。参数说明字典的值可以有多种设计如果你觉得顶层和高楼层对房价影响差异不大也可以都归为 3这取决于你对广州楼市的经验判断——顶层在广州夏天暴晒但视野好实际成交价往往低于高楼层所以我习惯单独分出来。朝字段同理南、南北、东南这些朝向在广州非常值钱北向便宜一截。可以用 one-hot 编码也可以用简单的评分规则比如主朝向含南得 1 分否则 0 分后面做特征时再细说。3. 特征工程与模型选型广州二手房能预测到什么程度3.1 区域和板块特征把天河区变成模型能理解的东西广州二手房价值最核心的变量是位置。同样是 80 平米珠江新城和从化能差出三四倍价格。原始数据里的区域字段通常是天河区、海珠区、越秀区、荔湾区、白云区、番禺区、黄埔区、花都区、南沙区、增城区、从化区这些文本。直接换成数字编号比如天河1、海珠2是不对的因为编号大小会被模型当作数值大小天河比海珠大 1没意义。正确处理是 one-hot 编码或者 target encoding。样本量小用 one-hot样本量大超过 3 万条可以试试 target encoding也就是用每个区域的历史平均单价作为特征值# 用区域均值做编码注意用训练集计算防止数据泄露 area_mean_price df.groupby(district)[unit_price].transform(mean) df[district_target_enc] area_mean_price # one-hot 方式 district_dummies pd.get_dummies(df[district], prefixdistrict) df pd.concat([df, district_dummies], axis1)逻辑说明transform(mean)会把每个区域的均价广播回每一行这就意味着模型只需要一个特征就能学到这个区域贵不贵的信息。数据泄露问题非常关键如果你在划分训练集/测试集之前就做了这个变换测试集的信息已经混进训练集了最后评估结果会虚高而且虚高得很隐蔽。参数说明prefixdistrict是给生成的列加前缀避免重名天河区会变成district_天河区这样的列值为 0 或 1。用 target encoding 时我会把均值计算放在交叉验证的每一折内部重新做这虽然麻烦但结果干净。3.2 面积、房龄、装修连续特征直接进模型还是需要加工面积、建筑年份、房间数、厅数这些字段相对干净可以直接进模型但有几个细节。面积和总价之间存在天然的多重共线性如果你同时把面积、单价、总价三个字段都放进线性回归模型参数估计会很不稳定因为单价乘以面积基本等于总价。二选一或者去掉单价只留面积和总价。房龄这个字段很多数据里给的是建筑年份比如 2005 年建成。直接用年份做特征模型的解释是年份越大房价越高这对历史数据成立但未来预测就很尴尬——难道 2050 年的房子最贵吗更合理的做法是转成房龄用当前年份减去建筑年份模型学到的就是房子越老越便宜这个稳定规律。import datetime current_year datetime.datetime.now().year df[house_age] current_year - df[build_year] # 异常处理房龄超过50年或为负数的样本 df df[(df[house_age] 0) (df[house_age] 50)] # 装修情况毛坯、简装、精装、豪华装 映射成有序值 decoration_mapping {毛坯: 0, 简装: 1, 精装: 2, 豪华装: 3} df[decoration_code] df[decoration].map(decoration_mapping).fillna(0)逻辑说明房龄上限设为 50 年是因为广州老城区确实有上世纪七八十年代的房子但超过 50 年的老宅交易量极小样本太少反而干扰模型。装修映射用有序数值是因为豪华装和毛坯之间存在明显的递进关系且装修对房价的影响是单调的。参数说明fillna(0)是把缺失装修信息的样本按毛坯处理这是一种保守做法后续可以在验证集上对比——如果你发现缺失装修的样本误差特别大说明这些样本有信息缺失要不要保留需要单独权衡。3.3 模型选型先跑线性回归做基准再上随机森林新手拿到这类压缩包最容易犯的错是直接上 XGBoost看到训练集 R² 到了 0.95 就发朋友圈。实际上房价预测这种任务线性回归和树模型各有定位。线性回归的可解释性极强你能看到每个特征的系数知道面积每增加 1 平米总价大约增加多少钱这对二手房买卖双方都有参考价值。随机森林、XGBoost 这类树模型则能捕捉非线性关系比如面积 60 平米以下每增加一平米涨 2 万但 120 平米以上每增加一平米只涨 1.5 万这种拐点。我的习惯是先跑一个线性回归当基准看 R² 和 MAE 是多少再跑随机森林对比from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, r2_score feature_cols [area, house_age, bedroom, living_room, floor_code, decoration_code, district_target_enc] X df[feature_cols].values y df[total_price].values X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) lr LinearRegression() lr.fit(X_train, y_train) y_pred_lr lr.predict(X_test) print(LinearRegression MAE:, mean_absolute_error(y_test, y_pred_lr)) print(LinearRegression R2:, r2_score(y_test, y_pred_lr)) rf RandomForestRegressor(n_estimators200, max_depth10, random_state42) rf.fit(X_train, y_train) y_pred_rf rf.predict(X_test) print(RandomForest MAE:, mean_absolute_error(y_test, y_pred_rf)) print(RandomForest R2:, r2_score(y_test, y_pred_rf))逻辑说明train_test_split默认是随机抽样但对房价数据我建议设置shuffleFalse按时间排序后切分因为房价有随时间上涨的趋势用过去的预测未来才是真实场景随机抽样的测试集里包含了未来的数据评估结果会偏乐观。参数说明random_state42固定随机种子保证可复现随机森林的max_depth10是防止过拟合的第一道防线n_estimators200是树的数量超过这个量级收益递减训练时间却线性增长。如果线性回归 MAE 是 30 万随机森林 MAE 是 20 万说明数据里非线性关系明显值得继续调树模型如果两者差不多那线性回归的可解释性更值钱。3.4 数据划分的逻辑预测未来不是考古继续展开时间切分的细节。二手房价预测的落地场景是用 2023 年之前的数据训练预测 2023 年下半年的挂牌价。如果你随便随机抽样训练集和测试集混着不同时期的样本模型可能学到的是2023 年上半年比下半年便宜这种时间趋势这个趋势在真实预测时不见得成立。正确做法是# 假设有 listing_date 字段按时间排序后切分 df df.sort_values(listing_date).reset_index(dropTrue) split_idx int(len(df) * 0.8) train_df df.iloc[:split_idx] test_df df.iloc[split_idx:] X_train train_df[feature_cols].values y_train train_df[total_price].values X_test test_df[feature_cols].values y_test test_df[total_price].values时间切分的代价是如果数据量少可能出现测试集里某个区域的样本太少评估结果波动大。折中方案是保证训练集覆盖所有区域测试集里剔除那些在训练集中几乎没有样本的冷门板块。这里没有完美解法只有根据数据量做的权衡。4. 广州房价预测最常见的5个翻车点现象、原因、解决4.1 训练集R²高达0.98测试集R²只有0.3现象模型在训练集上表现接近完美特征重要性也很合理但一换测试集就崩。原因这是典型的数据泄露。最常见的是 target encoding 在全量数据上计算均值或者在特征工程时用了包含测试集信息的统计量比如全量数据的区域均价。另一个隐蔽来源是特征里包含了挂牌总价而爬虫数据里总价和单价是同一个来源本质上等于把答案告诉了模型。解决严格用训练集内部计算统计量交叉验证时每一折都重新做编码检查特征列表删除与目标变量线性相关的字段。我会在代码里写一个断言assert total_price not in feature_cols养成习惯。4.2 天河区样本预测误差巨大其他区正常现象模型整体 MAE 还能看但误差按区域分组后天河区偏差特别大。原因广州各区域房价方差悬殊。天河区既有珠江新城 15 万一平的豪宅也有东圃 4 万一平的刚需盘同一个区域内价格极差能到 3 倍。模型为了整体误差最小会倾向于把预测值压在分布中间导致高价位区域系统性低估、低价位区域系统性高估。解决分组评估误差不要只看整体指标df_test test_df.copy() df_test[pred] y_pred_rf df_test[error] df_test[pred] - df_test[total_price] grouped_error df_test.groupby(district)[error].apply( lambda x: (abs(x) / (x df_test[total_price])).mean() ) print(grouped_error)如果天河区确实误差最大可以做两件事第一单独为豪宅/非豪宅建模型用面积或单价分桶第二对目标变量做对数变换让高价位样本的误差权重不再那么极端。对数变换后预测值要np.expm1()还原代价是解释性变差。4.3 房源更新时间字段导致重复数据删不掉现象清洗完剩 3 万条但同一个小区的同户型、同面积、同样装修出现了 5 条总价微妙不同。原因挂牌房源每天会重新上架爬虫如果按抓取日期去重保存的是每次快照。这不是标准意义上的重复而是真实市场的挂牌记录但直接进模型会让这个小区在训练集里被过度代表。解决按小区名称加面积加户型的组合去重保留总价中位数或最后一条挂牌记录。参数上要控制面积允许误差范围比如面积字段保留 1 位小数先四舍五入再拼接去重键。如果同一房源在不同时间总价变化很大说明业主在试探市场这种记录保留最后一条更有现实意义。4.4 预测结果出现几百万的负偏差但看特征都在正常范围现象某条预测总价 200 万实际房源挂牌 500 万且所有特征面积、区、装修都是常见范围内。原因大概率是少了重要特征。广州二手房市场里学位、地铁距离、小区物业质量对房价影响非常大但这些字段爬虫经常抓不到或者存在近地铁学区房这类文本描述里没有被解析出来。模型没学过这些特征遇到这类房源只能按平均偏好预测。解决能补数据就补不能补就在结论里明确标识误差范围。我会在最终预测表里加一列confidence当预测值落在该区域均价附近时标记为高置信度偏差超过区域价差一半时标记为低置信度。这比硬调模型参数有用得多。4.5 脚本跑完输出一片红sklearn 库版本不兼容带来的崩溃现象本地明明能跑的代码换个环境就报AttributeError: GridSearchCV object has no attribute best_params_或者ImportError: cannot import name plot_tree。原因sklearn 版本变化导致 API 调整比如plot_tree从 0.21 开始才可用n_jobs参数行为在不同版本里有差异。压缩包里的代码如果是两三年前写的在新环境大概率跑不了。解决先看代码头部有没有sklearn.__version__打印。没有的话手动建立一个虚拟环境并安装依赖时不要直接装最新版。二手房预测这个任务不需要追新conda create -n house_price python3.8 conda activate house_price pip install pandas1.5.3 numpy1.24.3 scikit-learn1.2.2 matplotlib3.7.1 jupyter notebook版本组合不是固定的但要保证 pandas 和 sklearn 之间没有高版本 API 断裂。装完先python -c import sklearn; print(sklearn.__version__)确认。这种环境问题占整个项目排障时间的 30%不值得花时间研究新版特性。5. 从基准模型到可用的预测网格搜索与误差分布验证基准模型跑通之后提升预测精度主要靠两条线模型调参和误差结构分析。随机森林最值得调的是n_estimators、max_depth、min_samples_leaf。min_samples_leaf这个参数常常被忽略但它对防止过拟合非常关键——它控制每个叶子节点最少要多少个样本调大之后模型会更平滑不容易被极端样本带偏。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [100, 200], max_depth: [8, 10, 12], min_samples_leaf: [3, 5, 10] } rf_tuned RandomForestRegressor(random_state42) grid GridSearchCV( rf_tuned, param_grid, cv5, scoringneg_mean_absolute_error, n_jobs-1 ) grid.fit(X_train, y_train) print(grid.best_params_) print(-grid.best_score_)逻辑说明scoringneg_mean_absolute_error表示用负的 MAE 作为评估分数sklearn 里GridSearchCV遵循分数越大越好的约定而 MAE 是越小越好所以取负。cv5是五折交叉验证每一折用 4/5 数据训练、1/5 验证五个结果取平均这个平均 MAE 比单次划分的结果可信得多。参数说明n_jobs-1表示用满所有 CPU 核心如果数据量有 5 万条n_estimators200配合 12 个深度单次搜索可能要跑十分钟要有耐心。网格搜索不是终点。我会再看预测残差的分布直接画图import matplotlib.pyplot as plt residual y_test - grid.best_estimator_.predict(X_test) plt.scatter(y_test, residual, alpha0.4) plt.axhline(y0, colorred, linestyle--) plt.xlabel(Actual Price (10k CNY)) plt.ylabel(Residual) plt.show()这张图的读法很简单如果残差在零轴上下随机散布说明模型已经学到了数据里的主要规律如果呈现出喇叭形实际房价越高残差波动越大说明高价房的预测不确定性天然大于低价房这不是调参能解决的是数据里高价房样本太少导致的。明白了这一点你在向别人解释预测结果时就有了底气不是模型烂而是不确定性分布不均匀。另一个常用技巧是分位数回归专门预测区间而不是单点。用RandomForestRegressor的每个决策树的预测结果做分位数统计比直接调参更能回答这套房子挂牌价大概率落在哪个范围。我对接实际需求的时候买方问的最多的不是这套房多少钱而是多少价位能看到这个面积段的房子后者本质上就是条件分位数。最后的习惯是每次跑完实验把特征重要性、模型参数、分区误差一起导出成一个 CSV 存档。三个月后回头翻代码时你会感谢当时的自己留了这份记录——否则你连当初为什么选max_depth10而不是 12 都回想不起来。这是我在做了十几个类似房价预测项目之后养成的习惯希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

模型优化器实战:量化、剪枝与蒸馏的选型与调参指南 2026/9/28 6:58:39

模型优化器实战:量化、剪枝与蒸馏的选型与调参指南

1. 模型优化器到底在优化什么第一次看到 Model-Optimizer 这个词,很多人会下意识地把它和“训练加速”“显存压缩”画等号。实际上,它涵盖的范围比想象中要宽得多。简单说,Model-Optimizer 是一套围绕模型全生命周期做“减负”和“提速”的工…

阅读更多 →
从缓存到微服务:架构演进的两级跳与实战指南 2026/9/28 6:58:39

从缓存到微服务:架构演进的两级跳与实战指南

1. 为什么"缓存到微服务"这条路线几乎是所有系统的必经之路之前有朋友问我,说他在一家传统公司做后端开发,系统跑了好几年,单体架构,几百万行代码,最近领导让他牵头做架构升级,问我是该先上缓存还…

阅读更多 →
ForgeCode 动态系统上下文渲染机制:变量注入与逐轮重渲染实现解析 2026/9/28 6:58:33

ForgeCode 动态系统上下文渲染机制:变量注入与逐轮重渲染实现解析

人工智能AI Agent代码智能体AI 应用CLI开发工具 【免费下载链接】forgecode AI enabled pair programmer for Claude, GPT, O Series, Grok, Deepseek, Gemini and 300 models 项目地址: https://gitcode.com/gh_mirrors/forge39/forgecode 点击查看 免费下载 导读…

阅读更多 →
贺州建设网站速查手册:被黑挂马急救与防坑指南 2026/9/28 6:58:33

贺州建设网站速查手册:被黑挂马急救与防坑指南

贺州建设网站速查手册:被黑挂马急救与防坑指南 网站突然打开变成色情广告或赌博链接,后台密码怎么改都没用?别慌,这通常是典型的被黑挂马现象。很多贺州本地企业在做网站建设时,为了省那点开发费,忽略了基础安全配置,结果网站上线没半个月就中招。这份…

阅读更多 →
前置放大器噪声设计核心:电荷与电流灵敏架构选型指南 2026/9/28 6:58:26

前置放大器噪声设计核心:电荷与电流灵敏架构选型指南

1. 为什么前置放大器的“第一级”噪声决定一切:从探测器源头讲起你手里的那个硅漂移探测器(SDD)或者PIN光电二极管,输出的信号到底有多微弱?不是毫伏,不是微伏——是皮安(pA)级的电流…

阅读更多 →
继电器抖动本质与硬件软件协同消抖实战 2026/9/28 6:58:26

继电器抖动本质与硬件软件协同消抖实战

1. 项目概述:为什么继电器开关会“手抖”,又该怎么治?继电器开关抖动现象分析与优化策略——这标题里藏着的不是故障,而是硬件工程师每天都在和它掰手腕的“老朋友”。我干这行十一年,从GD32H7的ADC硬件滤波调试到STM3…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉