资讯动态

融合SIR模型与LightGBM的疫情预测:时间序列建模实战

发布时间:2026/8/24 9:31:06 来源:尧图企业网站定制
1. 项目概述当数学模型遇见疫情预测看到这个项目标题估计不少朋友会心一笑或者眉头一皱。没错这又是一个关于新冠疫情的数据建模项目。但别急着划走这个项目远不止是“又一个疫情预测模型”那么简单。它本质上是一个经典的时间序列预测问题融合了传染病动力学模型与现代机器学习方法是数据科学、公共卫生和数学交叉领域一个绝佳的练手案例。无论你是想深入理解传染病传播的底层逻辑还是希望掌握如何用Python将理论模型转化为可运行、可评估的预测工具这个项目都能提供一条清晰的路径。我之所以花时间研究并复现这类项目是因为它麻雀虽小五脏俱全。你需要处理真实世界杂乱的时间序列数据需要理解SIR、SEIR这些经典方程背后的物理意义还需要用Scikit-learn、Statsmodels甚至PyTorch等工具来构建和优化模型。最终你得到的不仅是一串预测数字更是一套应对“具有时空依赖性和外部干预的复杂序列预测问题”的方法论。这套方法论完全可以平移到金融时序预测、设备故障预警、能源需求估算等众多领域。接下来我就把自己在复现和改进这个“意大利新冠疫情预测模型”过程中的核心思路、实操细节以及踩过的坑毫无保留地分享出来。2. 核心思路与模型选型为什么是“模型融合”单纯用机器学习算法如LSTM、XGBoost去拟合疫情数据或者单纯用微分方程模型如SIR进行推演都有明显的局限性。前者像个黑盒虽然预测精度可能不错但缺乏对疾病传播机制的解释性容易过拟合后者机理清晰但假设理想如人群均匀混合对真实世界中封控、检测能力变化、病毒变异等外部冲击的刻画能力弱。因此这个项目的核心思路在于融合。具体来说我采用了“机理模型打底数据模型修正”的两阶段策略2.1 第一阶段基于传染病动力学模型进行趋势拟合传染病动力学模型是基石。最经典的莫过于SIR模型它将总人口分为易感者Susceptible, S、感染者Infectious, I和康复者Recovered, R三类通过一组微分方程描述其随时间的变化dS/dt -β * S * I / N dI/dt β * S * I / N - γ * I dR/dt γ * I其中β是感染率γ是康复率其倒数1/γ平均感染期N为总人口。这个模型的关键在于估计参数β和γ。对于新冠疫情更常用的是SEIR模型它在S和I之间增加了一个潜伏期人群Exposed, E能更好地模拟新冠病毒的潜伏特性。注意直接使用意大利全国的总人口数作为N会严重高估易感人群规模。在疫情中期实际有效接触人口远小于总人口。一个实用的技巧是将N也作为一个待优化参数或者根据疫情集中地区的实际人口进行估算。在这个阶段我们的目标不是追求完美的日度预测而是利用模型捕捉疫情发展的内在规律和基本再生数R0 β/γ。我们可以使用scipy.optimize库中的最小二乘法通过拟合真实的累计感染人数曲线来反推出最优的模型参数。2.2 第二阶段利用机器学习模型捕捉残差与外部效应通过第一阶段SIR/SEIR模型我们可以得到一条理论上的感染人数曲线。将这条曲线与真实曲线对比其差值即残差包含了所有模型未考虑的因素政府干预封城、检测策略变化、公众意识提升、季节效应以及病毒变异等。第二阶段的任务就是用机器学习模型来学习和预测这个残差序列。这是一个典型的时间序列预测问题。我尝试了以下几种方案并对比了效果经典时序模型如ARIMA、SARIMAX。优势是理论成熟、解释性强特别适合捕捉序列的自相关和季节模式。可以使用statsmodels库实现。如果发现残差序列具有明显的7天一周季节性SARIMAX会是一个好选择。树模型如XGBoost、LightGBM。这类模型能很好地处理非线性关系并且可以通过特征工程引入外部变量如“距离全国封锁的天数”、“周末标识”、“新增政策发布”等虚拟变量。它们对趋势和突变点有不错的捕捉能力。神经网络模型如LSTM、GRU。这是处理序列数据的利器能够自动学习长期依赖关系。如果残差序列的模式非常复杂LSTM可能表现出色。但需要注意它需要更多的数据、更精细的调参且训练时间更长。在实际操作中我采用了LightGBM作为主要的残差预测模型。原因在于它的训练速度快对缺失值不敏感能够方便地融入我构造的各类时间特征如“星期几”、“当月第几天”、“是否为假期”并且提供了很好的特征重要性输出帮助我理解哪些外部时间因素对预测误差影响最大。3. 数据获取、清洗与特征工程实战巧妇难为无米之炊高质量的数据准备是项目成功的一半。3.1 数据来源与获取意大利的疫情数据相对公开透明。我主要使用了两个来源约翰斯·霍普金斯大学JHU的CSSE COVID-19数据集这是全球最常用的疫情数据集之一通过GitHub每日更新包含各国、各地区的确诊、死亡、康复病例时间序列。我们可以使用pandas直接读取其CSV文件。import pandas as pd url https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv df_global pd.read_csv(url) # 筛选出意大利的数据 df_italy df_global[df_global[Country/Region] Italy].iloc[:, 4:] # 前4列是地理信息后面是日期列意大利民防部门Protezione Civile的官方数据数据更细粒度有时包含大区级数据。可以通过其官方GitHub仓库或API获取。实操心得务必记录你使用的数据快照日期。疫情数据可能存在后期修正回溯性新增或核减不同日期的数据副本可能导致结果可复现性差异。建议将下载的原始数据本地保存并在代码中注明版本。3.2 数据清洗与关键指标计算原始数据不能直接使用必须经过清洗处理缺失值与异常值早期数据可能有缺失后期数据可能因统计口径变化出现跳变。对于缺失值我用前后日期均值填充。对于单日异常高值需结合新闻核实如是否包含补报数据并考虑使用移动平均进行平滑。计算每日新增原始数据通常是累计确诊。我们需要通过差分计算每日新增确诊这才是模型真正要预测的目标变量。df_italy_cumulative df_italy.T # 转置让行索引为日期 df_italy_cumulative.index pd.to_datetime(df_italy_cumulative.index) df_italy_daily_new df_italy_cumulative.diff().fillna(0) # 计算每日新增构建7日移动平均由于检测和报告存在周期性波动例如周末报告延迟日度数据噪音很大。采用7日移动平均线能更好地反映疫情趋势也是后续模型拟合和评估更可靠的指标。df_italy_daily_new_smooth df_italy_daily_new.rolling(window7, min_periods1).mean()3.3 为机器学习模型构造特征对于第二阶段预测残差的LightGBM模型特征工程至关重要。我构造了以下几类特征时间特征从日期索引中提取如“月份”、“星期几”、“当月第几天”、“季度”、“是否周末”、“是否节假日”。这些能捕捉周期性和社会活动模式。滞后特征这是时间序列预测的核心。将目标变量残差的历史值作为特征例如前1天、前7天、前14天的残差值。趋势特征如“距离疫情首次爆发的天数”、“距离全国封锁令2020年3月9日的天数”。这些能帮助模型识别疫情发展的不同阶段。基于SIR模型的衍生特征将第一阶段SIR模型每日计算出的易感者比例(S/N)、感染率(β)等作为特征输入实现机理模型与数据模型的深度耦合。4. 两阶段建模的完整实现流程下面我将结合核心代码片段详解整个建模流程。4.1 第一阶段SIR模型参数估计首先定义SIR模型的微分方程和求解函数。import numpy as np from scipy.integrate import odeint from scipy.optimize import minimize def sir_model(y, t, beta, gamma, N): S, I, R y dSdt -beta * S * I / N dIdt beta * S * I / N - gamma * I dRdt gamma * I return dSdt, dIdt, dRdt def solve_sir(beta, gamma, I0, R0, days, N): # I0, R0为初始感染和康复人数 S0 N - I0 - R0 y0 S0, I0, R0 t np.arange(0, days, 1) ret odeint(sir_model, y0, t, args(beta, gamma, N)) S, I, R ret.T return S, I, R然后定义损失函数并使用优化器寻找最优参数。def loss_function(params, infected_data, N): beta, gamma params # 获取初始值例如从真实数据第一天获取I0, R0假设为0 I0 infected_data[0] R0 0 days len(infected_data) # 模拟SIR模型 _, I_pred, _ solve_sir(beta, gamma, I0, R0, days, N) # 计算模拟感染人数与真实感染人数的均方误差 mse np.mean((I_pred - infected_data) ** 2) return mse # 准备真实数据使用累计感染人数的平滑序列 infected_real df_italy_cumulative_smooth.values.flatten() # 假设已处理为平滑序列 # 设定总人口参数N这里作为一个粗略估计也可参与优化 N_guess 60e6 # 意大利约6000万人 # 设置参数初始值和边界 initial_guess [0.4, 0.1] # beta, gamma的初始猜测 bounds [(0.001, 1.0), (0.01, 0.5)] # 参数边界 # 执行优化 result minimize(loss_function, initial_guess, args(infected_real, N_guess), boundsbounds, methodL-BFGS-B) beta_opt, gamma_opt result.x print(f优化得到的参数: beta{beta_opt:.4f}, gamma{gamma_opt:.4f}, R0{beta_opt/gamma_opt:.2f})得到最优参数后运行SIR模型得到理论上的感染人数曲线I_sir。4.2 计算残差并准备第二阶段数据集# 计算残差真实数据 - SIR模型预测值 residual infected_real - I_sir # 将残差序列转换为DataFrame并合并之前构造的时间特征 df_residual pd.DataFrame({residual: residual}, indexdf_italy_daily_new_smooth.index) # 假设df_features是包含所有时间特征、滞后特征的DataFrame df_dataset pd.concat([df_residual, df_features], axis1).dropna() # 划分训练集和测试集按时间划分不能随机打乱 split_date 2020-06-01 # 示例分割点 train df_dataset[df_dataset.index split_date] test df_dataset[df_dataset.index split_date] X_train, y_train train.drop(residual, axis1), train[residual] X_test, y_test test.drop(residual, axis1), test[residual]4.3 第二阶段训练LightGBM残差预测模型import lightgbm as lgb # 创建LightGBM数据集 lgb_train lgb.Dataset(X_train, labely_train) lgb_eval lgb.Dataset(X_test, labely_test, referencelgb_train) # 设置模型参数 params { boosting_type: gbdt, objective: regression, metric: {l2}, num_leaves: 31, learning_rate: 0.05, feature_fraction: 0.9, bagging_fraction: 0.8, bagging_freq: 5, verbose: 0 } # 训练模型 gbm lgb.train(params, lgb_train, num_boost_round500, valid_setslgb_eval, callbacks[lgb.early_stopping(stopping_rounds20)]) # 在测试集上预测残差 residual_pred gbm.predict(X_test, num_iterationgbm.best_iteration)4.4 融合预测与最终结果最终的日度新增预测值等于SIR模型的理论预测值加上机器学习预测的残差值。# 获取测试集时间段内SIR模型的预测值 I_sir_test final_prediction I_sir_test residual_pred然后我们可以将final_prediction与真实的日度新增数据进行比较计算RMSE、MAE等指标并绘制对比图来直观评估预测效果。5. 模型评估、问题排查与调优经验模型建好了不代表工作就结束了。评估与调优才是提升项目价值的关键。5.1 评估指标的选择对于疫情预测不能只看传统的RMSE均方根误差。因为疫情发展不同阶段误差的意义不同。上升期/高峰期绝对误差MAE更重要预测少1000例和多1000例影响巨大。平台期/下降期相对误差MAPE或对称平均绝对百分比误差sMAPE可能更有参考价值。趋势方向可以计算预测方向与真实方向一致的“趋势准确率”。预测对了拐点有时比预测对具体数字更有价值。我通常会计算一个综合评分例如Score 0.5*Normalized_MAE 0.3*Normalized_MAPE 0.2*Trend_Accuracy。通过这个综合指标来对比不同模型和参数的效果。5.2 常见问题与排查清单在复现过程中我遇到了不少问题这里总结一下问题现象可能原因排查与解决思路SIR模型拟合曲线与真实数据前期吻合后期严重偏离1. 参数β和γ被假设为常数但现实中因干预措施会变化。2. 总人口数N设置不合理。1. 尝试分段拟合SIR模型例如以封城日为界分两段优化参数。2. 将N作为可变参数进行优化或使用有效接触人口估计值。残差序列波动剧烈机器学习模型难以学习1. 原始数据噪音过大。2. 残差中仍包含强烈的自相关未被SIR模型捕捉。1. 对原始数据使用更合理的平滑方法如7日移动平均。2. 检查残差的自相关图ACF/PACF如果自相关强考虑在特征中加入更多滞后项或先对残差序列建立ARIMA模型。LightGBM模型在训练集上表现好测试集上表现差1. 过拟合。2. 疫情发展阶段发生根本性变化如新变种出现训练集模式失效。1. 增加min_data_in_leaf降低num_leaves增加reg_alpha和reg_lambda等正则化参数。2. 采用时间序列交叉验证TimeSeriesSplit确保验证集始终在训练集之后更贴近现实预测场景。最终融合预测在拐点处总是滞后或超前1. SIR模型本身对干预响应有延迟。2. 机器学习模型的特征未能及时反映政策影响。1. 在特征工程中加入政策强度的代理变量如谷歌移动性数据的变化率。2. 尝试使用对突变点更敏感的模型如带有注意力机制的时序模型。5.3 模型调优的一些心得不要迷信复杂模型在这个项目中我尝试过LSTM但其表现并不总是优于精心调参的LightGBM。对于中等长度的序列特征工程良好的树模型往往更稳定、更快、更好解释。可视化是你的好朋友务必绘制以下图表1) SIR拟合曲线与真实累计病例对比图2) 残差序列随时间变化图3) 特征重要性条形图4) 最终预测值与真实值的逐日对比图。这些图能帮你快速定位问题。理解业务背景2020年3月9日意大利全国封锁这个日期前后模型必然要区别对待。强行用一个模型拟合全阶段效果肯定不好。将“后封锁时代”作为一个哑变量特征加入或者直接分阶段建模效果立竿见影。6. 项目延伸与高级探讨完成基础版本后这个项目还有很多可以深挖和扩展的方向空间异质性建模意大利北部伦巴第大区和南部的疫情严重程度天差地别。可以尝试使用元胞自动机Cellular Automata或基于图网络的模型将各大区作为节点人口流动数据作为边构建空间传播模型。这能极大提升预测的精细度。引入更多外部数据单纯依靠病例数据是“后视镜”。可以融入谷歌社区移动性报告反映人员流动、天气数据温度、湿度可能影响传播、网络搜索趋势如“发烧”、“失去嗅觉”的搜索量作为领先指标。不确定性量化预测不只是给一个数更重要的是给出一个范围置信区间。可以使用贝叶斯方法如PyMC3库来拟合SIR模型直接得到参数的后验分布和预测分布。或者对机器学习模型使用分位数回归来预测区间。实时更新与在线学习设计一个管道当有新数据到来时自动重新训练模型或部分参数实现滚动预测。这更贴近实际的疫情监测预警系统需求。这个项目就像一把钥匙帮你打开了“复杂系统建模”和“时序预测”的大门。它教会你的不仅是Python编程和调包更是如何将领域知识流行病学转化为数学模型如何用数据驱动的方法去修正和增强理论模型以及如何严谨地评估一个预测系统。这些技能在你未来面对销售预测、流量预测、故障预测等任何时序问题时都将是无价的财富。最后一个小建议把所有代码、参数和实验结果用Jupyter Notebook完整记录下来并写好注释。几个月后当你回头再看或者需要向别人展示时你会感谢自己这个习惯。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价