资讯动态

广州二手房房价预测:Python数据清洗到模型解释全流程

发布时间:2026/9/11 23:41:41 来源:尧图企业网站定制
简介面向房地产数据分析初学者与价格预测爱好者这份广州市二手房价预测资源将原始数据、Python建模代码和结果可视化整合在一起便于快速理解房价回归分析全流程。压缩包共19个文件包含1个CSV数据集、1个Python脚本和17张PNG图表CSV提供原始房价相关数据脚本覆盖预处理、特征选择、模型训练与评估图表直观展示区域、朝向、楼层、面积、装修、建成时间与总价的关系。资源整体仅1.05MB已有984人学习使用。从代码和图中可看到Pandas清洗、Scikit-learn建模、Matplotlib/Seaborn绘图的具体实践项目涵盖缺失值处理、特征相关性分析、回归模型对比、交叉验证及MSE/R²等指标评估也包含对总价取对数、多维度交叉分析等细节对希望提升数据分析与机器学习落地能力或在二手房场景中开展预测训练的学习者这是一份内容紧凑、可直接对照运行的完整样例。1. 二手房价预测这件事数据比模型更值钱看到“广州市二手房价预测——数据python代码.rar”这个压缩包名字大多数人的第一反应是“又一份网盘里吃灰的资料”。但真正做过房价预测项目的人会知道这个标题其实戳中了两个要害第一广州二手房市场是典型的“强区位驱动”市场同一条马路两侧的单价能差出一倍没有精细到小区和楼龄的数据任何模型都是空中楼阁第二Python 代码的价值不在于调包而在于把“数据清洗—特征工程—模型对比—误差分析”这条链路走通让预测结果能解释、可验证。这篇文章不评价那份压缩包里的具体内容而是基于“广州市二手房数据 Python 代码”这个组合把一套可复现的房价预测方案讲透。适合三类人准备做毕业设计或课程项目的学生想用公开数据练手的数据分析初学者以及想评估广州特定板块房价水平的从业者。需要说明的是这里的方案不依赖任何私有数据源使用公开的链家、贝壳历史挂牌记录即可复现核心是讲清楚“为什么这样做”和“代码参数该怎么设”。2. 数据获取与预处理先解决“脏数据”再谈模型精度2.1 公开房源数据的字段构成和采集方式二手房挂牌数据的典型字段包括小区名称、所在城区、板块、户型室厅卫、建筑面积、朝向、装修情况、电梯有无、楼龄、总价、单价、挂牌时间。其中“单价 总价 / 面积”这个派生字段在原始数据里往往直接给出但建议自己重新计算一次因为原始数据里偶尔会出现总价和面积对不上的情况。采集方式上不建议直接爬取链家或贝壳的实时页面反爬策略复杂且容易触发封禁。更稳妥的思路是使用 GitHub 上定期更新的历史数据集或者使用第三方数据平台的导出功能。如果决定自己爬需要控制请求频率并在代码中设置 User-Agent 和延时。import pandas as pd import numpy as np # 假设已经从 CSV 文件读取原始数据 df pd.read_csv(guangzhou_house.csv, encodingutf-8-sig) # 检查缺失值情况 print(缺失值统计) print(df.isnull().sum()) # 去掉关键字段为空的记录 df df.dropna(subset[total_price, area, district]) # 重新计算单价避免原始数据错误 df[unit_price] df[total_price] * 10000 / df[area]提示总价单位通常是“万元”面积单位是“平方米”算出的单价单位是“元/平方米”。这一步一定要自己重算而不是直接信任原字段。2.2 异常值处理广州房价数据的“合理区间”如何划定广州二手房的真实成交单价区间2024 年前后大致在 1.5 万到 10 万/平方米之间。但挂牌数据里会出现两种极端情况一是车位、商铺混入住宅数据单价低至几千元二是别墅或豪宅的单价和总价远超普通住宅。处理策略不能只看单价要结合面积和总价做交叉过滤。# 过滤异常单价广州住宅合理区间 df df[(df[unit_price] 15000) (df[unit_price] 100000)] # 面积过滤住宅面积通常 20-300 平方米 df df[(df[area] 20) (df[area] 300)] # 总价过滤避免车位混入 df df[df[total_price] 50] print(f过滤后剩余样本量: {len(df)})这里的阈值设定有讲究。单价下限 1.5 万是广州外围区域如从化、增城部分板块的真实水平低于这个数大概率是车位或工业产权上限 10 万覆盖珠江新城核心区的高端住宅超过这个数多半是录入错误或者是独栋别墅。如果是做学术研究可以把别墅单独建模而不是硬塞进普通住宅模型里。2.3 特征工程把“地段”量化成模型能吃的数字房价预测里最重要的特征是区位但“天河区”“越秀区”这种字符串不能直接喂给模型。常见做法是把行政区映射为数值标签但更好的方式是引入“到市中心距离”或“到地铁站步行时间”这类连续变量。如果原始数据没有这些字段可以从小区名称反查经纬度后计算。# 行政区映射为类别编码 district_map { 天河: 0, 越秀: 1, 海珠: 2, 荔湾: 3, 白云: 4, 番禺: 5, 黄埔: 6, 花都: 7, 南沙: 8, 增城: 9, 从化: 10 } df[district_code] df[district].map(district_map) # 楼龄计算 df[house_age] 2025 - df[build_year] # 户型字段拆分成室、厅数量 df[[bedrooms, hall]] df[layout].str.extract(r(\d)室(\d)厅).astype(float) # 是否电梯房 df[has_elevator] df[elevator].apply(lambda x: 1 if x 有 else 0)提示楼龄对房价的影响是非线性的5 年以内的次新房和 20 年以上的老破小单价差异巨大。如果有精力可以对楼龄做分段处理小于 5 年、5-10 年、10-20 年、20 年以上而不是直接用连续数值。3. 模型选择与 Python 代码实现为什么先用线性回归打底3.1 房价预测的模型选型逻辑房价预测常见的模型有三类线性回归包含岭回归、Lasso、树模型随机森林、XGBoost、LightGBM、神经网络。先说结论如果数据集在几千条的量级优先用 LightGBM 和随机森林如果只有几百条线性回归加正则化反而更稳。原因很直接树模型能自动捕捉非线性关系和特征交互比如“天河区 楼龄小于 5 年”这种组合效应线性模型需要手动构造交叉特征才能表达。但树模型在样本量不足时容易过拟合而且调参复杂度高。作为项目演示先用线性回归建立基线再用树模型提升精度是最合理的路径。from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score # 选特征列 feature_cols [district_code, area, bedrooms, hall, house_age, has_elevator, total_price] X df[feature_cols].drop(total_price, axis1) y df[total_price] # 划分训练集和测试集 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.predict(X_test) print(fMAE: {mean_absolute_error(y_test, y_pred):.2f} 万元) print(fRMSE: {mean_squared_error(y_test, y_pred, squaredFalse):.2f} 万元) print(fR2: {r2_score(y_test, y_pred):.4f})提示total_price 单位是万元MAE 输出如果是个位数说明平均误差在几万块对二手房这种总价几百万的标的来说可以接受。3.2 特征重要性分析找出影响广州房价的隐藏变量线性回归的系数能直接反映特征的影响方向和幅度但树模型更擅长给出特征重要性排序。如果只做一种分析建议用随机森林的重要性输出配合 SHAP 值解释具体预测结果。from sklearn.ensemble import RandomForestRegressor rf RandomForestRegressor( n_estimators300, max_depth15, min_samples_leaf3, random_state42, n_jobs-1 ) rf.fit(X_train, y_train) # 特征重要性排序 importance pd.DataFrame({ feature: X.columns, importance: rf.feature_importances_ }).sort_values(importance, ascendingFalse) print(importance)参数说明n_estimators 设为 300 是精度和速度的折中低于 100 时偏差偏大超过 500 收益递减max_depth 限制为 15 防止过拟合因为特征数量不多深度太大没有实际意义min_samples_leaf 设为 3 让叶子节点至少包含 3 个样本减少极端预测。运行后大概率看到面积和 district_code 排在前两位这两个特征对房价方差的解释力通常在 60% 以上。3.3 树模型参数调优网格搜索的三个必调参数随机森林的默认参数对房价预测这类中等规模回归任务通常不是最优的。三个必调参数是 n_estimators、max_features 和 min_samples_split。max_features 默认是“auto”即特征总数的平方根但在特征少于 10 个时建议直接设为 1.0 让每棵树都用全部特征反而减少随机性带来的方差。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [200, 300, 500], max_depth: [10, 15, 20], min_samples_split: [2, 5, 10] } grid_search GridSearchCV( RandomForestRegressor(random_state42, n_jobs-1), param_grid, cv5, scoringneg_mean_absolute_error, verbose1 ) grid_search.fit(X_train, y_train) print(f最优参数: {grid_search.best_params_}) print(f最优 MAE: {-grid_search.best_score_:.2f} 万元)注意GridSearchCV 的 scoring 参数我用的是 neg_mean_absolute_error 而不是默认的 R2。房价预测场景中 MAE 更贴近业务理解——你就知道“平均下来预测差 8 万”这比 R20.85 这种指标直观得多。cv5 指的是 5 折交叉验证目的是避免单次划分的运气成分。4. 训练、验证与误差分析预测准不准要看误差分布在哪里4.1 训练集和测试集怎么切才符合业务场景房价预测的数据切分有两种思路随机切分和按时间切分。随机切分假设所有样本独立同分布适合课程项目按时间切分则模拟真实场景——用历史数据训练预测未来挂牌价。实际业务中我推荐按时间切分因为二手房市场的价格走势有明显的阶段性和周期性。# 按挂牌时间排序后切分 df df.sort_values(listing_date) split_idx int(len(df) * 0.8) train_data df.iloc[:split_idx] test_data df.iloc[split_idx:] # 重新整理特征和标签 X_train train_data[feature_cols].drop(total_price, axis1) y_train train_data[total_price] X_test test_data[feature_cols].drop(total_price, axis1) y_test test_data[total_price]提示如果原始数据里的 listing_date 字段格式不统一需要先用 pd.to_datetime 统一转换。按时间切分的好处是保证测试集的时间晚于训练集避免“未来数据泄漏”到训练过程这是房价预测项目里最容易犯的隐蔽错误。4.2 残差分析哪些房子预测偏差最大模型评估指标只能给一个平均概念真正找到问题要靠残差分析。把测试集每套房子的真实价格和预测价格相减然后按区域、面积段、楼龄分组看残差的分布特征。# 计算残差 test_data test_data.copy() test_data[pred_price] rf.predict(X_test) test_data[residual] test_data[total_price] - test_data[pred_price] # 按区域看平均残差 district_residual test_data.groupby(district)[residual].agg([mean, count]) print(district_residual.sort_values(mean)) # 按面积段看误差 test_data[area_bin] pd.cut(test_data[area], bins[0, 60, 90, 120, 200, 500]) area_residual test_data.groupby(area_bin, observedFalse)[residual].agg([mean, count]) print(area_residual)这里有个规律残差均值绝对值最大的区域往往是学位房溢价最明显的板块比如越秀区的老旧小户型。原因在于挂牌价里包含了大量模型看不到的信息——学区政策、业主心理预期、小区物业管理质量。这些信息在结构化数据里缺失表现为系统性低估或高估。4.3 模型对比和 XGBoost、LightGBM 的差距有多大随机森林是稳健的基线但 Gradient Boosting 系列模型在表格数据上通常表现更好。LightGBM 对房价这种连续值回归任务的优势在于直方图算法能处理特征的分布偏移而且训练速度比 XGBoost 快 3 到 5 倍。import lightgbm as lgb lgb_model lgb.LGBMRegressor( n_estimators1000, learning_rate0.05, num_leaves31, max_depth7, subsample0.8, colsample_bytree0.8, random_state42, verbose-1 ) lgb_model.fit( X_train, y_train, eval_set[(X_test, y_test)], eval_metricmae ) lgb_pred lgb_model.predict(X_test) lgb_mae mean_absolute_error(y_test, lgb_pred) print(fLightGBM MAE: {lgb_mae:.2f} 万元) print(f随机森林 MAE: {mean_absolute_error(y_test, y_pred_rf):.2f} 万元)参数说明learning_rate 设 0.05 配合 n_estimators1000是防止过拟合的标准组合——学习率越低需要的树越多但精度更高num_leaves31 对应 5 层深度的叶子数过大容易过拟合subsample 和 colsample_bytree 都设为 0.8让每棵树只用 80% 的样本和特征增加多样性。4.4 处理类别不平衡与样本量不足的应急方案广州二手房数据如果遇到了“天河区样本 5000 条从化区只有 50 条”这种极端不平衡模型会对天河区过拟合而完全忽略从化。解决方案有两种一是按区域分组训练独立模型二是使用分层采样保证每折验证都包含各区样本。from sklearn.model_selection import StratifiedKFold # 先对区域做分层再训练 df[district_code] df[district_code].astype(int) skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) mae_scores [] for train_idx, val_idx in skf.split(X, y, df[district_code]): X_tr, X_val X.iloc[train_idx], X.iloc[val_idx] y_tr, y_val y.iloc[train_idx], y.iloc[val_idx] model RandomForestRegressor(n_estimators300, random_state42, n_jobs-1) model.fit(X_tr, y_tr) pred model.predict(X_val) mae_scores.append(mean_absolute_error(y_val, pred)) print(f分层交叉验证 MAE: {np.mean(mae_scores):.2f} ± {np.std(mae_scores):.2f} 万元)5. 落地技巧用 SHAP 解释预测结果让代码跑出业务价值模型训练完成只是第一步真正让“数据 Python 代码”这套东西有用武之地的是解释每个预测结果为什么是这个价格。SHAP 是目前最成熟的特征归因工具能告诉我们“这套房子比区域均价高 30 万主要是楼层和装修贡献的”。import shap # 用随机森林模型解释 explainer shap.TreeExplainer(rf) shap_values explainer.shap_values(X_test) # 可视化第一个样本的预测解释 shap.initjs() shap.force_plot( explainer.expected_value, shap_values[0, :], X_test.iloc[0, :] )注意TreeExplainer 对所有树模型都适用包括 LightGBM 和 XGBoost但对线性回归要换成 LinearExplainer。如果数据集超过 5 万条建议先采样 1000 条再计算 SHAP 值否则会有明显的内存开销。进一步可以做一个全局分析把所有测试样本的 SHAP 值按特征汇总得到每个特征对预测结果的“方向性影响”。比如结果是“面积每增加 1 平方米SHAP 值平均增加 0.8 万”“楼龄每增加 1 年SHAP 值平均减少 0.3 万”。这类量化结论比单纯的特征重要性排序更有说服力可以直接写进项目报告或答辩 PPT。最后一个实践建议把模型导出为 joblib 或 pickle 文件配合 Flask 写一个简单的 API 接口输入户型、面积、区域、楼龄输出预测价格区间。这样的完整交付物才是“数据 Python 代码”压缩包的正确打开方式——既能跑出结果也能让别人看懂每一个数字是怎么来的。本文还有配套的精品资源点击获取

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

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

免费获取报价