资讯详情

资讯详情

数据理解先行:疫情下的骑手行为预估实战复盘

“新冠期间饿了么骑士行为预估”这个赛题我从拿到数据包到真正开始建模中间隔了整整一周。这一周我几乎没碰模型全在啃数据和业务逻辑。事后回头看这一周恰恰是整个比赛周期里价值最大的一段时间——因为所有特征工程的灵感、标签设计的依据、甚至验证集切分的坑都是从“数据理解”这一步里长出来的。这篇复盘我就把这部分工作摊开讲清楚怎么读数据字典、怎么从字段分布反推业务机制、怎么识别疫情带来的结构突变以及怎么避免被一份看似“干净”的数据骗过去。如果你也要打这类带强业务背景的预测赛或者只是想把一份陌生的行为数据真正“看明白”这篇内容应该能帮你少走不少弯路。1. 赛题背景与业务逻辑拆解1.1 “骑士行为预估”预测的到底是骑手还是订单拿到赛题的第一件事不是急着打开 CSV而是反复读题搞清楚“行为预估”这四个字的边界。我当时的判断是这类赛题表面在预测“骑手行为”实际预测粒度通常落在订单或骑士的时间窗口上区别非常大。如果是订单级预测目标是每笔订单是否准时送达、配送时长多少特征可以围绕订单属性、商家、天气、路况来构建。如果是骑士级预测目标是某个骑手未来一段时间是否活跃、是否接单、是否可能取消特征则要围绕骑手历史行为序列来构建。还有一种常见设定是把“行为预估”做成排序问题比如预测骑手对订单的接受概率本质上是一个点击率预估式的任务。这三种玩法对数据理解的要求完全不同。我在数据里先找的字段是订单状态、事件时间戳、骑手编号和订单编号然后看它们之间的关系。如果同一订单号下有多条状态记录且状态枚举包含“已接单”“已取餐”“已送达”“已取消”那大概率可以做订单级的履约预测如果数据带骑士ID且跨多天重复出现那还可以延伸到骑手级行为建模。防疫期间的数据还有个特殊点平台很可能增加了无接触配送、异常订单标记、健康状态上报等额外字段。这些字段有没有、怎么分布都能反过来帮你判断赛题想让你关注哪一段“行为”。我在解析字段时会把所有字段按“实体维度”归类订单实体、骑手实体、商家实体、地理实体、时间实体。归类之后预测目标的轮廓会清晰很多后面做特征也不会东一榔头西一棒子。1.2 疫情这个外部变量改变了哪些行为逻辑疫情对骑手行为的影响不是“平均变慢了10%”这么简单而是结构性、分阶段的变化。我在数据理解阶段把它拆成供给、需求、履约三层来看。供给端可用骑手数量波动剧烈。某些区域因为封控、健康监测、隔离等原因骑手运力锐减而另一些区域的骑手可能因为订单集中反而出现短时过载。需求端线上订单结构发生变化。囤货型订单变多防疫物资订单激增小区门口集中取货成为常态单笔订单的商品件数分布可能被拉高。履约端无接触配送普及骑手在写字楼和小区门口的等待时间变长配送距离未必增加但“门到门”的时间却被明显拉长。如果建模时不把这些机制考虑进去很容易把疫情当作一个简单的时间戳特征然后发现模型在高峰期表现很差。我做数据理解时会强制自己追问每个字段这个字段的分布在疫情前、疫情早期、疫情高峰期、恢复期之间是不是存在肉眼可见的迁移这种迁移是均值平移还是方差变大实际操作中我会按周为单位聚合关键指标比如日均订单量、平均配送时长、取消率然后画趋势线。通常在疫情政策调整、防控措施升级的节点上这些曲线会出现明显的断崖或跳变。识别出断点之后后续做特征工程时就能有针对性地引入“阶段标识”或“分段归一化”而不是让模型自己在一片混乱里摸索。2. 数据理解的关键动作从字段到业务信号2.1 数据字典与字段枚举值的交叉验证数据理解的第一步永远是读数据字典但读字典不能只看字段名注释还要看枚举值的业务含义。我在这个赛题里遇到过一个典型情况某个字段叫‘区域类型’注释只写了‘1/2/3’但1、2、3分别代表什么字典里没有。唯一的办法就是拿它与天气、订单密度、配送时长做交叉分析反推数字背后的真实含义。通常我会先做一遍“字段体检”每个字段缺失率、唯一值数量、数据类型、示例值。这一遍跑完很多问题就暴露了。比如经纬度字段存在大量0值说明可能是默认填充时间戳字段有未来时间说明存在脏数据还有订单金额字段出现负数大概率是退款订单混了进来。做完体检后我习惯把字段分成几类直接可用字段骑手ID、订单ID、下单时间、送达时间等清洗后才能用。需要加工字段经纬度需要算距离时间戳需要提取小时、星期、是否为节假日。潜在标签字段订单状态、取消原因、超时时长这类字段决定了标签怎么构造。噪音字段大量缺失且无业务含义的字段该删就删不必恋战。这里特别说一下枚举值。骑手行为预估里最容易出错的就是把“枚举值编号”当成数值来用。比如‘配送方式’的1、2、3如果直接喂给树模型模型能学但可解释性很差而且在某些采样不均匀的时候会误导分裂。我的习惯是先把枚举值转成带语义的字符串再根据后续需要决定是做 one-hot 还是 target encoding。这种处理方式在数据理解阶段就要想清楚否则后面特征代码越写越乱。2.2 时间维度从下单到送达的完整链路行为数据的核心是时间。外卖配送本身就是一条时间链路用户下单骑手接单骑手到店骑手取餐骑手送达。每一步都有时间戳的比赛数据里通常不会全部给齐但至少会有接单时间和送达时间。我在数据理解阶段会把时间字段拆成几组“时间差”接单耗时、到店耗时、取餐耗时、配送耗时。如果字段不全就用自己的业务理解估算。例如同时有下单时间和送达时间但没有接单时间那我至少能算出总时长剩下每段能拆多少算多少实在拆不出来的就放弃不要硬凑。接下来按时间粒度做分布。先看小时级分布一天之中订单量什么时候冲高配送时长什么时候变长。疫情阶段尤其要看“午餐峰”和“晚餐峰”是否出现了时间偏移——有些地区的居家办公导致早餐时段订单上升写字楼午餐峰变得不明显。这种偏移是很有价值的特征信号也直接影响后续按小时做归一化的方式。再看天级和周级。周级分布可以暴露星期效应周末和节假日的骑手行为与工作日完全不同。疫情让这种周期变得更加复杂比如封控期间可能天天都是“周末效应”解封后又会恢复明显的周中/周末差异。我会把这种周期性做成可视化图表然后在脑子里形成对数据节奏的感觉这会指导我后面决定隐藏特征怎么滑窗、滑窗窗口取多大。2.3 空间维度距离与栅格化骑手行为离不开空间。数据里可能有精确经纬度也可能只有匿名化的街区网格编号不管哪种都要理解空间分辨率。如果只有经纬度最基础也最有效的加工是计算配送距离。我在计算距离时用的是高德/百度风格的球面距离公式也就是 haversine 公式。算完之后我会重点关注距离分布是不是大量订单集中在短距离区间是不是有少量订单距离异常大比如从城市的一端跑到另一端如果数据给的是网格ID那就更直接。网格ID天然适合做栅格特征可以直接统计每个网格的订单密度、配送时长均值、取消率等。我在理解数据时会画一张“网格-订单量”的透视表快速找出哪些网格是高频区域。这些高频栅格往往对应商业区、医院、大型小区是疫情期间骑手行为变化最敏感的地方。空间维度还有一个容易忽略的点同一路段在不同时间的路况完全不同所以“空间特征”和“时间特征”必须交互使用。我的做法是构造“时段-区域”交叉特征比如“早高峰时段的高频区域”“晚高峰时段的低频区域”这种交叉特征往往比单独的时间或空间特征更有解释力。数据理解阶段把这些交叉规律摸清楚后面特征工程就顺理成章。2.4 数据质量的系统性体检数据质量体检我放在最后讲不是因为不重要而是因为它是查漏补缺的工具。前面几节已经把字段属性和业务逻辑梳理清楚了再做体检会更有针对性。常见的数据质量问题包括缺失值占比超过50%的字段要慎重使用。缺失模式比缺失本身更重要比如某个字段只在特定区域缺失说明采集过程中针对某些区域有特殊逻辑。异常值配送时长出现负数或超过12小时基本是脏数据。我的处理方式是先识别再决定是剔除还是修正而不是一律删除。重复记录同一个订单ID出现多次可能是状态更新日志也可能是重复采集。如果是状态更新那一定要按时间排序后取最新状态。时间倒挂下单选时间晚于送达时间或者接单时间晚于取餐时间这类记录要么删除要么修正为NaN因为它会严重污染时间差特征。我还会做一致性检查比如订单状态是“已送达”的样本必须有送达时间状态是“已取消”的样本不应有送达时间。如果发现大量样本违反这种业务约束那说明数据生成过程有bug后面的特征工程必须小心。3. 实操手记分层解读骑士行为数据3.1 骑手维度活跃时间、配送效率与取消率骑手是“多订单并发”的调度主体同一时间可能同时持有多个订单所以只看单笔订单维度会丢失很多信息。数据理解阶段我习惯先把数据按骑手ID聚合看每个骑手一天里跑了多少单、分布在哪些小时、平均每单耗时多少。我当时做了三个关键透视骑手活跃时长骑手首次接单时间到末次完成时间的跨度这能反映骑手是全职还是兼职。疫情阶段兼职骑手比例可能会上升这会直接影响运力稳定性。骑手配送效率每小时完成订单数。效率过低的骑手可能是新手或者路况不熟效率过高的骑手则可能是同时接多单的“老手”。骑手取消率骑手主动取消的订单占比。取消率过高说明骑手挑单严重对平台调度是很大的挑战。这三个指标做出来之后我惊讶地发现配送效率和时段关系很大有些骑手午高峰效率极高但下午基本消失有些骑手全天效率平稳但高峰时段反而表现一般。这种“骑手-时段”的交互模式在后面的特征工程里是非常好的素材。3.2 订单维度品类、时段与配送方式的组合效应订单维度的数据理解核心在于找出“配送行为”和“订单属性”之间的关系。我最先关注的是商品品类。疫情囤货期间粮油、日用品、生鲜这类订单的配送时长明显高于餐饮订单因为商品体积大、重量大且可能需要额外的取货时间。我统计了不同品类的平均配送时长和超时率发现生鲜类目的超时率几乎是奶茶类的三倍。这种差异如果不加处理模型很容易把“品类”当作简单枚举值而忽略它背后的物理约束。时段效应同样重要。同样是奶茶订单午高峰的配送时长和下午茶的配送时长就完全不同。我按“小时×品类”做了交叉统计发现午高峰的订单不仅密度大而且商家出餐时间普遍更长。这提醒我在后面构造特征时不能简单把“小时”或“品类”单独使用而是要做交叉。配送方式也是一个关键字段。疫情期间无接触配送普及我看到不同配送方式的订单在配送时长分布上有明显差异无接触配送平均耗时更高但超时率反而更低。这可能是因为无接触配送有更宽松的时间预期也可能是平台在分配这类订单时预留了更多缓冲。这种信息对预测任务非常重要。3.3 疫情阶段变化在数据上的呈现方式疫情不是一根“铁板一块”的时间线而是分阶段的爆发期、高峰期、平台期、恢复期。我尝试把订单数据按周聚合画出一条条趋势线然后人工标出断点。在趋势线上我重点看了四个指标日均订单量订单量出现明显跳升或跳水的周往往是疫情相关政策变化的节点。平均配送时长如果配送时长突然拉长可能对应无接触配送的全面推广或者某个区域的运力短缺。取消率取消率突然升高可能是用户因为配送慢而主动取消也可能是骑手因为封控无法履约。超时率平台允许的最大配送时长在疫情期间可能被动态调整过所以我只看“相对超时”不只看绝对时长。这样标出来的断点对后续建立“阶段特征”非常有帮助。我给每个样本加了一个“疫情阶段标识”然后在后续建模时看看这个特征的重要性排序。结果不出所料阶段特征排在了模型重要性前列。这说明把外部环境信息编码成离散阶段比让模型自己去拟合时间连续性更高效。4. 常见问题与排查技巧实录4.1 标签不平衡与阈值选择骑手行为预估里如果目标是“是否准时送达”大概率会面临标签不平衡问题。准时配送的订单可能占80%以上超时订单只有20%。这种情况下模型即使全预测“准时”准确率也有80%但AUC可能很难看。我的处理方式分几步先看标签分布确定不做任何处理时模型的 baseline。如果严重不平衡考虑做负样本下采样或者调整分类阈值。观察模型的 PR 曲线而不是只看 AUC因为在正样本极少的情况下PR 曲线更能反映真实表现。实际比赛中我往往不会一上来就做正负样本平衡而是先用原始分布跑一个 baseline 模型记录下它在验证集上的表现。然后针对性地做重采样或阈值调整对比结果后再决定要不要保留。这种做法能帮你判断不平衡问题是不是当前最主要的瓶颈。4.2 缺失值里藏着的业务信息缺失值不一定是垃圾很多时候它自己就是特征。以配送距离为例如果距离字段缺失可能意味着该订单走的是“到店自取”或“特殊配送”模式而不是骑手从商家送到用户家。直接删除或均值填充都会丢失这部分业务信号。我的建议是在数据理解阶段把所有关键字段的缺失情况整理成一张矩阵然后看缺失模式之间是否存在关联。如果发现“配送地址缺失”和“订单取消”几乎同时出现那缺失值本身就可以作为预测标签的强特征。实际操作上我会先为每个字段生成一个“是否缺失”的布尔特征再在模型重要性排序里观察它们。多次经验证明这些缺失指示特征往往能排进前20。4.3 时间穿越与预测泄露行为预测最忌讳的就是时间穿越。如果我预测的是T时刻的配送时长那模型只能使用T时刻之前产生的信息。如果我在特征里加入了“送达后的用户评价”或者“订单完成后的金额”模型在训练时就会“偷看未来”导致在线推理时完全崩掉。我在数据理解阶段就会特意标记每个字段的产生时间。比如订单金额在用户下单时就有了可以用用户是否给出高评分在配送完成后才有不能用取消原因如果发生在配送过程中则需要根据业务逻辑判断它是前置还是后置信息。一个典型的泄露场景是用全样本的均值填充缺失值。如果我按整个数据集计算某个区域的配送时长均值然后填充到缺失样本里这个均值实际上包含了未来信息。正确做法是用训练集的均值或者用时间上只包含过去的滑动均值。4.4 分布漂移与验证集切分疫情数据天然存在严重的时间分布漂移。前两周的订单特征分布和后两周的可能完全不同。如果用随机切分的方式把数据分成训练集和验证集验证集会包含大量时间相近的样本导致模型评估结果偏乐观。我采用的切分方式是严格按时间切分前70%的时间段做训练集后30%做验证集。切分之后再确认验证集的时间范围里没有出现极端的政策变化。如果必须针对不同疫情阶段分别评估我会额外划分“早/中/晚”三个验证子集分别看模型的稳定性。这比只报一个总体分数更有说服力也更容易暴露模型在哪类时段上泛化差。5. 从数据理解到建模方案的关键衔接5.1 行为标签选择的三个候选方案数据理解完成之后接下来最重要的一步是定义标签。我当时列了三个候选方案A是否超时二分类。优点是业务含义清晰只管“准不准时”缺点是忽略了超时程度的差异。方案B实际配送时长回归。优点是信息量更细可以精确比较不同骑手、不同订单缺点是受极端值影响大。方案C超时时长的分桶多分类。优点是对异常值更鲁棒且可以通过阈值控制业务风险缺点是标签定义相对主观需要尝试不同分桶方式。我用数据理解阶段产出的洞察来比较这三个方案。方案A虽然简洁但容易受阈值影响疫情期平台对配送时长的容忍度可能在变化方案B更直接但需要做好数据截断处理方案C最灵活但可解释性稍差。我最终选择以“是否超时”为第一版标签因为它的评估指标和业务表达最匹配。后续如果时间充裕再对比另外两个方案的模型效果。5.2 快速基线的搭建与学习曲线观察标签确定后我搭建了第一版轻量基线用原始字段里最直接的几十个特征包括配送距离、下单小时、区域ID编码、天气状况、商品品类喂给LightGBM。这个基线的AUC在0.72左右不算高但是已经能验证整个训练-验证代码链路是否顺畅。基线跑通后我做了一次特征重要性和学习曲线分析结果很说明问题配送距离和下单小时排在前几位符合业务直觉。骑行时段交叉特征比纯小时特征更稳定。训练集和验证集的AUC差异不大说明没有严重过拟合但也没有明显的欠拟合。这正是数据理解的回报——因为没有盲目堆特征所以能更清晰地看到哪些变量在驱动预测结果。后续我在此基础上按骑手维度、订单维度、时空交互维度逐步加特征每加一批就重新评估一次保持模型的迭代方向始终有依据。5.3 一份数据理解报告的沉淀方法比赛过程中养成的一个习惯是在每个阶段都沉淀一份简短的数据理解报告包含数据字典补充说明、字段分布快照、关键趋势图、假设清单。这份报告不需要写得非常正式甚至可以只用 Markdown 或 Jupyter Notebook 来记录但对后续建模帮助极大。我自己的报告模板一般是这样的数据概览多少行多少列时间范围。字段分类哪些字段已经清洗哪些还在排查。关键发现3-5条数据洞察每条都要注明对应的业务逻辑。风险清单哪些字段可能泄漏哪些缺失模式需要关注。下一步计划标签候选、特征候选、验证集策略。这样做的好处是即使比赛周期拉长或者中途需要更换队友重新交接也能在半小时内恢复对全部数据的理解。我在不少项目里都吃过“记不清某个字段当初为什么这么处理”的亏后来养成了这个习惯才彻底解决了问题。数据理解这件事做到最后其实是在训练一种“翻译能力”——把数字翻译回业务场景把业务场景翻译成特征方案。我在这场比赛里的一个很深体会是越是在数据混乱、外部环境剧烈变化的场景里冷静下来做数据理解的时间就越不会白费。它不会直接帮你把AUC从0.7拉升到0.9但能让你在后续每一次特征迭代和模型调优时都清楚地知道自己为什么这么做、下一步该往哪里走。翻车最多的比赛往往不是模型不够强而是从一开始就没有把数据看明白。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →