ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

伦敦房价预测Kaggle实战:特征工程与时间序列验证是关键

伦敦房价预测Kaggle实战:特征工程与时间序列验证是关键 1. 竞赛任务拆解伦敦房价预测到底在预测什么先聊聊这个竞赛的核心。我参加过不少房价预测类的比赛伦敦这个赛题属于看似入门实则有深水的类型。它给你一批伦敦住房的交易记录包含房屋属性、位置、成交时间等信息要求你预测房价评估指标通常用RMSE均方根误差或MAE。听上去和波士顿房价那个经典案例差不多但真做起来你会发现波士顿那个数据集跟伦敦这个完全不是一个量级。1.1 数据背景与评估指标的选择逻辑先明确一个事评估指标决定了整个建模策略的方向。如果赛题用RMSE意味着大偏差会被平方放大你宁可让预测整体偏保守也不能在某几套豪宅上犯大错如果赛题用MAE那你更该关注中位数附近的样本对极端值的容忍度可以高一些。伦敦房价有一个显著特点——尾部特别长。市中心的海德公园周边和伦敦远郊的房价能差出一个数量级所以要不要对目标变量做变换往往是我动手之前想得最久的问题。我强烈建议先看一眼目标变量的分布。伦敦房价数据十有八九是右偏的长尾拖到很远处。这时候直接拿原始房价作为学习目标模型会被少数豪宅带着走梯度提升树倒是还好但线性模型和神经网络就很吃亏。我的做法是对房价取log变换让分布接近正态模型拟合的稳定性会有肉眼可见的提升。而且Log变换还有个隐性好处——RMSE在log空间里相当于预测比率误差天然降低了量纲差异对损失的支配。1.2 房价预测的难点到底藏在哪里很多人以为房价预测的难点是特征怎么造、模型怎么调但伦敦这个赛题真正的难点在于时间与空间的双重交叉。伦敦房价受宏观经济利率、通胀、脱欧预期的影响也受微观地段地铁站、学区、泰晤士河景观的影响。你把这两者同时塞进一个模型它很容易顾此失彼。另一个容易忽略的问题是数据泄漏。这类竞赛的数据集往往把训练集和测试集按时间切分比如训练集是2000到2015年的成交记录测试集是2016年之后的。如果你直接用全局统计特征比如全量数据的平均房价去编码那测试集的信息就已经渗进训练特征里了。我见过有人这么做之后本地验证分数极其漂亮一上LB排行榜就崩掉就是这个原因。处理时间型数据时必须带着时间旅行的视角——只能用过去的信息预测未来不能用未来的信息回头填坑。2. 数据清洗与探索性分析看不见的坑最致命数据清洗这一步80%的参赛者都是跑个isnull().sum()填个均值结束。但在伦敦房价这个赛题上粗放的处理方式后面一定会找你算账。2.1 缺失值处理不是填个数那么简单缺失值要分三种情况看第一种是真正随机缺失填中位数或众数问题不大第二种是缺失本身就有含义比如一栋房子的车库面积字段为空可能不是没记录而是真的没有车库——这时候你应该把是否缺失直接做成一个独立的二值特征让模型自己学习缺失的含义第三种是业务驱动的缺失比如某些行政区的数据上报不完整这类缺失往往和相关联的特征存在共线性闭着眼睛填均值会扭曲局部规律所以我更倾向于用分组统计填充——按区域分组计算中位数再回填缺失值保留组间差异。举一个我实际踩过的例子伦敦不少老房子是没有中央供暖这个字段记录的而新建公寓几乎都有。如果我全局填有模型就会把老房子和新公寓混为一谈如果我按建造年份分组填充模型就能捕捉到老房子无供暖记录这个组合特征反而对价格有不错的区分度。2.2 离群值与目标变量分布别急着删数据房价数据里的离群值分两类真实离群和错误录入。比如一套1600年建成的二级保护建筑卖出天价这是真实离群它不代表数据质量有问题而是代表这个市场存在收藏品逻辑。如果按标准差一刀切删掉等于抹掉了伦敦房地产最有辨识度的部分。但如果一条记录显示卧室数50、面积80平米这基本就是录入错误该删就删。我处理离群值的做法不是看单变量而是结合时间与空间一起看。我会按行政区分组计算每个区域内房价距中位数的偏离倍数偏离超过5倍的点单独拎出来看是豪宅就保留是错误就直接清洗。另外提醒一句离群点对LightGBM这类树模型的影响没有那么大但对XGBoost的直方图分桶和神经网络的影响是实打实的。先确定主模型再决定清洗力度这个顺序不能反。3. 特征工程让模型看到地段的隐藏语义特征工程才是这个赛题拉开差距的地方。伦敦房价的规律很大一部分藏在空间关系里而空间关系的特征化方式直接决定了模型能不能学到地段这个不可量化的语义。3.1 地理信息编码经纬度不是给你画散点图用的原始数据里往往只有经纬度两列但伦敦这个地方一公里之差房价可能差30%。所以经纬度必须做二次加工我常用的手法有几种。第一种是距离特征。计算每套房到伦敦市中心通常以特拉法加广场为原点的欧氏距离以及到最近地铁站、最近火车站、最近公园、最近河岸的距离。这些距离特征在梯度提升树里非常容易被选中因为房价在空间上的衰减规律是真实存在的。第二种手法是逆地理编码如果你手头有行政区的边界数据可以把经纬度映射到具体的区Borough然后按区计算房价均值、房价增速等统计量作为区域标签。第三种是聚类编码——用KMeans或者DBSCAN把经纬度聚类成若干个自然商圈再把所属簇的编号作为类别特征喂进模型实操下来效果往往比行政分区更细腻因为行政边界本身就是人为划分的不一定贴合房价的自然梯度。还有一个我强烈推荐的技巧在经纬度上构造交互特征比如到市中心的距离 × 是否靠近地铁站。因为市中心附近的地铁站密度高远郊的地铁站反而成了稀缺资源这两者的交互关系不是单独两个特征能表达的。3.2 时间与交易特征从日期里榨出更多信息住房交易数据里的时间字段通常有成交日期。我一般会拆成年、月、日、星期几、季度然后再加两个业务特征从挂牌到成交的耗时如果有这个字段的话和成交月份距当年年末的剩余天数。后面这个特征有点冷门但在伦敦实际有解释力——年末成交的房子往往是卖家急于出手价格上可能有一点折价。另一个值得做的方向是滞后特征。假设训练集跨度为多年你可以计算每个区域在上一年度的房价均值、成交量然后merge回当前年份的交易记录。这相当于把历史价格趋势作为已知信息喂给模型本质上是给模型一个宏观视角让它不只看到单套房的微观属性。但这里有个前文提到的坑做滞后特征时必须保证merge的键和时间窗口严格向后看。比如预测2015年的房价只能用2014年及之前的数据计算滞后统计量绝对不能用2015年全年数据算了再塞回去否则就是典型的数据泄漏而且这种泄漏在本地验证里极难发现。4. 模型构建与调优从LightGBM到集成策略模型部分我直接说结论如果你只打算跑通一个模型用LightGBM如果你想拿靠前的名次集成是绕不开的路。这不是说其他模型没用而是针对伦敦房价这种中等规模、含大量类别特征和缺失值、没什么复杂非线性纹理的表格数据梯度提升树在实践中就是性价比之王。4.1 基线模型的选择先跑通再谈优化我习惯第一版用一个轻量级的LightGBM参数全部默认只设置一个合理的类别特征列表目的是快速验证特征工程的有效性而不是追求指标。这个基线的作用有三个一是确认数据管线没有泄漏二是给你一个心里有底的分数锚点三是为后续特征筛选提供重要性排序的基准。在跑基线的时候我会做一次完整的特征重要性排序把重要性靠后的特征先标记出来。但这里提醒一句不要只看gain重要性也要看split重要性。有些特征在每棵树上都被拿来切分split高但单次切分带来的增益很小gain低这类特征往往是高基数类别特征比如精确到街区的编号它们不一定没用但需要警惕过拟合。4.2 交叉验证策略时间序列数据不能用K-Fold乱切这是伦敦房价赛题里最容易被忽略、也最致命的一个环节。如果你的数据是时间排序的标准的5折K-Fold会随机打乱样本导致训练集里混入了未来的样本每折的验证分数都会虚高。这种虚高在本地会让你误以为模型很好一提交就露馅。我的建议是使用TimeSeriesSplit或者Purged K-Fold。保持时间顺序用前60%的数据训练、后40%的数据验证再逐步滑窗。在伦敦房价的比赛里时间滑窗式的验证分数虽然比随机K-Fold难看一点但它更接近线上测试集的真实表现。我甚至建议最终调参时以时间序列验证为主随机K-Fold只用来观察方差。4.3 集成方法不只是平均一下分数到了集成阶段经常有人问不就是把LightGBM、XGBoost、CatBoost的结果平均吗——理论上是但实操里有几个细节直接影响效果。第一模型之间必须有差异性。如果三个模型都是同样的特征、同样的超参仅仅是库不同集成出来的提升非常有限。我一般会让LightGBM吃多一些特征包括高基数类别XGBoost做严格的缺失值处理与正则化CatBoost则直接喂原始类别特征不编码让三者的偏见倾向各自不同方向。二是加权方式别只看验证分数。我习惯于对比各模型在不同价位段低端、中端、高端上的误差表现如果某个模型在高端价位明显更准就给它更高的权重而不是简单地按整体RMSE选权。第三集成以后再做一次blending的残差分析看看加权结果在哪类样本上依然有明显偏差这可能意味着你的特征库里还缺一个和该类样本相关的关键维度回到特征工程找灵感胜过继续堆参数。5. 实战复盘踩过的坑与最终提升的两个关键操作这部分算是压箱底的经验了单独拎出来说因为过程实在曲折但每一步都值得复现。5.1 第一个坑滞后特征的时间泄漏我第一次做滞后特征的时候用的是全量train数据按区域算的均值本地验证RMSE掉得非常漂亮我一度以为拿了上分秘籍。直到提交之后分数比本地验证差了一大截才反应过来特征构建时用了未来信息测试集里的区域房价均值已经被污染了。修复方式不算复杂对训练集做滞后续——每个时间窗口的统计特征只基于更早的历史数据计算测试集上则用截止到训练集末尾的历史数据推算。修完之后本地分数小幅变差但线上分数稳了很多。这算是我在时间序列数据上花过的最贵的一笔学费。5.2 第二个关键操作地理聚类特征的点数选择另一个提升比较大的操作是在聚类特征上做了一次细分。一开始我用KMeans把经纬度聚成20簇效果一般。后来我改成多尺度聚类分别聚成10簇、30簇、60簇然后把三个尺度的簇编号都作为特征放进模型。多尺度的逻辑是10个簇代表大片区的宏观差异60个簇代表小社区的微观差异树模型可以自己决定在哪个尺度上切分。这个操作让我的CV分数直接往前走了一小截而且和行政区特征并不冲突模型在两组特征之间找到了更好的互补关系。5.3 关于Kaggle注册和环境的碎碎念最后说个和赛题无关但很多人卡过的问题——Kaggle账号注册和环境访问。这个竞赛本身需要能正常登录Kaggle、把notebook跑通。如果你遇到注册收不到验证邮件、页面加载不稳定的情况多半是网络环境的问题。我只能建议你检查一下网络本身是否稳定换个时段再试不要强拉。另外比赛环境一定要提前测好——训练脚本在本地跑通之后记得在Kaggle的GPU/TPU环境中做一次完整推理确认依赖版本、内存限制都没问题否则临提交才发现环境跑不起来那才是真的心态崩溃。6. 最后几点实操建议按照老规矩把我这次经验浓缩成几条清单方便你下次参赛直接参考第一动手之前先确认评估指标RMSE和MAE的建模策略完全不同。第二目标变量先看分布右偏就log变换不要犹豫。第三时间序列数据严禁使用普通K-FoldTimeSeriesSplit是你的底线。第四滞后特征务必做后视校验任何用到未来信息的特征都等于作弊。第五LightGBM做基线XGBoost和CatBoost做差异化最后加权集成这是性价比最高的路线。第六地理聚类做多尺度比单尺度聚类信息量大得多。我自己做完这一套下来最大的体会是Kaggle竞赛比的从来不是谁的模型更花哨而是谁的数据处理更扎实、谁的验证策略更贴近线上。伦敦房价这个赛题尤其如此——房价不是一张静态的快照而是一张被时间、地段、政策共同拉扯的动态网络。那些看不见的坑往往比看得见的特征对最终排名更关键。希望这篇复盘能帮你在下次参赛时少踩几个坑。
返回列表