资讯详情

机器学习驱动的流行病学预测:从SEIR到混合建模实战

📅 2026/10/20 5:27:47 | 华诺云谱 👁 阅读
机器学习驱动的流行病学预测:从SEIR到混合建模实战
2020年那个冬天几乎所有做传染病建模的人都在面对同一个问题病毒传播的速度到底能不能被提前算出来机器学习从业者第一次感受到流行病学预测模型不是教科书里那种“跑通一个模型就算交差”的练习而是要在每一天变化的数据、不断调整的防控手段、滞后而残缺的报告口径里用尽可能多的信号拼出一张未来几周的图景。这篇文章我想把这套东西拆开讲清楚——从问题定义、数据处理、模型选型到部署和踩坑基于我个人做类似项目的完整思路来复盘适合正在入门智慧医疗方向、或者想把时序预测项目落到真实场景中的同学参考。题目虽然是“第1章”但内容足够支撑你从零搭建一个可用的预测闭环。1. 先把问题定义清楚这不是普通的时序预测1.1 流行病学预测到底在预测什么很多人一上来就急着选模型这是最大的误区。做普通的时间序列预测比如电商销量、服务器负载目标通常是“未来的数值是多少”。但流行病学预测面对的是传染病在人群中的传播过程它输出的远不止一条病例曲线还应当包括几个关键问题未来一周或两周内每日新发病例会落在什么区间当前传播是否在加速还是减速——这对应有效再生数的变化趋势医疗系统在未来会承受多大的住院和重症压力。不同的目标对应完全不同的建模方案。如果只需要预测病例数可以用纯粹的机器学习时序模型如果需要解释传播动力学、估计干预措施的效果就必须引入仓室模型的结构化假设。开篇第一件事是明确你的服务对象是谁。如果模型要服务公共卫生决策需要的不是黑盒的精确数字而是“在乐观/悲观情景下的范围”如果模型要服务于医院内部的床位和物资调度需要的又是另一种粒度的住院率预测。定义不清楚后面全部白做。1.2 传统仓室模型和机器学习各自的边界传统流行病学建模的主角是SIR、SEIR这类仓室模型。把人群划分成易感者(S)、潜伏者(E)、感染者(I)、康复者(R)用常微分方程描述状态之间的流转。这类模型的最大优势是“可解释”——每个参数都有生物学或流行病学含义模型的曲线可以直接对应到传播过程。但它的痛点也恰恰在此假设传播率β、康复率γ在模拟周期内是常数这在真实疫情中几乎不成立。人群防护意识在变化、病毒变异导致传播力改变、不同阶段检测能力也在变所有这些都会导致参数漂移。机器学习模型的优势正好互补。它不要求你事先假设传播机制而是从大量历史特征中自动学习“哪些因素会推高病例数”。但纯机器学习也有盲区它很难外推到训练数据中没有见过的疫情阶段。比如一个城市此前每日新增从未超过一千模型预测两万例时的行为就会非常不稳定。所以早期我调研这类项目时得到的重要结论是不要站队做混合。用SEIR的框架提供动力学约束用机器学习拟合时变参数或直接做残差修正。这是后面整个方案的核心基调也建议大家把思路从“哪个模型更强”切换成“如何把两种建模哲学组合起来”。2. 数据准备脏活儿累活儿都在这一层2.1 需要哪些数据源以及从哪里找流行病学预测的第一步永远是数据盘点。我从实际项目里总结出的数据分层大概是这样的核心流行病学数据每日新增本地确诊、无症状感染者、现有住院人数、重症人数、累计治愈和死亡。这些是模型的主序列通常来自各地卫健委发布的通报再按天归一成结构化表格。人口和社会特征地区常住人口、人口密度、年龄结构因为不同年龄段的感染风险和重症率差异很大、城市化率。人群移动数据跨城市迁徙强度、市内公共交通客流量、地铁拥挤度、热点区域人流指数。在传染病模型里人口流动直接影响传播范围的扩散速度是特征体系中非常重要的一类。防疫干预数据核酸检测范围与频次、隔离政策的起止时间、公共场所关闭状态、口罩佩戴率。这些可以用哑变量、等级评分或者“距离政策开始的天数”来刻画。外部环境数据气温、相对湿度、日照时长。很多呼吸道病毒的传播效率有季节性把温度湿度放进特征工程往往能明显提升模型在跨季节预测时的表现。需要说明的是部分数据存在隐私合规和可获得性问题比如手机信令原始数据就不是普通团队能直接拿到的。实际落地时常用公开的迁徙指数替代或者用流量占比这类聚合脱敏数据。这并不影响思路关键是清楚数据背后的含义——指数上升30%到底对应多少人员流动需要在特征编码时备注清楚。2.2 病例数落后于感染数的“报告延迟”陷阱做流行病学数据清洗时最容易踩的一个坑是“报告的今天”不等于“发生的今天”。每天公布的病例数实际上是在一个时间跨度内陆续完成检测并确诊的个案。潜伏期平均三到七天的特性决定了今天的新增确诊很大概率是三到五天前被感染的人群。真正的感染时间曲线和报告曲线之间存在一个系统性平移而报告本身还会因为检测能力、送检流程甚至节假日而抖动。处理办法有几类。最朴素的是在特征里加入滞后窗口——用过去三到七天的病例数预测未来模型自己会学到潜伏期造成的时间平移。更严格的做法是用“发病日期”而不是“报告日期”来重构序列但这需要病例级别的流调数据很多场景拿不到。还有一种方法是做延迟分布反卷积假设从感染到确诊的延迟服从某个分布用当前报告数据反推真实的感染曲线。这个方法学术上很成熟但实现起来要对边界和尾部做很多稳健性处理我当时是在第二阶段才引入的初期没必要做这么重。2.3 特征工程的几个关键操作特征工程是这类项目性价比最高的一环。我把自己的通用做法按优先级排序给你第一优先级是滞后特征和目标统计。预测未来七天的每日新增病例至少要构造过去1/3/7/14天的病例数过去7天病例数的移动均值、标准差、峰值过去7天环比变化率以及“最近一天较七天平均值”的偏差。这些特征本质上是在告诉模型当前的传播处在什么趋势阶段。第二优先级是比例特征。单纯看病例绝对值容易被检测量影响。比如一个城市突然开展大规模核酸筛查一天查出几千存量病例这不代表疫情在加速只是“把账算清了”。所以建议构造阳性率阳性检出数/检测人数和检测量本身让模型能区分“传播加速”与“检测加强”两种情况。另外无症状感染者与确诊的比例在不同阶段也很有信息量。第三优先级是外部特征。把移动指数、政策等级、气象变量直接作为普通特征输入或者构造一些交叉特征比如“病例上升期叠加管控收紧”这样的交互项。树模型对这类交叉特征很敏感值得多尝试。2.4 数据清洗中的常见脏数据问题实际清洗时的情况比论文里描述的复杂得多。比如历史数据被修订——某天公布的累计数后面又被修正我们到底该用哪个版本作为训练标签我的建议是记录每一次数据修订训练和评估使用同一套“数据发布当时可见”的快照而不是事后修正版。否则模型在回测时会看到未来信息上线后的表现会比回测差很多。这就是“前视偏差”的典型例子很多人一开始没在意结果模型上线第一周就翻车。另一个典型问题是节假日效应。春节期间检测点放假、人员流动结构完全改变每日新增病例数会短暂失真是很正常的事。如果不加处理模型会把这几天当成异常样本硬学出一个错误的模式。经验做法是引入节假日哑变量或者把节假日当天的目标值做一个“不做特别学习”的标记让模型保持对常态分布的拟合。缺失值处理也要按时间序列的方式——前向填充优先于全局均值填充因为后者会抹掉趋势信息。3. 模型选型与核心原理从SEIR到深度学习3.1 SEIR仓室模型的核心公式与参数含义SEIR四个字母对应易感者(Susceptible)、潜伏者(Exposed)、感染者(Infectious)、康复者(Removed或Recovered)。整个模型可以写成一组离散递推方程。离散形式在编程时更直观我习惯把时间步设为一天每天做一次状态转移$$S_{t1} S_t - \frac{\beta S_t I_t}{N_c}$$$$E_{t1} E_t \frac{\beta S_t I_t}{N_c} - \sigma E_t$$$$I_{t1} I_t \sigma E_t - \gamma I_t$$$$R_{t1} R_t \gamma I_t$$这里的β是每日每个感染者的有效接触传染率σ是潜伏期倒数的进展速率γ是康复速率。基本再生数R0由β/γ近似得到代表一个感染者平均传染多少人。实际应用中市民不会把N_c理解成全部人口而应该理解成“当前有效易感人群规模”尤其是疫苗接种和既往感染后易感池会变小。把这几个状态变量映射到卫健委的公开数字时I对应“目前在院治疗”R对应“累计治愈死亡”E没有直接观测值只能间接估计这正是后来用机器学习去拟合的切入点。3.2 为什么纯SEIR不够用参数是时变的如果你用真实疫情数据去拟合一个恒定参数的SEIR几乎一定失败。因为β本质上不是常数而是和人群戴口罩比例、聚集性活动强度、封控时间、病毒变异情况都相关的时变函数。政策一调整β立刻变化而模型的常微分方程不会自己知道这件事。解决办法有两种路线。经典路线是“分段估计”——划分时间段在每个阶段重新拟合参数这是一些研究团队的常用做法简单易行但分段边界怎么定有很多主观性。机器学习路线是“用神经网络表达β(t)”。具体思路是构造一个小的神经网络把当前各项干预指标、移动指数、季节因素作为输入输出每天的β值再把这个β代入SEIR递推方程用真实病例序列作为标签端到端反传训练。这样既保留了SEIR的动力学结构又能让参数随外部环境变化。这也是我见过最成功的混合建模方式之一目前已经有若干开源库支持这类“神经网络增强仓室模型”降低了自造轮子的难度。3.3 循序渐进Prophet变体 → 树模型 → LSTM如果从零开始落地不建议直接挑战神经微分方程。我建议的推进路线是按模型复杂度递增每一步都做好评估再往前走。第一步用Prophet做基线和数据诊断。Prophet的本质是加法趋势分解把序列拆成趋势项、季节项、节假日项。它最大的价值不在于预测精度而在于快速帮你看清数据里有哪些异常点、趋势拐点在哪、星期效应有多强。这一步通常两天就能跑完足以评估数据有没有硬伤。第二步用XGBoost/LightGBM加滞后特征。树模型在结构化特征场景下表现稳健不需要归一化能自动处理特征交互训练过程也容易调试。把滞后病例数、外部特征、日历特征全部堆进去用时间序列交叉验证评估通常能拿到一个不错的baseline。第三步才是LSTM或Transformer类模型。循环网络可以同时拿“病例序列”和“外部特征序列”作为输入输出未来七天的预测。它的优势是能捕捉长距离依赖但也更容易在小样本场景下过拟合。CNN或Transformer模型如Informer也可以做序列预测但在历史数据长度有限比如只有一两年时规模收敛反而很慢。训深度学习模型必须配足验证滚动机制绝不能只看训练集损失。3.4 集成与混合建模是提升精度的关键我自己最终落地的版本是“三层结构”。第一层是SEIR动力学模型输出纯粹的机理预测第二层是LightGBM和LSTM分别从表格特征和序列特征出发做统计预测第三层是Stacking把前面所有模型的预测结果和近期误差作为特征再训练一个小模型做权重分配。这样的好处是如果某个阶段政策导致SEIR突然偏离统计模型还能兜底如果数据变化异常导致LSTM发散树模型的稳定输出也能让结果不至于整体崩溃。集成还有一个作用——把多个模型的分位点结果汇总。比如分别用分位数损失训练五个模型再取它们在30%和70%分位点的平均值合成一个“不确定性区间”。这个方法比单独用一个模型预测方差稳健得多尤其是在数据不稳定的场景里。4. 模型评估与验证别被常规交叉验证坑了4.1 时序泄漏随机划分是灾难很多机器学习教程都会教你用train_test_split随机划分训练集测试集但这个操作放在时间序列预测上会直接导致数据泄漏。前一天的数据和后一天的数据在统计学上严重相关——今天大概率会影响明天。随机划分等于把“未来”的信息放进了训练集回测指标会虚高到匪夷所思上线后立刻归零。正确做法是使用时间序列交叉验证比如滚动窗口验证设定训练集为前180天验证集为紧接着的14天然后每7天向前滚动一次重复多次。每一步训练集都会“吸收”之前验证过的数据模拟模型上线后不断用新数据更新的真实过程。观察各次回测结果的误差分布才能准确估计模型在未来的真实表现。4.2 评价指标的选择MAPE会“爆炸”的坑评价指标方面MAE和RMSE是最常见的。但面对流行病学数据MAPE有个很头疼的问题当真实值很小比如只有个位数时任何微小的绝对偏差都会被放大成巨大的百分比误差。疫情早期的几例和十几例之间差出100%的百分比变化这对评估毫无意义。我的建议是优先用WAPE加权绝对百分比误差或SMAPE既保留了百分比口径的可解释性又不会被零值附近的噪声主导。医疗场景还需要关注“预测区间覆盖率”。每天的预测应当给出一个区间比如“下周每日新增预计在1200到1800之间”如果实际值落在区间外的频率超过了设定概率说明模型的高斯假设或分位数估计有问题。公共卫生决策者宁可要一个略宽但可靠的区间也不要一个精准但经常脱靶的点预测。这也是我在汇报口径上做了一次重要转变从报“点值”改成报“区间置信度”。4.3 多步前向预测的评估策略预测未来1天容易预测未来7天或14天才是真实需求。这里有个细节不要只评估“第7天的预测值”和真实值的差距而要评估整个轨迹的开销。我通常的做法是从第T天出发预测T1到T7共7个点然后逐天统计误差随提前期的变化曲线。通常第1天误差最小第5到第7天误差迅速膨胀——这是正常的因为不确定性随提前期递增。如果模型到第5天后误差突然爆炸而非渐进上升往往说明训练数据中存在前视泄漏或预测被推到训练集分布之外。另外这类任务适合用“分阶段评估”把疫情划分为上升期、平台期、回落期三个不同阶段分别评估。一个在上升期表现好的模型在平台期可能完全失效因为平台期的信号更弱、信噪比更低。把模型的表现拆细到这个程度才能准确判断它到底还能不能上线。5. 实操过程从特征库到部署的完整链路5.1 特征库与训练数据的标准结构数据工程层面建议把所有原始数据先整理成统一列名日期、地区、指标名、指标值。然后再通过pivot转成一个“日期×地区×特征”的宽表。我通常把特征分成三层前缀epi_、mob_、env_代表流行病学、移动性、环境三类。这样看一眼列名就知道特征来源模型调试时定位问题会很快。下面是一个简化的训练样本构建示意伪代码import pandas as pd # 假设 daily_wide 结构: [date, region, new_confirmed, mobility_index, temperature, policy_level, ...] df daily_wide.sort_values([region, date]).copy() # 基础滞后特征 for lag in [1, 3, 7, 14]: df[fepi_lag_{lag}] df.groupby(region)[new_confirmed].shift(lag) # 移动平均比率特征 df[epi_ma7] df.groupby(region)[new_confirmed].transform(lambda x: x.rolling(7, min_periods1).mean()) df[epi_ratio_1_7] df[epi_lag_1] / (df[epi_ma7] 1) # 日历特征 df[weekday] df[date].dt.weekday df[is_holiday] df[date].dt.date.isin(holiday_dates).astype(int) # 预测目标未来7天累计新增或逐日新增 for h in range(1, 8): df[ftarget_{h}] df.groupby(region)[new_confirmed].transform(lambda x: x.shift(-h))这段代码里有几个细节值得注意。滞后和移动平均的分组必须按地区独立计算不能跨地区滑动。预测目标使用shift(-h)所以最终训练每一行的时候要drop掉包含NaN的行。如果想做“未来七天总和”预测可以再加一列把未来七天累加起来。这个数据结构的最大好处是模型无关——同一份宽表可以同时喂给LightGBM和LSTM只是后者要reshape成序列格式。5.2 LightGBM的时序交叉验证与调参时序场景下我一般不用LightGBM默认的EarlyStopping策略因为默认是随机划分验证集依然会泄漏。正确做法是把验证集按时间切在训练集之后再用早停控制树的数量。import lightgbm as lgb train_df df[df[date] 2022-06-01] valid_df df[(df[date] 2022-06-01) (df[date] 2022-06-15)] feats [c for c in df.columns if c.startswith(epi_) or c.startswith(mob_) or c.startswith(env_)] model lgb.LGBMRegressor( objectivemae, n_estimators2000, learning_rate0.03, num_leaves64, subsample0.8, colsample_bytree0.8, ) model.fit(train_df[feats], train_df[target_1], eval_set[(valid_df[feats], valid_df[target_1])], callbacks[lgb.early_stopping(50, verboseTrue)])参数上objective选“mae”比默认的“mse”更稳健因为流行病学数据里偶尔会有极端值MAE对长尾不敏感。学习率设小一点配套更大的树数量是最能稳定出效果的组合。我试过不少数据集后感觉这个项目的调参不需要太花哨按时序验证、按早停、特征工程做扎实效果基本就能稳定在行业可用的水平。5.3 LSTM的输入结构与训练细节LSTM的输入是三维张量样本数, 时间步长, 特征数。假设我们用过去14天的数据预测未来7天构造方法如下import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout SEQ_LEN 14 HORIZON 7 N_FEATURES len(feats) def make_sequences(df, seq_lenSEQ_LEN, horizonHORIZON): xs, ys [], [] data df[feats].values targets df[target_7].values for i in range(len(df) - seq_len - horizon 1): xs.append(data[i : i seq_len]) ys.append(targets[i seq_len horizon - 1]) return np.array(xs), np.array(ys) # 按时间顺序划分 train_seq, train_t make_sequences(df[df[date] 2022-06-01]) valid_seq, valid_t make_sequences(df[(df[date] 2022-06-01) (df[date] 2022-06-15)]) model Sequential([ LSTM(64, return_sequencesTrue, input_shape(SEQ_LEN, N_FEATURES)), Dropout(0.2), LSTM(32), Dense(16, activationrelu), Dense(1), ]) model.compile(optimizeradam, lossmae) model.fit(train_seq, train_t, validation_data(valid_seq, valid_t), epochs50, batch_size32, verbose0)训练LSTM时最需要注意的还是过拟合。流行病学数据一般也就是几百天样本量远比不上自然语言或图像数据所以Dropout一定要用epochs也不宜过多配合早停把验证损失守住。如果验证损失连续几十个epoch不下降就停。归一化方面建议对每个特征分别做MinMax缩放但要注意缩放器的统计量只能从训练集计算不能在整个数据集上计算否则又有前视泄漏。5.4 部署到智慧医疗系统的接口设计模型训好之后工程上要做的是把它包成一个标准的预测服务。我在项目里用的是一个简单但实用的三层接口输入层接收地区编码、当前日期、最近N天历史序列或直接从统一数据平台拉取。模型层加载训练好的LightGBM和LSTM权重从特征库自动构建特征产出多模型预测。输出层返回一个JSON内容包含未来7天每日新增的点预测、80%置信区间、以及一条趋势判断上升/平稳/下降。这块服务不直接参与诊疗决策而是作为公共卫生态势感知模块嵌入到更宽的智慧医疗平台里供医院床位调度、防疫物资储备和疾控分析做参考。从我的经验看输出格式的设计和“给谁看”强相关给决策者看要用摘要和区间图给数据分析师看要给原始数值和置信度给系统对接看要定义清晰的错误码和重试机制。6. 常见问题与排查技巧6.1 预测突然“失灵”先怀疑数据口径再怀疑模型这类项目上线后最常见的故障是连续几天预测值显著偏差。我的排查顺序是固定的先看当天预测输入用的历史数据有没有被修正甚至有没有数据缺失再看是不是有新政策上线导致传播状态突变最后才怀疑模型参数。有一次线上模型某天输出突然翻倍查到最后发现是上游数据同步脚本把另一个城市的数据混进来了。这类问题从特征分布图上往往一眼就能看出来但如果没做监控图排查耗时就会非常长。所以特征分布漂移监控和预测误差监控要一起部署。6.2 节假日导致的预测暴跌/暴涨怎么处理节假日期间新增病例数下降很多时候不是疫情好转而是检测量下降了。模型如果学到“这个日期附近病例下降”等节假日结束后会把反弹预测得过于缓慢或过快。我在实践中是用“节假日检测调整系数”来修正的当检测量低于平时60%时把当天的新增病例按检测缺失比例做一次粗略放大作为特征输入而不是直接改标签。同时在训练时把这几天样本的权重调低不让它们主导模型的趋势判断。6.3 为什么模型在平台期误差特别大平台期的特点是没有强趋势每天病例数在小范围内随机波动。模型如果学习到的是一种趋势外推逻辑在平台期就不知道该往哪个方向拐预测结果容易反复震荡。这类问题的本质不是模型不够强而是信噪比低。应对方法有两个一是降低预测输出的更新频率比如在平台期只做“未来三天稳定”的判断不做逐日精细预测二是在集成模型里增加一个“均值回归”分支专门预测序列会围绕当前水平波动避免整体模型在无趋势阶段乱动。6.4 算出来的有效再生数忽高忽低怎么办有效再生数(Rt)是衡量当前传播能力的重要指标通常用近几日的病例时间序列反推。如果直接用每日病例数做窗口除算出来的Rt噪声会非常大。更稳的做法是先用7日移动平均平滑序列再去做滑动窗口估计或者采用贝叶斯平滑方法。Rt的用途不是看单日数值而是看趋势——连续多日在1以下和连续多日在1以上对应的态势完全不同。当Rt在1附近反复穿越时要提醒使用者“当前处于临界状态任何短期波动都不具备决定性意义”。6.5 需求方觉得预测“不够准”怎么沟通这是比算法更难的问题。非技术决策者经常拿模型和“天气预报”类比觉得不准就没有价值。但流行病学预测的核心价值不在于“算准每一天”而在于“给出不同情景下的准备边界”。在和决策者沟通时我通常把输出改成三个情景低情景感染人数在预测区间下沿可以维持现有资源、中情景在区间中部需要准备一定余量、高情景在上沿需要启动应急储备。把决策动作绑定到情景而不是绑定到具体的数字上模型的实际作用会显著提升。写在最后的经验沉淀做这类跨学科项目我最深的体会是机器学习模型的精度往往取决于你愿不愿意花三倍时间在数据清洗和特征构造上而不是花三倍时间换一个更复杂的神经网络。流行病学预测尤其如此——数据发布的延迟、口径的变化、政策干预带来的结构突变都是模型要吃的“噪音”预处理阶段是否考虑周全直接决定模型上线后的真实表现。如果你打算在这个方向深耕建议从Prophet当基线、树模型做主力、深度学习做辅助的组合入手把监控和评估机制先立起来再逐步把混合建模加进去。这套思路不只适用于病例预测对住院率、重症率、医疗资源占用量的预测同样成立。技术永远是工具真正有价值的是你对问题本身的理解有多深。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