当时手头接到这个任务的时候说实话我心里是有预期的——疫情预测这事儿看着是数据科学问题真做起来会发现它是个从数据到业务再到人性的综合性难题。同名项目网上不少但很多止步于“套一个LSTM画个拟合图”。这篇我就把这段实操里真正卡过壳、踩过坑、最后跑通的东西掰开揉碎讲清楚从特征构造到模型融合再到结果落地尽量让后面接手的人少走弯路。适合谁看两类人一是刚入门想用机器学习做时间序列预测的同学可以当完整案例参考二是已经在做传染病或公共卫生数据建模的从业者里面有些细节比如统计口径切换、模型漂移是实战里最容易栽跟头的地方。1. 整体设计思路与方案选型这个项目的核心难点不是“用什么模型”而是“预测任务本身要怎么定义”。我刚接手的时候看了网上不少公开方案大部分是端到端直接扔给神经网络去学习原始序列。这类做法有两个绕不开的问题第一疫情数据本质上是一个被强力干预过的非平稳过程第二单点预测在业务上几乎没有决策价值。所以我把项目拆成了两条主线来设计一条是数据主线另一条是任务主线。数据主线的核心是“多源数据汇聚与清洗”。光有确诊数是不够的还要考虑检测量变化、人口流动趋势、防控措施的等级调整、天气因素对呼吸道传染病来说温度和湿度确实有影响这些数据源的量纲不一样、发布频率不一样、统计口径还会变汇聚阶段就得做大量对齐和归一化工作。任务主线的核心是把“预测未来确诊数”拆成“预测新增趋势 预测拐点概率”两个子任务。为什么这么拆因为新增确诊数本质上是“基数×传染率×易感人群接触概率”的乘积结果直接回归这个乘积模型很难学到因果结构。分而治之以后趋势模型负责主路径拐点概率模型负责修正和告警两路汇合后再做集成整个系统的解释性和稳定性都会好很多。模型选型上我走过一段弯路。最开始想直接上Transformer后来冷静下来一想样本量根本不够。疫情有效训练窗口也就几百天天气和出行数据更短Transformer这类大参数模型在这个数据规模下纯粹过拟合。最终我确定了“多模型并行的轻量架构”Prophet负责趋势分解LSTM负责短期波动拟合XGBoost负责非线性特征交叉和拐点判断。三个模型各自独立结果再做加权融合。提示模型选型之前先搞清楚你的样本量上限是多少。深度学习不是万能钥匙小样本场景下集成树和结构化时序模型往往更稳。这个决策的核心逻辑是三个模型各有盲区但它们盲区重叠的部分很少。Prophet对假期效应和周期性变化敏感但不擅长学习多变量交叉LSTM能捕捉短期动态依赖但在长周期预测上会衰减XGBoost可以吃进大量外部特征做非线性组合但对时间顺序不敏感。互补性好的模型做集成提升不是“锦上添花”而是“缺谁都不行”。2. 数据处理与特征工程的关键环节2.1 数据画像你以为的“完整数据”其实千疮百孔先说数据预处理因为这里面的坑比建模还多。项目刚开始时我们拿到的确诊数据在三个渠道上对同一时间段的数据就对不上原因不复杂——统计口径调整、病例归属地重新划分、无症状感染者的纳入标准在不同阶段发生过变化。我的处理方案是建立一个“口径变更表”把每次统计标准调整的时间节点和影响幅度记录下来在做序列切分的时候保证每段数据内部口径一致。具体做法是以当前口径为基准对历史序列做修正而不是直接拼接原始值。这一步做完后模型预测的稳定性提升非常明显。另一个容易被忽视的点是“数据发布延迟”。确诊数据公布的是前一天甚至前两天的情况也就是说你拿到的“今天”数据展现的其实是过去48小时之前的现实。在做特征切分时必须把特征时间点和标签时间点严格错开否则就是在用现在预测过去训练评估做好看但上线就崩。数据对齐这块我用了两级策略日期对齐以报告日期为准统一所有序列的日期索引事件对齐将防控措施、假期、大规模检测活动等“事件”作为额外维度写入特征这两招搞定之后再去看数据很多伪相关就自动消失了。2.2 特征工程的三个思路滞后、窗口与外部协变量特征这块我主要围绕三个思路展开。第一个是滞后特征。疫情传播有潜伏期今天的确诊数通常与5到14天前的接触行为高度相关。构造滞后特征时不是简单取前一天的数值而是综合过去3天、7天、14天的滑动统计量这样才能体现“潜伏期内积累效应”的时间尺度。第二个是窗口统计特征。用一个滑动窗口计算近期确诊数的均值、方差、一阶差分峰值。这些特征的意义在于刻画传播速度的变化率。如果单日新增还是上升但7日均值已经走平说明增长势头在减弱这类特征对拐点判断特别有用。窗口长度我最终选定了7天和14天两组7天捕捉周内节奏14天覆盖两个完整潜伏期效果比单一窗口好得多。第三个是外部协变量。天气数据我取了温度、相对湿度和昼夜温差人口流动数据取了城市内出行指数和跨城流动强度防控措施按照实施等级做了有序编码。这些协变量不是直接喂给模型而是先做交叉验证筛选只有单变量AUC大于某阈值才保留目的是防止无关变量稀释深度学习模型的收敛效率。注意外部协变量有一个共同的坑——你只能拿到历史数据做未来预测时这些变量本身就是未知的。我当时的做法是先用Prophet对这些协变量做二期预测生成“预测值误差带”再传给下游模型。误差会累积所以预测周期超过14天后协变量的权重需要做衰减补偿。2.3 标签构造与数据泄漏让模型学会“预测未来”标签构造是整个数据处理阶段最容易被小看的环节。预测目标是未来3天、7天、14天的新增确诊数那标签就不能用当天的数值。我用的是“t日预测tn日”这样构造的Label天然规避了数据泄漏因为预测时用到的全部特征都截止于t日。数据泄漏这个问题我必须多说一句。公开数据集经常有人用同一时段的数据既做特征又做标签训练时精度极高一上真实数据就拉垮。我在代码里专门写了一个验证函数扫描所有特征列与目标列的滞后关系一旦发现特征里包含未来信息的列就自动丢弃或后移。这个函数帮我抓出了至少三个隐藏泄漏点其中一个来自我自己的粗心——不小心把“未来一周的假期计划”直接编码进了特征矩阵。另一个非常重要的细节是负值截断。预测模型在没有约束的情况下可能输出负的确诊数这在数学上合理但在业务上荒谬。我在最终输出层接入了一个ReLU约束函数低于零的预测值会被置零并对这个样本提高惩罚权重。效果是预测分布整体右移均值预测更接近真实趋势。2.4 数据集的划分策略与验证方式时间序列的数据划分和普通机器学习不一样不能随机打散。我采用的是“滚动向前验证”策略训练集前60%时间窗口验证集接下来20%测试集最后20%验证方式上我跑了一个“扩窗回测”从第100天开始每5天重新训练一次、预测未来14天一直推到数据末尾。这样得到的多组重叠预测序列既能评估模型在不同阶段的表现又能用来做集成时的置信区间估计。划完数据我算了一笔账如果只用一次切分模型很容易被某一段特殊时段的“异常模式”带偏。扩窗回测让每个时段都有机会成为验证集这在疫情这种非平稳环境里几乎是必须的。3. 模型解析与训练策略3.1 基线模型先搞明白“傻办法”能到多少分做复杂模型之前我建议所有人先跑通两个基线一是历史均值法拿过去14天均值当作未来预测二是季节朴素法拿去年同期或上一个周期同时段的数值直接套用。这两个基线看起来“傻”但它们能告诉你这个预测问题的下界在哪里。实测结果很有意思在疫情平稳期历史均值法的表现几乎和LSTM持平在特定周内甚至更好。但一旦进入趋势突变段历史均值法的误差立刻飙升到LSTM的3倍以上。这说明什么说明短期数据平稳时复杂模型学到的“规律”很可能只是平均效应只有数据分布剧烈变化时模型的非线性特征才真正发挥作用。基线结果出来之后我有一个原则任何新模型如果不能在三个指标MAE、方向准确率、P50预测区间覆盖上全面超越基线就降级为候选模型。这个门槛帮我砍掉了好几个花哨但没用的尝试包括一个效果“看起来不错”但实际上只是运气好的随机森林版本。3.2 Prophet趋势分解与假期效应Prophet在这个项目里的定位是“长期趋势基线”。它的核心价值在于把时间序列分解为趋势项、季节项和事件项这个分解过程天然对突发事件有容忍度。实战配置上我做了三处自定义一是将疫情“防控措施升级”这一类事件添加到节假日列表里让模型为每一次强力干预学习一个独立的影响系数二是关闭了默认的周季节性原因是疫情数据的周周期性远不如零售数据的周周期明显三是开启了不确定区间估计用它的置信区间作为后续模型融合的权重参考。Prophet最有用的输出不是预测值本身而是“趋势分量的斜率变化”。当斜率从陡峭转为平缓并且持续了3天以上大概率说明干预措施开始生效。这个输出后来直接作为拐点概率模型的一个高权重特征。3.3 LSTM短期波动与序列依赖LSTM在这个项目里负责的是“未来7天内的波动轨迹预测”。我设计了一个三层结构输入层接收32维特征序列中间是两层各64单元的LSTM最后接一个全连接层输出未来7天的预测序列。训练策略上用了分段的Teacher Forcing——训练时按60%概率使用真实历史值作为下一步输入其余40%使用上一步模型的预测值。这样模型在推理阶段面对“自己生成的历史”时不会剧烈漂移。很多人在小样本时序任务里忽略了这个细节直接导致训练损失和推理损失之间有巨大鸿沟。另一个关键参数是序列长度。我对比过7天、14天、21天三种输入窗口最终用14天。因为7天窗口捕获不到完整的潜伏期效应21天窗口会让早期数据点与预测点的相关性衰减到几乎为零。14天恰好是两个潜伏期既包含了近期最新动态又不至于引入过量历史噪声。3.4 XGBoost特征交叉与拐点概率建模XGBoost在两个阶段被使用。第一阶段是特征筛选器。我用它对全部候选特征做重要性排序然后按照累计重要性保留前80%的特征子集供LSTM和融合模型使用。第二阶段是拐点概率模型。任务定义是以未来14天内是否存在“新增确诊连续下降3天”的拐点为标签做二分类。特征包括Prophet趋势斜率、近3日一阶差分的均值、检测阳性率变化方向、节假日影响系数等。输出是一个0到1的概率值代表拐点出现的可能性。这个概率值不直接参与数值预测而是用来动态调整融合权重。当拐点概率小于0.3时说明模型认为趋势将持续这时给Prophet趋势项更高的权重当拐点概率高于0.7时说明模型认为趋势正在转向这时给LSTM更高权重因为LSTM对近期拐点更敏感。3.5 集成策略谁靠谱谁说了算融合权重不是拍脑袋定的我设计了一个“误差历史加权法”维护每种模型在最近30天内的滚动MAE权重与历史MAE成反比。公式上是权重_i (1 / MAE_i) / Σ(1 / MAE_j)这样做的好处是模型的权重会随自身表现动态变化模型在某段时间失灵权重自动下降不需要人工干预。除了加权平均我还保留了一个“异常剪裁”逻辑当三个模型的预测结果两两之间差异超过30%时不直接融合而是取预测值的中位数并扩大置信区间。实战效果说明这个逻辑很靠谱因为大分歧往往发生在数据剧烈变化时此时任何单一模型都不可信取中位数比均值更能抵抗极端偏差。提示集成不是为了“看起来高级”而是为了在模型犯错时还能兜底。如果你只有一个模型那个模型错的时候你就全盘皆输集成的价值本质上买的是“容错保险”。4. 评估与结果分析4.1 评估指标不要只用MAE走路我用了五个指标做综合评估MAE平均绝对误差RMSE均方根误差MAPE平均绝对百分比误差方向准确率预测涨跌方向和真实方向的一致性P50区间覆盖率真实值落在50%置信区间内的比例为什么不全依赖MAE因为MAE对称看待高估和低估但在公共卫生决策里低估的代价远高于高估。一个延迟发现的大规模传播事件成本和一次过度警惕不在一个量级。方向准确率就是用来专门监控这个问题的如果模型的数值误差很小但方向经常反说明模型捕捉的可能是均值而不是动因。采用扩窗回测得到的测试集结果3日预测平均MAE低于基线约42%方向准确率在81%上下7日预测MAE低于基线约35%方向准确率降到76%14日预测MAE优势只剩15%方向准确率降到68%。这个下降趋势完全符合预期——预测期限拉长事件扰动的影响成倍放大任何模型都无法保证长周期精准。4.2 误差结构分析模型在什么时候失灵对误差做分段分析后发现了一个重要事实模型的误差不是均匀分布的而是集中在“趋势突变后的第一周”。具体表现为当一次强力干预措施出台后模型往往需要5到7天才能“反应过来”。这不能全怪模型因为数据层面确实存在发布延迟干预效果需要经过一个潜伏期才会显现在确诊数字上。但模型可以做得更好的地方是在干预强度特征发生明显跳变时主动提高预测结果的方差而不是死守一个确定性输出。我在融合层加了一个“波动放大器”当拐点概率介于0.4到0.6之间方向不明确时置信区间整体扩宽20%。这意味着预测系统在不确定时刻明确告诉你“我不确定”而不是给出一个虚假的精确值。对于决策者来说一个诚实的误差带比一个撒谎的精确值有价值得多。4.3 与公开方案对比多出来的那点分在哪儿项目后期我们和公开报告做了复盘对比有两点优势值得讨论。一是特征工程带来的差异。公开方案常用单一的滞后序列作为输入我们加入了事件变量和流动变量让小样本数据的信息密度提高了。二是模型融合带来的差异。公开方案多用单模型端到端预测我们用了“趋势分解短期波动拐点概率”的组合架构本质上把问题拆成了可解释的子任务每个子任务都能用不复杂的模型解决整体自然更稳定。不过也要承认我们的方案代价是工程复杂度更高、维护成本更大单模型方案部署起来毕竟省事。如果只是做一个教学Demo撑到“出一个预测曲线”这一步就够了但如果要真正支持决策拆分成子任务几乎不可省。5. 常见问题与排查实录5.1 翻车现场训练集表现极好测试集一塌糊涂这个问题的根源90%是数据泄漏。我当时第一次做扩窗回测就撞上了训练集MAE做到个位数测试集误差直接翻倍。排查思路是逐层检查特征列最终锁定在一个“全国累计确诊数”的特征上——它包含了未来信息因为累计值天生就是“过去现在”的和预测未来新增时不能用同一时刻的累计值。排查技巧将训练集时间列中心化后重训模型然后分别检查特征与标签的滞后相关性。任何相关系数大于0.9的特征都需要重新审视是否包含未来信息。5.2 归一化失效新增确诊数突然跳了两个数量级这是疫情数据里最特殊的难题之一。常规归一化MinMax或Z-score在数据平稳时工作正常但当统计口径调整或爆发期到来时新数据的值域会完全超出训练时的归一化边界导致所有后续特征全部失真。我的解决方案是采用“分位数裁剪 稳健缩放”将上下限设为训练集的2%分位数和98%分位数超过极限值的点单独标记为异常特征再扩缩到合理区间。这样模型不会因为一两个极端值把整体学习带偏。5.3 预测结果总有系统性滞后如果你发现预测曲线总是比真实曲线慢半拍几乎可以确定是特征构造有问题。滞后特征在时间上天然是“向后看”的模型能学到的上限就是你给它输入里包含的最新信息期。我当时的做法是增加“Delta特征”不再只看确诊数的绝对值而是同时输入一阶差分和二阶差分。差分特征能让模型直接感知变化率的加速度对于拐点的捕捉比绝对值快一天半左右。做了这个改动后7日预测的方向准确率上升了约6个百分点。5.4 模型漂移上线运行一个月后越来越不准静态模型在持续运行中退化几乎是必然的因为人群行为、病毒特性、检测策略都在变化。我做了一个“逐月重训”的自动流程每月第一天用最近90天数据重新训练全部模型并重新计算融合权重。同时设置了一个“漂移警报”如果连续7天的方向准确率低于60%就触发紧急重训。这个机制运行以后项目的长期维护成本大幅度下降。机器学习的模型维护从来不是上线就结束而是一个持续迭代的过程忽略这个事实的项目工期再长也白搭。6. 复盘与延伸思考这个项目做到尾声我对“预测模型”这件事的理解改变了不少。最开始我以为是纯技术问题多上模型、多调参、多叠特征就行。做到后面才发现真正决定预测价值的不是模型的准确率而是预测结果能不能被决策者信任和使用。这时候才有体会疫情期间各种预测数字满天飞闹剧频出的原因往往不是模型不够好而是大家只想要一个“答案”没人愿意要一个“概率分布”。但现实世界的预测从来不是掷出一个确定的结果而是一个不断随新信息更新的概率空间。这套系统能做到的最有价值的事就是在拐点到来前三天给出“可能发生转向”的信号并且明确告诉使用者这个判断的置信度是多少。最后分享一个经验疫情预测这类问题与其追求绝对数值的准确不如在“趋势方向判断”和“不确定性量化”上多下功夫。一个自带误差带的方向判断胜过一个虚假精确的数值。这个思路后来我也用在了别的时序预测项目上效果都说得过去算是这次磕磕绊绊攒下来的真东西了。