☰
数据理解决定特征工程上限:从骑士行为预估看数据竞赛关键第一步
2026/10/5 1:09:18 网站建设 项目流程

实话说,大部分第一次做数据竞赛的人,拿到的不是一份整理清楚的数据集,而是一堆字段名杂乱、缺失值遍地、分布还严重不均衡的表。这时候大家的第一反应都是赶紧跑个baseline压压惊,我也不例外。但在"新冠期间饿了么骑士行为预估"这类比赛里,我吃过的亏告诉我——**数据理解花的时间,直接决定后面特征工程的上限。**这篇博文就围绕数据理解这个阶段展开,讲讲我是怎么把比赛题目里的业务背景翻译成数据分析上的判断,怎么看字段、找洞察、躲坑,以及怎么平滑地衔接到特征工程。

1. 拿到题目先别急着建模:把业务背景吃透

1.1 为什么"新冠期间"这四个字决定了数据理解的方向

很多人拿到比赛数据,第一反应是看字段、看缺失值、跑统计,但我认为最该先做的是把题目里"新冠期间"这四个字,转化成数据分析上的具体含义。2020年初开始的那段时间,整个即时配送行业发生了结构性的变化,它不是普通的季节性波动,而是需求端和供给端同时被改写。

需求端,用户的外出频率显著下降,线上订单占比快速抬升,下单时段、单笔金额、购买品类都和平时不一样。供给端,部分骑士阶段性无法出勤,运力出现大起大落,单日订单量的走势变得很"脆",一个节点变了,整个曲线就断了。这两个变化叠加在一起,导致数据出现三个显著特征:时间序列上有多个结构性断点、不同地区的曲线形状差异极大、同一个骑士在不同阶段的行为模式可能完全不同。

数据理解阶段如果不先把这种"业务地震"的背景吃透,后面所有的统计分析都像是在用一个平稳世界的假设去解释一个非平稳世界,结论自然容易走偏。举个例子,正常业务里"上周同时段订单量"是一个很稳定的基准特征,但在这种场景下,上周的数据可能来自完全不同的供需环境,直接拿来做基准反而会引入噪声。

1.2 "行为预估"到底在预估什么:先界定样本和标签

题目里写的是"骑士行为预估",但"行为"这个词在不同比赛里指的东西完全不一样。数据理解阶段要做的第一件事,就是把题目文档里每个描述性词汇翻译成可计算的定义。

具体来说,需要回答这几个问题:预测目标是类别还是数值?是骑士会不会接单,还是这个订单可能多久送达?样本的粒度是什么——一条记录对应一个订单,还是对应骑士一天的行为汇总?预测的时点是什么——是在骑士看到订单之前预判,还是在订单完成后复盘?

这些问题如果不先钉死,后面训练集和验证集的划分、特征的时间对齐都会出错。我见过很多团队模型分数不低,但提交之后效果差很远,回头查原因,十有八九是样本口径从一开始就没想清楚。所以数据理解阶段的产出物,第一项就应该是"样本与标签说明书",把上述问题逐条写清楚。

1.3 数据理解阶段的产出物不是报告,是判断

数据理解很容易做成一件看起来很努力、但产出很虚的事情:输出一堆分布图、一堆相关系数矩阵,然后不知道下一步干什么。我的标准是,数据理解阶段必须产生三个可复用的东西:第一,样本和标签的定义说明书;第二,字段字典——每个字段的含义、类型、缺失率、取值分布和可用时间;第三,一组可复用的EDA脚本,后面每次数据更新或特征迭代都能直接跑。

这三个产出不是给别人交差的文档,而是给后面的自己做导航。尤其是字段字典,我在特征工程阶段几乎每周要翻几十次,查某个字段的粒度、查某个特征会不会泄漏、查缺失值集中出现在哪个时间段,全靠这一份字典。写到这,熟悉数据竞赛节奏的人应该能感觉到,数据理解阶段的核心价值,在于降低整个项目后半程的决策成本。

2. 先从字段地图开始:骑士行为数据里到底藏了什么

2.1 六类字段,六种理解方式

拿到原始数据之后,我习惯先把所有字段按信息类别分个组。分类的意义在于,每类字段在数据理解阶段要关注的重点完全不同,混在一起处理会漏掉很多细节。

字段类别典型字段数据理解阶段的核心关注点
标识字段骑士ID、订单ID、设备ID是否唯一、重复模式
时间字段下单时间、接单时间、完成时间粒度、覆盖范围、时区一致性
空间字段经纬度、区域ID、商家与用户位置分布密度、异常点
业务属性字段订单金额、物品类型、骑士等级缺失率、取值分布
环境字段天气、温度、风力取值完整度、时间戳是否对齐
标签字段是否完成、是否超时类别平衡、与业务定义是否一致

