ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Python数据分析实战:房地产价值预测与特征工程指南

Python数据分析实战:房地产价值预测与特征工程指南 简介一份面向房地产价值分析的数据分析项目适用于高校数据科学、统计学相关课程大作业与实践训练。项目针对房价影响因素识别、开发商户型规划建议、房屋市场价值预估三个典型问题提供完整的Python实现代码与配套分析报告覆盖数据清洗、归一化处理、特征相关性分析、回归建模及可视化展示等环节。压缩包共包含113个文件其中Python脚本18个、CSV数据文件19个、可视化图表74张png与jpg格式、说明文档与许可证文件整体大小约24.26MB文件组织清晰便于按数据处理、建模、报告等模块查阅。已有2292人学习/下载资源完整度高能帮助读者快速搭建同类分析流程也可作为课程设计报告撰写的参考蓝本。借助其中代码与图表可深入理解房地产价值分析的关键步骤并直接修改数据集用于其他区域研究。1. 把“房地产价值分析”当成一个可复现的数据分析工程很多人交出的数据分析大作业不是死于算法而是死在拿到数据之后的第一轮清洗上。房地产价值分析看似简单定一个目标列“总价”或“单价”抓来面积、房龄、楼层就开始跑回归但你会很快发现异常值、缺失比例过高的字段、时间上有偏差的数据会直接毁掉模型输出。这篇内容要拆解的是完成一份“使用Python相关算法对某地区房地产价值进行分析”的完整报告所需的最小技术链用pandas做数据质量检查用特征工程把区位信息变成可计算变量再用scikit-learn和LightGBM跑出可比较的基线结果最后把模型解释、表格和图片写进可提交的Markdown报告里。适合正在做数据分析期末大作业、参与类似竞赛项目以及想把自己的代码从“能出结果”升级到“能复现、能答辩”的人。2. 数据获取与清洗Python算法和报告成败的分水岭2.1 用pandas字段校验先把脏数据挡在门外在开始写任何算法之前我一般会先确认拿到的是“房产交易快照”还是“小区挂牌集合”。这两个概念交付的字段完全不一样前者包含成交日期、建筑面积、总价、户型、朝向、楼栋总层数、所在楼层后者更偏向物业费和容积率。以大作业最常见的数据格式为例先读入CSV用info()和nunique()做一次全字段体检。import pandas as pd df pd.read_csv(house_price.csv, encodingutf-8) print(df.info()) print(df.nunique()) # 房源号是唯一键出现重复说明原始数据存在渠道合并问题 if house_id in df.columns: dup_count df.duplicated(subset[house_id]).sum() print(重复房源号数量:, dup_count) df df.drop_duplicates(subset[house_id], keepfirst)关键参数是encodingWindows导出的Excel CSV经常是gbk编码UTF-8会直接报错。另一处是subset不要对整个DataFrame去重因为不同房源完全可能拥有相同的面积和总价只有house_id或经纬度组合才能作为唯一键。处理完重复之后还要把列类型确认清楚总价和面积转成float朝向、所在楼层这类类别字段保留成object否则后续pandas操作会把它们当作连续值。字段类别字段示例类型进入模型前处理连续数值面积、总价、物业费float去极值、对数变换类别型朝向、所在楼层、行政区object做one-hot或目标编码位置型经纬度float计算至市中心距离后取对数时间型成交日期datetime提取年月、季节或转为距今天数这段字段清单的价值在于它能帮你在报告里解释清楚“为什么要对某些特征做对应处理”而不是单纯把代码堆在一起。2.2 缺失值处理不要一刀切删除按业务字段选策略房价数据里最常见的缺失列是“车位配比”和“物业费”这两类字段对价格确实有解释力但覆盖率如果低于60%直接用算法填充反而会增加噪声。建议把缺失比例高于80%的列直接剔除覆盖率在60%-80%的列用中位数填充而“距最近地铁站距离”这类关键位置字段则需要用小区所在板块的公共信息回填。miss_ratio df.isna().mean().sort_values(ascendingFalse) drop_cols list(miss_ratio[miss_ratio 0.8].index) df df.drop(columnsdrop_cols) fill_rules { property_fee: df[property_fee].median(), # 物业费 subway_distance: df.groupby(district)[subway_distance].transform(median) } df df.fillna(fill_rules)这里的逻辑是横截面数据里字段缺失一般不是随机发生的而是渠道采集遗漏。直接dropna会把样本量砍掉三成影响训练比例全用均值填充则会让方差失真。分组回填的做法更适合带有行政区或板块的二手房价数据因为同一块片区的房源在地理条件上更接近。填写之后打印summary来看每列极值是否还处在正常业务范围。2.3 价格异常点识别用IQR和业务逻辑双重过滤总价和单价的异常往往来自车位买卖、老洋房过户价格做低等场景。只看标准正态分布不顶用房价数据本身右偏直接用3σ会被大量高总价房源误伤。所以我会先做一次IQR过滤再做业务口径二次把关如果一个房间数量为1、面积低于20平方米的房子挂着两三千万总价要人工确认是不是历史保护建筑记录。Q1 df[total_price].quantile(0.25) Q3 df[total_price].quantile(0.75) IQR Q3 - Q1 lower Q1 - 1.5 * IQR upper Q3 1.5 * IQR print(过滤下限:, lower, 过滤上限:, upper) df df[(df[total_price] lower) (df[total_price] upper)] df df[(df[area] 5) (df[area] 500)]IQR的1.5倍系数是探索性数据分析里的经典选择但用在房价上要意识到它会把顶部真实成交也一并切掉。如果你打算在报告里讨论高端住宅可以把上下限改成0.5分位和99.5分位或者保留异常值但单独建一个“高端盘”子集。处理完以后把清洗前后的样本量、单价均值、总价标准差写进报告的“数据预处理”章节很多大作业的分数差距就在这里拉开。3. 特征工程与EDA让算法看见地段的真实价值3.1 构造区位距离特征给房价数据增加“空间感”某地区的房地产价值不只由房子自身参数决定。地块与市中心、地铁站、重点学校之间的距离往往比卧室数量更能解释总价差异。如果你拿到的原始数据里只有经纬度或小区名可以通过公开地图API反解出行政区和商圈坐标再计算距离。注意这里不要用错距离公式城区几公里内用欧氏距离误差可以忽略但跨区数据应改用haversine公式。import numpy as np # 这里请替换为你分析地区的中心点经纬度 center_lat, center_lon 30.0, 120.0 df[dist_center] np.sqrt( (df[lat] - center_lat) ** 2 (df[lon] - center_lon) ** 2 ) # 经纬度差换算为公里再取对数让量级更接近其他数值特征 df[dist_center_km_log] np.log1p(df[dist_center] * 111)背景经纬度差乘以111公里是纬度方向粗略换算关系。更有用的是log1p它让市中心附近房子的特征值差异被放大远郊房子的差异被压缩符合人们对通勤负担的感知曲线。3.2 用相关性矩阵快速判断哪些特征该进模型原始变量之间高度相关时线性回归系数会抖动得厉害这就是多重共线性。房地产数据很容易出现面积和房间数量相关超过0.7房龄和楼栋总层数也可能有弱相关。先画Heatmap把所有数值字段丢进去目标列用实数编码能帮你决定是否要删除一个冗余字段。import seaborn as sns import matplotlib.pyplot as plt corr df[[total_price, area, bedrooms, age, dist_center]].corr() plt.figure(figsize(8, 6)) sns.heatmap(corr, annotTrue, cmapRdBu_r, center0) plt.title(Correlation Matrix for Housing Features) plt.savefig(corr_matrix.png, dpi150) plt.close()如果area与bedrooms的相关性超过0.8我会保留area并删除bedrooms因为面积已经是更细粒度的连续字段bedrooms的信息几乎包含在里面。不过要注意的是朝向、装修这类变量没有线性相关性它们是非线性分类信号。分类变量需要编码后看基尼重要性而不是放进入矩阵。连续特征与总价线性相关系数示例处理策略面积0.67直接入模观察是否存在非线性房龄-0.32保留必要时平方项距离市中心-0.45取对数后入模卧室数量0.58与面积相关性高可选删除表格示例值只用于演示你在报告里应替换成自己的真实计算结果。3.3 对偏态目标值做对数变换稳住回归模型的误差房价总价分布是典型右偏分布少数高总价房源会把RMSE拖得很大。对目标变量取对数之后模型在log空间计算误差相当于用相对误差衡量对总价300万和3000万的房子更公平。报告里最好同时给出原始尺度和对数尺度的RMSE。from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error y_log np.log1p(df[total_price]) X df[[area, age, dist_center_km_log, bedrooms]] X_train, X_test, y_train_log, y_test_log train_test_split( X, y_log, test_size0.2, random_state42 ) from sklearn.linear_model import LinearRegression model LinearRegression() model.fit(X_train, y_train_log) y_pred_log model.predict(X_test) rmse_log mean_squared_error(y_test_log, y_pred_log, squaredFalse) print(RMSE in log space:, rmse_log)注意squaredFalse是scikit-learn新版返回RMSE而非MSE的写法。random_state42固定切分方便复现。如果RMSE在0.2左右意味着预测价格的中位数误差大约是20%只能算及格。若报告只放R²而不放RMSE答辩时很容易被追问。4. 模型训练与超参数调优从线性回归到LightGBM的完整代码4.1 划分数据集不要用随机拆分跳过空间相关坑如果题目只给一个地区的截面数据随机切分会导致同一个小区的样本一半进训练集一半进测试集模型记住了小区ID而不是学到泛化规律。常见解决办法是GroupKFold按小区或行政区分组划分。from sklearn.model_selection import GroupKFold feature_cols [area, age, dist_center_km_log, bedrooms] X df[feature_cols] y np.log1p(df[total_price].values) groups df[district].values group_kfold GroupKFold(n_splits5) for train_idx, test_idx in group_kfold.split(X, y, groups): X_train, X_test X.iloc[train_idx], X.iloc[test_idx] y_train_log, y_test_log y[train_idx], y[test_idx] breakGroupKFold必须传入groups参数否则退化为普通K折。报告里可以将随机K折的结果作为baseline分组K折作为“更诚实的评估”两个结果放在一起比较。这是很多答辩加分所在。4.2 依次跑通线性回归、随机森林和LightGBM拿到同一份训练集先把三个模型都跑一遍。线性回归作为baseline随机森林展示非线性能力LightGBM体现梯度提升在表格数据上的速度优势。关键是不能只贴精度还要解释每个模型的使用前提。from sklearn.ensemble import RandomForestRegressor from lightgbm import LGBMRegressor from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler models { LinearRegression: make_pipeline( StandardScaler(), LinearRegression() ), RandomForest: RandomForestRegressor( n_estimators200, max_depth10, n_jobs-1, random_state0 ), LightGBM: LGBMRegressor( n_estimators300, learning_rate0.05, num_leaves31, random_seed0 ), } for name, model in models.items(): model.fit(X_train, y_train_log) pred model.predict(X_test) rmse mean_squared_error(y_test_log, pred, squaredFalse) print(f{name} : {rmse:.4f})线性回归之前加StandardScaler是为了让不同量纲特征的回归系数可比较树模型不依赖缩放但统一放在pipeline里便于组合使用。LightGBM的n_estimators和learning_rate必须联动调节learning_rate越低需要的树越多300对0.05是常见起点。4.3 用网格搜索和5折交叉验证锁定最优参数报告里写“我是用算法调出来的不是试出来的”最容易让人相信的方法是展示GridSearchCV代码。参数候选范围不要给太大否则大作业的机器会跑一个晚上。常见做法是先用粗粒度搜索锁定数量级再细粒度微调。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [200, 400], num_leaves: [15, 31], max_depth: [-1, 8], } lgbm LGBMRegressor(learning_rate0.05, random_state0) grid GridSearchCV( lgbm, param_grid, cv5, scoringneg_mean_squared_error, n_jobs-1, verbose1 ) grid.fit(X_train, y_train_log) print(Best params:, grid.best_params_)对树模型max_depth限制可以防止过拟合num_leaves是LightGBM比n_estimators更值得关注的参数。搜索完之后用最优参数重新fit一次记录CV均值和标准差。如果最优参数旁边紧邻一组相似参数且分数接近说明模型对超参数不敏感这个模型更值得提交。模型RMSE(log空间)训练耗时主参数LinearRegression0.1230.1sStandardScalerRandomForest0.0896.2sn_estimators200, max_depth10LightGBM0.0762.4slearning_rate0.05, num_leaves31表格中的数值只是示意跑不同数据会得到完全不同结果格式和解释方式可以直接套进报告。5. 报告生成的最后一步用SHAP和模板代码把结论钉在纸面上5.1 用SHAP值解释前三位特征报告不是堆指标答辩时最怕只给RMSE和R²。评委要问的是为什么选这个模型哪个特征对预测价格影响最大SHAP能给出每个特征对每条样本的边际贡献再做全局平均得到重要性排序。对LightGBM这类树模型必须用TreeExplainer。import shap explainer shap.TreeExplainer(grid.best_estimator_) shap_values explainer.shap_values(X_test) feature_names feature_cols shap.summary_plot(shap_values, X_test, feature_namesfeature_names)SHAP图里的横轴是SHAP值纵轴是特征取值高低。如果“面积”这条带子从左上向右下延伸那说明面积对总价有正向单调作用这是可以在报告里直接引用的一句话结论。5.2 用Jinja2生成Markdown报告循环写图写表既然作业叫“完整代码报告”那么报告生成也可以交给代码。最常见做法是用Jinja2模板渲染Markdown把样本量、模型名称、RMSE等变量传进去图片用相对路径引用。这样无论数据怎么换报告骨架都能自动更新。from jinja2 import Template template Template( # 房地产价值分析报告 样本量{{ sample_size }} 模型{{ model_name }} 交叉验证RMSE{{ rmse }} ## 特征影响 最重要的特征是 {{ important_feature }}SHAP均值贡献为 {{ shap_mean }}。 ) report template.render( sample_sizelen(df), model_nameLightGBM, rmseround(rmse_log, 4), important_featurearea, shap_mean0.32 ) with open(report.md, w, encodingutf-8) as f: f.write(report)模板里只放可以自动替换的量化结论不放主观判断。比如“该地区交通更便利的住房成交价更高”这类推断需要你人工确认后写在固定段落里。这样报告既保持自动生成的稳定性又不像空壳。5.3 一个必须做的验证残差与真实分布的贴合度最后一步是验证而不是收工。计算测试集残差的均值和中位数如果均值明显大于中位数说明有少数极端样本把误差拉偏要去检查这些样本是不是商住两用房或规划特殊户型。更直观的做法是画Q-Q图判断残差是否接近正态分布房价数据通常两端厚尾这一步骤的重点是记录现象而非强行修正。import scipy.stats as stats resid y_test_log - grid.best_estimator_.predict(X_test) stats.probplot(resid, distnorm, plotplt) plt.title(QQ Plot of Residuals) plt.savefig(resid_qq.png, dpi150) plt.close()如果Q-Q图两端偏离明显可以尝试对特征也做对数变换或者去掉顶部1%房源后重新训练。每一次剔除操作都要在报告里写明原因不能为了追求完美指标而随意删数据。这一套验证做完你的数据分析大作业就从“代码能跑”变成了“结论可信”。本文还有配套的精品资源点击获取
返回列表