资讯动态

伦敦房价预测实战:特征工程与模型集成全流程解析

发布时间:2026/10/1 17:34:12 来源:尧图企业网站定制
第一次看到 London House Price Prediction 这个题目时我第一反应是房价预测又是经典回归题应该不难。但真把数据下下来跑过一轮之后才发现这个项目背后的“Advanced Techniques”不是白写的——它真正考验的不是你会不会调一个 XGBoost而是你有没有一套完整的特征工程思路、验证策略和集成手段能不能在中等规模数据集上把成绩从“能跑”推到“高分”。这篇文章我就围绕这个 Kaggle 竞赛项目从数据理解、特征挖掘、模型选型到调参与排错完整梳理一遍我的实操路线适合正在入门 Kaggle 回归赛、或者想在表格数据领域把分数再往上提一档的朋友参考。1. 项目背景与数据集初步解析1.1 竞赛目标与数据集结构这个竞赛要解决的是一个标准的监督学习回归问题给定伦敦地区一批房产的交易属性预测成交价格。从题目名称看它隶属于 Kaggle 上典型的“Playground 风格”竞赛但数据规模和特征噪声都设计得很有代表性——没有到你随便跑个线性回归就能拿高分的程度也没复杂到需要大规模深度学习才能处理。原始数据通常包含以下几类字段房产的基本属性卧室数量、卫生间数量、面积、房屋类型公寓、联排别墅、独栋等地理位置信息经纬度坐标这是伦敦房价预测里权重最高的信息源时间信息挂牌时间、成交时间或者建筑年份目标变量最终成交价格呈显著右偏分布。我拿到数据后做的第一件事不是直接跑模型而是把字段逐一列出来判断每个字段是数值型还是类别型、缺失比例有多高、与房价的相关性大概是什么方向。这个步骤看起来基础但对后续特征工程的走向影响非常大——比如一开始我以为是面积对房价影响最大实际跑完相关性分析后发现位置特征的预测能力远超面积这个认知直接改变了我后面的大部分时间投入方向。1.2 为什么这个题目是“特征工程驱动”型任务伦敦是全球房价差异最悬殊的城市之一。同样是一套两居室在金融城附近和伦敦郊区单价可能相差三倍以上。这意味着模型必须能够“理解”地理位置否则仅靠房型、面积这类常规特征模型预测的天花板非常低。所以这个题目的“Advanced Techniques”核心并不在于用多么复杂的神经网络而在于三点如何把经纬度这种连续坐标转化为模型容易利用的信息如何组合多个低阶特征生成对价格有强解释力的交互特征如何通过合理的验证方式让模型在不同区域、不同时间段都能保持稳定。我采用的第一层位置特征处理方案是直接计算每个样本到伦敦几个核心地标的距离用哈弗辛公式haversine算球面距离。这一步做下来模型分数立刻有了明显提升。后续我又在这基础上扩展了格网划分、区域聚类等特征每一层都有稳定的增量。提示做位置相关特征时尽量用“距离”或“区域编号”这类对树模型友好的形式而不是直接把经纬度两个裸数值丢进去。树的切分逻辑本质上是在做阈值判断裸经纬度虽然也能切但很难表达“距市中心 15 分钟车程”这种连续语义。2. 数据清洗与特征工程的实战拆解2.1 缺失值处理不只是“填”那么简单这个数据集的缺失值情况不算严重但每个字段的缺失逻辑不一样处理方式也不同。比如卫生间数量有些行是空的很多情况下是挂牌信息没填全而不是真的没有卫生间有些字段比如建筑年份它缺失可能意味着老房子或信息不全这本身就包含信号。我的处理策略分三种类别型字段缺失用该列最频繁出现的值填充同时增加一个“is_missing”二值特征让模型自己判断这条样本是否缺失数值型字段缺失优先用中位数填充避免被个别极端值带偏有明确业务含义的字段例如年份如果缺失比例不高直接删除对应行如果比例较高则单独归为一类“未知”并配合 is_missing 特征。实际测试下来is_missing 特征在某些字段上的增益比中位数填充本身还高。原因是缺失本身往往和挂牌粗糙度有关而挂牌越粗糙的房子价格通常越低模型能捕捉到这种隐含关系。2.2 目标变量为什么要取对数大部分房价数据集的分布都是严重右偏的——少数几套千万级别的豪宅会把均值拉得很高但如果直接对原始价格建模模型会把大量精力花在拟合这些极端值上导致普通房子的预测反而不准。解决办法是目标变量做对数变换y_log log1p(price)这样做的本质是把误差惩罚从“绝对金额误差”变成“相对比例误差”。预测一个 50 万的房子相差 5 万和预测一个 500 万的房子相差 5 万在 log 空间里的损失量级是接近的但在原始空间里前者造成的误差会显著大于后者。这对业务也是合理的——买 500 万房子的人对 5 万误差的敏感度和买 50 万房子的人完全不同。训练时使用 log 后的价格作为回归目标提交预测时再用指数函数还原price_pred expm1(y_log_pred)这里有一个细节经常被忽略直接对 log 空间的预测值做指数还原得到的预测均值会比原始分布的真实均值偏低因为指数函数的非线性导致误差分布不对称。实践中可以用 smearing 估计量修正即price_pred expm1(y_log_pred) * mean(expm1(y_true_log) - expm1(y_pred_log))具体做法是计算训练集上真实值与预测值比例的平均值乘以测试集预测结果来微调。这个修正通常能让分数小幅提升。2.3 经纬度特征从坐标到知识的转换经纬度是这个数据集里信息密度最高的字段但在原始形式上两个整数浮点数对树模型来说既难切分也不直观。我的处理分三个层次第一层距离特征。选几个有代表性的参考点——金融城、主要交通枢纽、大型公园——用哈弗辛公式计算每个样本到这些点的距离。参考点不用多四到六个足够。核心代码逻辑如下import numpy as np def haversine(lat1, lon1, lat2, lon2): R 6371.0 lat1_rad np.radians(lat1) lon1_rad np.radians(lon1) lat2_rad np.radians(lat2) lon2_rad np.radians(lon2) dlat lat2_rad - lat1_rad dlon lon2_rad - lon1_rad a np.sin(dlat / 2) ** 2 np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(dlon / 2) ** 2 return 2 * R * np.arcsin(np.sqrt(a)) train[dist_center] haversine( train[latitude], train[longitude], center_lat, center_lon )第二层格网划分。把经纬度按不同粒度切分成格子每个格子生成一个类别 ID。比如按 0.01 度、0.05 度、0.1 度三个粒度分别切这样模型既能看到精细的小区域也能看到粗粒度的大片区规律。第三层区域聚类。用 KMeans 对经纬度做聚类把每个样本归入某个空间簇然后将簇中心距离、簇编号作为特征。这一步相当于让模型自动发现“哪些位置的房价模式比较接近”比手动设定地标要全面得多。三层特征叠加后模型的验证 R² 提升了至少 0.02可以说这是整个项目里收益最高的特征工程操作。3. 建模策略与验证策略设计3.1 主力模型为什么选梯度提升树家族表格类数据的建模梯度提升树GBDT家族基本是标配这个竞赛也不例外。我分别测试了 LightGBM、XGBoost 和 CatBoost最终的结论是三个模型各有优劣适合做集成而不是只押注某一个。模型优势需要注意的点适合场景LightGBM训练快、内存占用低、支持直方图加速leaf-wise 生长容易过拟合需限制深度大规模数据、快速迭代XGBoost正则化强、对缺失值有内置学习方向调参维度多默认参数往往不是最优中小规模数据、追求精度CatBoost原生支持类别特征、有序提升防目标泄漏训练相对慢类别特征需显式声明高基数类别特征多的场景我个人的主力选择是 LightGBM。它的直方图算法在大样本下迭代速度极快而且 leaf-wise 生长策略配合 max_depth 限制实际调参可控性很强。但 CatBoost 的优势在于它对类别特征的编码方式——这个数据集里的房屋类型、格网 ID 都是高基数类别变量CatBoost 能直接以原生形式处理省去了手动 one-hot 或 target encoding 的麻烦。3.2 交叉验证别让验证分数骗了你这是整个项目里最容易被低估的一环。常规做法是直接train_test_split或随机 KFold但对于房价预测这种带有强空间相关性的数据随机划分会让验证集里出现训练集的“邻居”模型分数虚高。我踩过这个坑。第一次用随机 KFold 跑 LightGBM验证 R² 到了 0.91当时还挺高兴提交后 LB 只有 0.87差距非常大。后来才意识到同一片区域里不同房源的价格高度相关随机划分把大量位置信息“泄漏”到了验证集里。解决方案有两种按格网 ID 做 GroupKFold保证同一区域的样本不会被同时分到训练集和验证集按时间排序后切分用前 80% 的时间段训练后 20% 预测模拟真实场景中的“用已知预测未知”。两种方案我都试过最终选择了 GroupKFold 作为主验证方式因为它在不损失太多训练样本的前提下能更真实地反映模型对新区域的泛化能力。虽然验证分数下降了 0.03 左右但和 LB 的匹配度大幅提升。3.3 调参路线先粗调后细调调参这件事我不建议一上来就上 Optuna 或 GridSearch。我的流程分三步第一步用默认参数跑通基线确认代码流程没问题记录验证分数 第二步粗调核心参数——学习率、树数量、最大深度找到大致的最优区间 第三步再对 feature_fraction、bagging_fraction、min_data_in_leaf 做小范围搜索。常用的 LightGBM 参数区间参考params { objective: regression, metric: rmse, learning_rate: 0.01, num_leaves: 63, max_depth: 7, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 1, min_data_in_leaf: 50, verbose: -1, }注意一点learning_rate和num_boost_round必须联动调整。学习率越低需要的树越多训练时间越长。我的策略是用 0.01 的学习率和 early stopping 回调让模型自动决定树的数量这样比手动固定树数要稳健得多。4. 集成方法与预测后处理4.1 为什么单一最强模型不够在 Kaggle 竞赛里单一模型即使调参调得再好排名也容易遇到瓶颈。核心原因有两个一是模型方差。同一个模型不同随机种子跑出来的验证分数会有波动单次提交等于在赌运气 二是模型偏差。LightGBM 和 CatBoost 对特征的利用方式不同它们在捕捉价格模式时各有盲区。比如 LightGBM 对缺失值的处理是学习一个默认方向而 CatBoost 对高基数类别特征的处理是全自动目标统计两者在同一份数据上的错误样本往往不重合。把多个不重合的错误来源叠加在一起错误会互相抵消整体精度反而提升。4.2 五折 Stacking 的完整流程我在这个项目里用的集成方案以 Stacking 为主、加权平均为辅。具体流程如下将训练数据按格网 ID 分成 5 折每个基模型LightGBM、XGBoost、CatBoost分别在 4 折上训练对第 5 折和测试集做预测5 次循环结束后把验证预测拼接成 OOFOut-of-Fold预测测试集预测取 5 次平均用 OOF 预测作为新特征训练第二层模型——一般用岭回归或者简单的线性回归即可第二层模型的输出作为最终预测。Stacking 的一个关键细节是第二层模型的输入只有基模型的 OOF 预测绝对不能用测试集预测去训练。否则第二层模型会“看到”测试集的信息导致提交结果失真。另外基模型之间的相关性要控制。如果三个模型全是同一种算法不同参数Stacking 的收益会很小但 LightGBM XGBoost CatBoost 这种异质组合增益相对明显。我最后提交用的权重大概是 LightGBM 0.4、CatBoost 0.35、XGBoost 0.25在私有榜上的表现比任何单一模型都高。4.3 预测值还原与分布对齐模型输出的是 log 空间的预测值提交前必须还原成真实房价。这一步本身不复杂但有几个细节值得留意第一expm1还原后预测分布整体会比训练集真实分布略微偏低这是对 log 目标做均值回归的固有现象。可以通过计算训练集上真实价格 / 预测价格的均值作为缩放系数对测试集预测做整体微调。第二一定要检查测试集预测的分布形状。我一般会把测试集预测和训练集真实价格的直方图画在一起对比如果形状差异明显说明模型可能存在过拟合或者数据泄漏需要回到前面的步骤排查。第三提交文件前检查 ID 顺序。Kaggle 平台对提交格式有严格限制少一行、多一行、顺序错乱都会被判 0 分。这个错误看似低级但每次竞赛都会有一批人踩坑。5. 常见坑点与实战排错5.1 平台使用类问题先回答一个很多人私信问我的问题Kaggle 是什么简单说它是一个数据科学竞赛平台企业或机构在上面发布真实业务问题全球的数据科学家提交模型以量化指标排名。伦敦房价预测这个竞赛就是典型的数据科学实战场景特别适合用来练习完整的数据处理与建模流程。关于注册确实有朋友遇到过收不到验证邮件的情况。常见原因就是邮箱把激活邮件放进了垃圾箱或者邮箱服务商对平台邮件做了拦截。处理办法很简单换一个常用邮箱重新注册或者检查邮箱的垃圾邮件目录。密码强度要求较高必须包含大小写字母、数字和特殊字符这也是注册失败的高频原因。如果提交注册后长时间收不到邮件可以尝试用浏览器无痕模式重新走一遍流程排除浏览器缓存干扰。5.2 训练与预测中的典型问题我在这个项目里遇到并排查过的问题整理成了一张速查表问题场景可能原因排查思路解决方案验证分数高LB 分数低随机 KFold 造成空间信息泄漏对比随机 KFold 与 GroupKFold 的分数差改用按格网 ID 分组的 GroupKFold预测价格整体偏低log 还原后的均值回归偏差画测试集与训练集价格分布对比图用缩放系数对预测做整体微调CatBoost 效果反而变差类别特征未声明为 category 类型检查特征类型是否被当作数值处理显式转换astype(category)并传入cat_featuresLightGBM 训练时间长学习率过低且未设 early stopping查看训练日志中的迭代数提高学习率并配合 early stopping提交后分数为 0预测结果与 ID 顺序不对齐检查 submission 文件行数与前几行对齐测试集原始 ID 顺序后重新提交多次提交结果抖动大随机种子未固定查看不同种子的 OOF 分数差异统一固定 seed或用多个种子做平均5.3 独家避坑技巧最后分享两个我在实际项目中摸索出来的小技巧。第一个是关于特征组合的。格网 ID 和房屋类型、格网 ID 和建筑年份这两个组合特征对树模型的增益非常明显。原理是同一个片区内公寓和联排别墅的价格基数是完全不同的同一个片区内老房子和新房的价格走势也不同。把这些组合直接展开成新特征等价于帮模型预先做了很多交互逻辑的搜索。第二个是提交前的小习惯。我会固定随机种子后把每个模型的五个 fold 预测文件分别保存下来最后再做平均。这样做的价值在于如果某次预测出现异常比如某个 fold 的预测分布明显偏离可以单独排查而不是等到提交后才发现问题。6. 一点个人心得与后续扩展思路到这一步整个伦敦房价预测的流程基本完整了。从数据清洗、特征工程到模型训练、调参、集成再到最后的预测还原每一步都有明确的决策逻辑。我自己在这个项目里最大的体会是Kaggle 竞赛真正锻炼的不是调参手速而是对数据的“嗅觉”——你能不能在看到经纬度的第一眼就意识到位置价值的权重能不能在验证分数虚高时保持冷静重新审视划分方式这些判断力才是从竞赛到实际工作最可迁移的能力。如果后续想继续扩展我会建议往模型可解释性方向挖一层。用 SHAP 值分析一下哪些特征在驱动伦敦房价的预测结果不仅能帮你自己理解模型的决策逻辑放在业务场景里也能直接回答“哪类房子具备升值潜力”这类真实问题。这个项目作为一次完整的数据科学实战值得反复跑几遍每跑一遍你都会对模型和数据产生新的理解。

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

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

免费获取报价 →
↑