举一个具体例子:标识字段的检查能发现"同一订单是否出现了多次"。如果是,那这张表很有可能是订单轨迹点表,而不是订单表,后面计算配送时长时就需要先做聚合。这类基础认知如果不建立,直接拿订单维度去统计,结果基本都是错的。

2.2 用唯一性组合反推数据粒度

判断数据粒度,最靠谱的办法不是看文档,而是自己动手做唯一性组合检查。操作很简单:用pandas的nunique,或者SQL里的count distinct,分别统计关键字段组合下的唯一值数量。

我建议按"骑士ID+日期"、“骑士ID+订单ID”、“订单ID+时间戳”、“骑士ID+小时”这几种组合依次排查。如果"骑士ID+订单ID"组合下出现重复行,说明一张订单可能被记录成多行;如果"骑士ID+日期"是唯一的,说明这张表是骑士维度的日粒度快照。这一步通常只需要写几行脚本,十几分钟就能跑完,但因为大多数比赛数据集的字段名并不规范,这一步带来的信息量往往非常大。

我在做这类检查时,习惯把每次结果用一张小表打印出来,记录组合名称、总记录数、唯一组合数、是否有重复。跑完两三张表之后,数据的组织方式基本就清楚了。很多人跳过这个步骤直接做统计,后面做特征时才发现维度对不上,返工成本远高于一开始就花十几分钟做检查。

2.3 时间字段的三个隐性坑

时间字段是骑士行为数据里最容易被忽略、又最能影响模型质量的部分。我整理了三个几乎每次都会出现的坑。

第一个是时间精度不一致。有的订单记录到分钟,有的只记录到日期,合并之后很难统一计算配送时长。第二个是时间语义不统一。同一张表里,"下单时间"和"接单时间"可能来自不同系统,一个记录的是骑士端点击时间,另一个是服务端入库时间,两者相差几十秒到几分钟,如果直接拿来做时长计算,噪声会很大。第三个是时区隐患。跨区域业务如果有一列时间忘记统一到北京时间,小时级别的分布就会整体偏移,等画"24小时活跃度曲线"的时候才会发现曲线形状不对,但此时往往已经很难追溯是哪部分数据出了问题。

我的习惯是,在数据理解阶段专门写一个时间字段检查脚本,把每个时间字段的min、max、缺失值比例、是否含时间部分、粒度是否一致全部输出成一张清单。跑完一轮之后,哪些时间字段能用、哪些需要清洗,心里就有底了。

3. 我从数据里看到的四个关键洞察

3.1 骑士活跃度不是一个平稳曲线,而是三段式结构

如果把骑士每日活跃数量和日订单量拉成时间序列,会看到非常明显的三个阶段。疫情初期,活跃骑士数量和订单量还维持在日常水平附近;进入高峰期后,活跃骑士数明显下滑,而单个骑士日均承担的单量却快速上升,这说明运力端出现了明显的供需错配;到了恢复期,活跃骑士数回升,单人日均单量回落。

这三段式结构几乎在每个区域的数据里都能复现,只是时间节点有差异。这个洞察直接决定了后面特征工程的一个核心思路:不能把整个时间段当成同一个分布来建模,必须给样本加上"阶段"信息。无论是直接做一个阶段标签特征,还是按阶段分别训练模型,这个信息都会带来很大的提升。数据理解阶段如果没画出这张曲线,后面的模型就少了一个最关键的结构性信息。

3.2 配送时长分布的整体漂移

正常时期,配送时长的分布大致是右偏的钟形,均值稳定,高峰期略微拉长。但在疫情影响下,配送时长的整个分布会整体右移,长尾明显变长,而且这种变化不是均匀的——高峰期变得更慢,平峰期变化相对小。

这个洞察看起来简单,实际影响很大。第一,如果用全量历史均值做配送时长的基准特征,在疫情阶段会系统性低估真正的时长;第二,配送时长分布的变化本身就是一个强信号,可以衍生成"当前环境是否异常"的特征。做数据理解时,我通常按周为单位画配送时长的分位数折线图,分别看P50、P90、P95的走势,观察这几个分位数的拐点,比只看均值更能准确描述分布形态的改变。

3.3 接单响应时间和取消率的联袂变化

骑士行为预估里有个很容易被忽略的表征维度,就是"接单响应时间"——从订单推送给骑士到骑士点击接单之间的间隔。正常时期这个指标相对稳定,但在疫情高峰期,响应时间会明显变长,同时订单取消率上升。

这两者的联袂变化,反映的是骑士在接单决策上的保守化:接得更慢、更挑,或者接完发现路线不可行就取消。对模型来说,这类行为特征恰恰是"行为预估"任务里最有预测力的部分——因为它反映的是骑士状态的实时信号,比静态属性特征敏感得多。数据理解阶段,我会专门比较不同阶段下"响应时间"和"取消率"的分布差异,确认这些信号在目标定义下是"输入"还是"目标",避免后续特征错位。

3.4 天气与时段的交互效应被疫情放大

最后一个是天气与时段、疫情阶段的交互效应。正常时期,下雨天和早晚高峰对配送时长的影响是叠加的,但影响幅度有限。而疫情期间,这种叠加效应会被明显放大,高峰期遇上雨天,配送时长的P90可以比正常时期翻倍。

这种情况很难用单个特征表达清楚,需要构造交叉特征。我的做法是在数据理解阶段先画一张透视表:行是时段分箱,列是天气类别,再加一个是否疫情高分期作为第三层维度,看配送时长在每种组合下的均值和中位数。透视结果通常能直接告诉我们,哪些交互项值得进模型,哪些其实只是随机波动。这个发现也是后面做特征工程时"时段x天气x阶段"交叉特征的最初来源。

4. 数据理解阶段最容易踩的坑

4.1 缺失值并非随机缺失,直接填充等于抹掉关键时期

比赛数据里的缺失值,往往不是均匀分布在整段时间里的。最常见的模式是:某个站点或区域在某个阶段停止了数据上报,导致那个时间段、那个区域的记录大量缺失;或者某段时间系统压力大,部分字段没有写入。如果直接在全局做均值填充或删除缺失行,等于把疫情阶段最特殊的分布变化全部抹平了。

正确的做法是先看缺失值的时间分布和空间分布。我常用两幅图:按天统计缺失率的热力图、按区域统计缺失率的条形图。如果缺失明显集中在某个时间段,那这个时间段的样本应该特殊处理,要么单独标记缺失来源,要么把"该区域该时间是否有数据"作为一个特征。至少在数据理解阶段的结论里,要把这种缺失模式写进字段字典,防止后续特征工程无意识地污染样本。

4.2 标签泄漏:用到了"未来信息"而不自知

行为预估类比赛里,标签泄漏是非常隐蔽、又杀伤力极大的问题。常见的情况是:预测目标是"骑士是否会接某订单",但特征工程时不小心加入了"该订单是否在后续被完成"、"完成后的配送时长"这类事后变量。这类特征在训练集上效果特别好,验证集也正常,但到了真正预测未来时全是空的,分数直接崩盘。

数据理解阶段就要建立"可用时间"的概念:每看到一个字段,都要问一句,在预测时点那一刻,这个值能不能拿到。不能拿到的,不管在训练集里多有用,都必须在特征列表里标红。我在字段字典里专门有"可用时间"和"是否可能泄漏"两列,每次新增候选特征都要填。这个习惯帮我避免了至少三次线下分数虚高的假象。

4.3 订单量统计口径混用:下单时间还是完成时间

订单量的时间序列,用"下单时间"统计和用"完成时间"统计,走势在平稳期几乎一样,但在疫情这种剧烈波动期会出现明显错位。比如午高峰下单的订单,因为配送变慢,完成时间被拖到下午,如果特征和标签一个用下单时间对齐、另一个用完成时间对齐,衔接处就会出现系统性偏差。

我的建议是在数据理解阶段就统一全局口径:特征、样本、标签的时间对齐方式必须在同一份文档里写明,并写进特征字典,防止后面写着写着混掉。特别是做滑窗统计特征时,得明确"过去一小时订单量"里的时间戳到底是下单时间还是完成时间,这个不统一,窗口特征就全乱了。

4.4 对比基期选错,后期评估全乱套

做特征效果对比或模型评估时,很多人随手选一个时间段当基期。在平稳业务里问题不大,但在分段式变化强烈的数据里,基期选错会让整个评估失真。比如拿疫情高峰期作为验证集窗口,和拿恢复期作为验证集窗口,同一个特征的增益可能一个为正、一个为负。

数据理解阶段的产出里应该有一份"时间窗口划分方案",明确训练窗口、验证窗口、测试窗口各自覆盖哪个时间段,并说清楚为什么这么切。通常的原则是:训练集必须包含完整的阶段变化信息,验证集要模拟模型真实部署时的未来场景,最好使用时间靠后的数据。这个方案在后续所有迭代中应该保持相对稳定,否则不同版本的实验结果之间完全不可比。

