很多搞地理围栏或者位置服务的团队,一上来就问我怎么划分训练集和测试集最科学。我看了一眼他们给的代码,心里凉半截。直接随机切分80/20,完蛋,基本就废了。为什么?因为地理位置数据最大的坑,不是量大,是“空间自相关性”。
咱们说点大白话。你住在北京朝阳区,旁边那家店的数据肯定跟你高度相似,这叫就近同质性。如果你训练集里全是东边的小区,测试集里全是西边的小区,模型看着准确率挺高,一旦上线部署到混合区域,直接崩盘。这就是典型的“过拟合”,模型只是在背地图,没学会规律。
我上个月帮一个做本地生活配送估时的团队调优,他们初期用的就是那种简单的随机切割。结果线上表现一塌糊涂,高峰时段预测延迟误差高达30%以上。后来我们重新做了geo如何选验证集的动作,核心逻辑只有一个:按区域隔离,而不是按样本数量。
具体怎么做?别搞什么复杂的K折交叉验证里的随机折叠,太抽象。我习惯用基于地理网格(H3或者Geohash)的策略。先把整个服务城市划分成大小一致的网格,比如6公里半径一个圈子。然后,确保同一个网格里的一天内所有订单,要么全进训练集,要么全进测试集,绝对不允许同一个格子里的数据既出现在训练里又出现在测试里。
这样做初期你会觉得测试集的数据量变少了,准确率好像没涨多少,甚至因为分布不均看起来更波动。但只要你坚持一个月,会发现模型泛化能力直线上升。那个配送团队在改用这种“空间隔离”策略后,平均预估时间从45分钟压缩到了38分钟,客诉率直接腰斩。
这里有个很多人忽视的细节,就是“时间维度”的干扰。很多时候,你以为是在测空间泛化,其实是在测时间漂移。周一早高峰的流量分布和周六晚高峰完全两个样。所以,我在定义geo如何选验证集的时候,通常会引入时间窗口。比如,用前三个月的数据训练,最后一个月的数据做验证,但这还不够,最好是前两个月的数据训练,中间一个月验证,最后一个月作为最终测试。这样能捕捉到路网变化、临时施工对位置数据的影响。
还有一点,别迷信全域数据。如果你的业务主要覆盖在二线城市,千万别拿一线城市的偏远郊区数据来当验证集的一部分。那个区域的道路稀疏度和生活节奏,跟你主战场完全是两码事。验证集必须得有代表性,要有“长尾场景”。比如雨天、节假日、特殊活动期间的订单数据,必须要在验证集中占到一定比例,大概15%-20%左右比较合适。我之前见有团队因为忽略了台风天的数据导致模型在恶劣天气下完全失效,最后被用户骂翻了。
最后说点实在的,选验证集不是跑个脚本就能完事。得有人工干预。你需要去看测试集里的具体案例,是不是包含了你要覆盖的所有关键场景。比如你的网约车平台,验证集里有没有包含医院门口、学校门口这种上下客困难的点位?如果测试集里全是主干道上的顺畅路段,那模型永远学不会怎么预测拥堵。
这事儿急不得,多花两天时间清洗和划分验证数据,比上线后天天改bug强得多。记住,数据的质量决定上限,而geo如何选验证集的方式决定了你能不能触碰到这个上限。别偷懒,手动检查几个典型网格,真的有用。