4.5 把聚合特征直接落下,忽略分布变化

最后一个坑相对隐蔽。很多人做统计特征时,直接算"过去N天的平均配送时长",但均值在非平稳分布下会被长尾严重拉偏。疫情阶段配送时长分布整体右移,均值和中位数的差距变得很大,只用一个均值会丢失大量信息。

我后期做统计特征时会刻意加入分布类特征,比如P50、P90、P95、标准差等。这个习惯就是在数据理解阶段看到配送时长分布变化之后形成的。可以说,数据理解看得越细,特征工程反而越不容易做极端——你会自然地知道哪些统计量稳健、哪些统计量会被长尾影响。

5. 从数据理解到特征工程:这一步怎么衔接

5.1 先沉淀一份特征字典

数据理解阶段产出的字段字典,到了特征工程阶段会自然演化为特征字典。每一行记录一个候选特征:特征名、特征含义、数据类型、取值范围、缺失率、可用时间、是否可能泄漏、在哪个样本粒度上计算。

写这个字典的过程很枯燥,但它是整个项目里性价比最高的文档之一。我平时做特征的时候,会先查这个字典,确认"这个特征是不是已经有人做过了"、"这个特征的统计粒度是什么",能避免大量重复劳动。很多时候,团队里几个并行的人各做各的特征,最后合并时才发现两个人做了同一件事,原因就是没有共用一份字典。如果是一个人单打独斗,字典也能帮你记起"这个特征我当初为什么做了一半就停了"。

5.2 滑窗统计特征:窗口大小由业务节奏决定

行为预估任务里最常用的一类特征是滑窗统计特征:过去1小时接单量、过去3小时配送时长均值、过去24小时取消率等。窗口大小的选择不能拍脑袋,而是看业务变化的节奏。

从数据理解部分我们已经知道,疫情期间骑士行为在小时级别就有明显波动,所以短窗口特征(1小时、3小时)往往比长窗口特征(7天)更有区分度。窗口太长,特征值会被往中间值拖,等于平滑掉了这段时期最有价值的波动信号。当然,长窗口也不是完全没用,它更多表达的是骑士的历史稳定水平,适合拿来和短窗口特征做差值,形成"当前偏差"类特征,比如"过去1小时接单量比近7天同时段均值高了多少"。这类特征把"异常程度"直接量化,模型很容易学到环境突变的影响。

5.3 把业务规则量化为特征

数据理解阶段得出的业务判断,几乎都能量化为特征。举几个例子:如果发现某区域订单量出现异常下降,可以计算"该骑士所在区域过去1小时订单量比过去7天同一时刻均值下降了百分之多少";如果发现骑士接单响应时间拉长,可以做"骑士最近3次接单响应时间的均值相较于历史均值的偏移量"。

这类"偏离度"特征,本质上就是把业务规则翻译成模型能理解的语言。而翻译的素材,恰恰来自数据理解阶段那些看起来只是"随便看看"的分析。这也是为什么我一直强调数据理解不是走流程,因为它本身就是特征工程的上游。数据理解时画过的每一张分布图、每一张透视表,都能在特征设计时找到对应的衍生方向。

5.4 用简单模型验证数据理解的假设

数据理解阶段最后一步,我会用一套最简单的特征快速跑一个LightGBM,目标不是拿分,而是验证前面的判断:阶段标签特征到底贡献了多少增益、短窗口特征是否真的比长窗口强、哪些交叉特征值得保留。

具体做法是固定相同的参数和训练集,做特征消融对比:带阶段标签 vs 不带阶段标签、带短窗口特征 vs 只带长窗口特征、带交互特征 vs 不带交互特征。每组的AUC或对数损失差异,就是数据理解阶段这些假设的最好验证。如果验证结果和预期不一致,通常说明某个环节的数据理解还有遗漏,需要回到前面重新检查。这一步看着简单,却是把数据理解与实际建模效果打通的关键节点,很多队伍在这里才发现自己前期判断里有几个明显偏差。

这个比赛最花时间的地方,往往不在模型精调,而在数据理解阶段的耐心。我个人的做法是,这一阶段至少留出完整的两到三天,不急着写模型,而是把样本口径、字段字典、阶段划分、风险点全部钉死。后面每一轮特征迭代,都会发现这部分时间花得物超所值。等回头再看,你会发现数据理解做得好不好,不是当时看出来的,而是等你发现自己在特征工程阶段返工最少的时候,才后知后觉地意识到它的价值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询