尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
流感预测实战:ARIMA+LSTM+Transformer三模型组合实现
简介面向计算机专业课程设计与期末大作业的流感时间序列预测Python项目整合ARIMA、LSTM、Transformer等经典统计与深度学习方法适合正在做期末大作业、课程设计以及需要项目实战练习的学习者可同时作为多模型对比实验与建模流程参考。资源包约4.93MB共25个文件包含7个Python脚本、7个CSV数据文件、4个Excel表格、2个Jupyter Notebook及若干辅助压缩材料其中Python脚本分别对应平稳性检验、差分处理、ARIMA/SARIMA定阶、残差分析、多模型对比与预测等步骤Notebook则提供交互式实验过程。目前已有387人浏览学习。该项目是经导师指导认可通过的98分高分作业源码按1_1、1_2等步骤模块化组织并附有带中间结果的notebook与分步脚本便于读者按流程复现实验、观察各模型在流感数据上的拟合与预测差异同时代码命名清晰、目录结构直观可直接参考其工程组织方式用于课程设计答辩或拓展到其他时间序列预测任务。1. 流感预测的“三模型组合拳”这个 Python 源码项目为什么值得做把“基于 ARIMA、LSTM、Transformer 做流感时间序列预测”这串词拆开看它其实是一条完整的生产链路先用 ARIMA 打底确认线性趋势与季节周期再用 LSTM 捕捉周与周之间的非线性惯性最后让 Transformer 用注意力机制重新关联长距离的爆发信号例如去年同期的峰值如何影响今年。很多人误以为深度学习模型一定比传统统计模型准实际做下来流感周报这种小样本强周期数据里Transformer 常常输给一组调参到位的 SARIMA但三者组合之后的效果又稳定高于任何单一模型。这个方向适合公共卫生数据从业者、时序预测方向的转行者也适合做毕业设计或竞赛项目的人数据公开、任务定义清晰、评价指标直观而这份 Python 源码的价值不在于模型多新在于把“数据处理—基线模型—深度模型—评估”做成了一套可复现的流程。2. 数据是流感预测的地基从周报清洗到窗口切分2.1 流感原始数据长什么样字段结构与时间跨度的选择流感预测最常用的公开数据是流感样病例ILI周报国内发布渠道会给出按周统计的流感样病例百分比ILI%部分年份还能拿到分年龄段、分南北方省份的明细。一个典型的 CSV 文件大致有以下字段年份、周数、ILI 百分比、南方省份活动水平、北方省份活动水平。建模时我一般只保留两个核心列日期由年周换算成真正的日期和 ILI 百分比其他字段作为可选特征在后续扩展中使用。时间跨度上至少取三年以上这样才能覆盖至少两个完整的流感流行季。如果年份过短SARIMA 的季节项根本拟合不了 52 周的周期Transformer 也学不到“去年爆发”这个最重要的长期依赖。需要注意的坑是流感周报在夏季疫情低谷期经常出现零值或缺失值而那段时间恰好是模型最容易学坏的地方。许多人在处理缺失值时直接用线性插值结果把夏季的低位拉成了波谷曲线秋冬爆发反而被压缩。常见做法是用前四周的中位数填补缺失值同时保留缺失位置作为掩码标记这样既不引入突变的假信号也不会把缺失周的异常信息传递给周围样本。2.2 预处理三步走缺失值填补、对数变换与平稳性判断预处理这段我一般固定走三步。第一步是缺失值处理用滚动中位数替代线性插值因为流感传播的短期波动非常大中位数对爆发期的尖峰不敏感。第二步是对数变换流感数据的量纲在爆发期可能从 1.5% 跳到 6% 甚至更高直接用原始值建模模型会把绝大部分学习能力浪费在拟合那几次大爆发上而忽略基线波动取log1p之后数据分布被压缩尖峰变得相对可控。第三步是平稳性判断对取完对数后的序列做 ADF 检验如果 p 值大于 0.05就做一阶差分对周报数据来说一阶差分往往还不够因为 52 周的季节性依然存在后续交给 SARIMA 的季节项处理。import pandas as pd import numpy as np from statsmodels.tsa.stattools import adfuller df pd.read_csv(ili_weekly.csv, parse_dates[week]) df df.set_index(week).sort_index() # 滚动中位数填补缺失周 df[ili_rate] df[ili_rate].fillna(df[ili_rate].rolling(4, min_periods1).median()) # 对数压缩尖峰 df[log_ili] np.log1p(df[ili_rate]) # ADF 检验原始对数序列是否平稳 adf_stat, p_value, *_ adfuller(df[log_ili].dropna()) print(fADF p-value: {p_value:.4f}) # 若不平稳则做一阶差分 if p_value 0.05: df[diff_ili] df[log_ili].diff().dropna()这段代码里rolling(4, min_periods1)的 4 指的是前四周窗口之所以不用更大的窗口是因为流感活动变化很快五周前的数据对当前缺口的参考价值已经很弱。log1p里加 1 是为了保证零值存在时不会产生负无穷。ADF 检验的 p 值是一个后续判断依据如果你看到 p 值在 0.05 边缘别急着差分可以先去查一下是不是数据里存在缺失区间导致的假性非平稳。2.3 把时间序列转成监督学习格式滑动窗口与半步切分ARIMA 可以直接吃一维序列但 LSTM 和 Transformer 需要“用前 k 周预测后 h 周”的监督学习格式。这里我给出一个通用的切分函数三个参数分别控制输入长度、输出长度和步长。流感预测通常用过去 8 周预测未来 4 周即未来一个月的疫情走势步长设为 1 表示每周滚动一次如果你做的是每周更新的业务预测步长也可以设为 4让模型每条样本之间不重叠减少训练量。import numpy as np def make_window(seq, lookback8, horizon4, step1): X, y [], [] for i in range(lookback, len(seq) - horizon): X.append(seq[i - lookback:i]) y.append(seq[i:i horizon]) i step return np.array(X), np.array(y) X, y make_window(df[log_ili].values, lookback8, horizon4, step1) print(f样本数: {X.shape[0]}, 输入形状: {X.shape}, 输出形状: {y.shape})切分时最容易忽略的问题验证集和测试集必须按时间顺序切不能随机打乱。流感数据本身有强烈的周期自相关性随机切分会把未来信息泄漏到训练集里模型在验证集上的表现会虚高线上预测却一塌糊涂。我习惯的做法是把数据集按时间顺序切成三段前 60% 训练、中间 20% 验证、最后 20% 做最终测试并且切分时要保证验证集包含至少一个完整的流感季。如果你的数据恰好只有三年那么前两年训练、后一年测试是更稳妥的划分方式。3. ARIMA 定基线为什么先跑通传统模型再碰深度学习3.1 定阶三件套ACF/PACF 看图、AIC 网格搜索、残差检验ARIMA 在流感预测里的最大价值是提供一个“及格线”。很多团队一上来就堆 LSTM最后模型的预测精度还不如一组调好季节项的 SARIMA原因就在于流感数据里最强且最稳定的信号就是年度季节性这种东西统计模型用有限参数就能捕捉而神经网络需要大量样本才能自己摸索出来。做流感预测我永远是先跑 ARIMA/SARIMA把它的精度当作后续深度模型必须超越的下限。定阶的常用套路是三步。第一步画 ACF 和 PACF 图初步确认自相关阶数 p 和移动平均阶数 q。第二步用 AIC 做网格搜索注意这里要搜索的是四个参数p、d、q 再加上季节项因为流感周报是 52 周一个周期。第三步是对拟合后的残差做白噪声检验如果你看到 Ljung-Box 检验 p 值小于 0.05说明残差里还有信息没有被模型提取此时提阶或者增加季节项比直接调参更有效。from statsmodels.tsa.statespace.sarimax import SARIMAX import itertools import numpy as np best_aic np.inf best_params None for p in range(0, 3): for d in range(0, 2): for q in range(0, 3): for P in range(0, 2): for D in range(0, 2): for Q in range(0, 2): try: model SARIMAX( df[log_ili], order(p, d, q), seasonal_order(P, D, Q, 52), enforce_stationarityFalse, enforce_invertibilityFalse ) res model.fit(dispFalse) if res.aic best_aic: best_aic res.aic best_params (p, d, q, P, D, Q) except Exception: continue print(f最优 AIC: {best_aic:.2f}, 对应参数: {best_params})seasonal_order里的 52 是周报数据的一年周期不可省略。enforce_stationarityFalse和enforce_invertibilityFalse是让 SARIMAX 在搜索时不强制参数满足平稳可逆条件否则很多中间组合会直接报错跳出错过真正的最优区域。这个网格搜索在数据量不大时几秒跑完完全不必担心性能。3.2 ARIMA 预测结果怎么解读输出分位数而不是单个点ARIMA 的预测结果应该包含置信区间这在流感场景里比点估计更有业务价值。公共卫生决策者最需要知道的是“未来四周的爆发概率有多大”而不是一个具体的百分之几。SARIMAX的get_forecast方法返回的置信带就是依据残差方差推导出来的正态区间。我做业务汇报时会把预测中位数和 80% 置信区间一起画出来然后单独标注超过历史同期阈值的区间段那些就是需要预警的候选周。另外要提醒一个容易翻车的地方如果你对序列取了对数变换那么 ARIMA 的预测结果必须做np.expm1还原回原始量纲并且置信区间也要先还原再解释。很多人忘记了这一步直接把对数尺度上的预测值拿去做对比结果预测值比真实观测值低了整整一个量级还以为是调参问题。4. 从 PyTorch 搭建 LSTM 和 Transformer网络结构、训练配置与参数调整4.1 LSTM 的输入输出约定三维张量与多步预测的两种写法LSTM 在流感预测中的常见用法是用过去若干周的数据作为序列输入输出未来四周的爆发水平。PyTorch 的nn.LSTM要求输入形状是(batch, seq_len, input_size)其中seq_len就是滑动窗口里设定的 lookbackinput_size是你启用的特征数量。如果你只用 ILI 率单特征它就是 1如果你把南方和北方活动水平、甚至气候湿度一起塞进去那它就是对应的特征列数。多步预测有递归和多输出两种方式。递归方式是把模型预测出来的下一周结果拼回输入再预测再下一周这种写法误差会逐步累积流感爆发期的误差尤其大推荐的做法是直接让模型输出一个长度为horizon的向量一次预测未来四周代价是输出层的参数量会变大但不会出现误差滚雪球。下面的代码采用多输出方式。import torch import torch.nn as nn class LSTMPredictor(nn.Module): def __init__(self, input_size, hidden_size, num_layers, horizon): super().__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue ) self.fc nn.Linear(hidden_size, horizon) def forward(self, x): out, (hn, cn) self.lstm(x) # 取最后一个时间步的隐状态 last_hidden out[:, -1, :] return self.fc(last_hidden)hidden_size我一般取 32 到 128 之间流感序列长度只有几百周hidden_size 太大很容易过拟合。num_layers取 2 足够3 层以上在这种小数据量基本不带来收益。训练时如果发现验证集 loss 持续震荡优先降低学习率而不是加深网络。4.2 Transformer 用于时序预测的关键改动位置编码与因果注意力Transformer 在流感预测里并不是直接套用 NLP 结构。标准 Transformer 的编码器是“看全局”的但在时序预测里未来的信息一旦进入注意力范围就构成了数据泄漏。解决这个问题有两种常见做法一种是在注意力矩阵上做 causal mask让每个位置只能看到它之前的时刻另一种更简单是只用编码器结构输入整个历史窗口输出端用最后一个位置的隐含向量接全连接层。后者参数量更小在小样本场景下效果通常更好。位置编码是 Transformer 应用于时序任务时最容易被忽略的部分。LSTM 天然有顺序感但 Transformer 的注意力是无序的不注入位置信息时模型会把“第 3 周”和“第 30 周”当成同一个模式。下面的实现使用标准正弦位置编码但把max_len限制在 512 以内避免训练阶段见过的位置数量远小于推理阶段产生的无效编码。import math import torch import torch.nn as nn class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len512): super().__init__() pe torch.zeros(max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) self.register_buffer(pe, pe.unsqueeze(0)) def forward(self, x): return x self.pe[:, :x.size(1)] class TransformerPredictor(nn.Module): def __init__(self, d_model, nhead, num_layers, horizon, dropout0.1): super().__init__() self.embed nn.Linear(1, d_model) self.pe PositionalEncoding(d_model) encoder_layer nn.TransformerEncoderLayer( d_modeld_model, nheadnhead, dim_feedforwardd_model * 4, dropoutdropout, batch_firstTrue ) self.encoder nn.TransformerEncoder(encoder_layer, num_layersnum_layers) self.fc nn.Linear(d_model, horizon) def forward(self, x): x self.pe(self.embed(x)) x self.encoder(x) return self.fc(x[:, -1, :])d_model是嵌入维度我常用 64 或 128nhead设为 4 或 8且必须能被d_model整除。dim_feedforward是前馈层的中间维度固定取d_model的 4 倍这跟 PyTorch 默认配置一致。这里self.embed输入维度写死为 1如果你要加入多个特征记得改成特征数量。4.3 训练配置归一化方式、学习率与早停的取舍在训练深度模型前必须把数据缩放。流感序列取对数后依然是数量级波动的Transformer 里注意力对尺度极其敏感所以一般要把数据缩放到 0 到 1 之间。注意缩放器必须在训练集上fit然后同时对训练集、验证集、测试集做transform。如果对全部数据一起 fit就跑到了未来的统计信息这属于非常隐蔽的泄漏。from sklearn.preprocessing import MinMaxScaler from torch.utils.data import TensorDataset, DataLoader scaler MinMaxScaler() scaled_train scaler.fit_transform(X_train.reshape(-1, 1)).reshape(-1, 1, 1) scaled_val scaler.transform(X_val.reshape(-1, 1)).reshape(-1, 1, 1) train_dataset TensorDataset(torch.tensor(scaled_train, dtypetorch.float32), torch.tensor(y_train, dtypetorch.float32)) train_loader DataLoader(train_dataset, batch_size32, shuffleFalse)这里的shuffleFalse是故意设的流感序列的样本之间本来就依赖时间顺序打乱后虽然训练 loss 会下降但是模型学到的映射关系会变形。学习率方面我用 AdamW 初始学习率 1e-3配合早停法连续 10 轮验证集 loss 不降就终止。Transformer 模型则建议学习率降到 5e-4 或者加一个 warmup 阶段否则前几轮很容易看到 loss 直接冲到 NaN。5. 流感预测的五个典型坑数据泄漏、峰值低估与训练翻车的排障笔记5.1 验证集 Loss 很低但预测曲线永远滞后一步现象验证集上的 MAE 只有零点几但画出来的预测曲线和真实曲线形状高度重合只是整体往右平移了一两周。原因归一化时缩放器看到了验证集甚至全量数据的统计范围这等于把未来的信息间接注入了模型的训练目标。另一个常见叠加因素是使用了shuffleTrue。解决先用TimeSeriesSplit重新切分数据把缩放器的fit严格限定在训练折内并确认 DataLoader 里shuffleFalse。血泪经验是出现“曲线形状完美但滞后”的时候先去检查数据泄漏不要先调模型结构。5.2 SARIMA 残差里仍然有显著周期成分现象SARIMA 模型的 AIC 已经很低但残差做周期图观察时52 周的峰依然很明显。原因季节阶数选得不够D 只做了 0 阶或 1 阶差分没有完全消除年度周期性。解决把seasonal_order里的 D 加到 1 或 2同时将季节项的回看窗口从 52 调成 104给模型更长周期的记忆。注意此时计算量会暴涨网格搜索时间从几秒变成几分钟但数据量小时完全可接受。5.3 Transformer 训练时损失函数震荡甚至变成 NaN现象训练到第 3、4 轮loss 突然从 0.3 跳到 NaN之后再也回不来。原因学习率过大或者在 Softmax 之前的注意力分数出现极端值梯度因此溢出。解决把学习率从 1e-3 降到 5e-4并在优化器上增加梯度裁剪max_grad_norm设置为 1.0。如果仍然不稳检查输入是否做了缩放以及位置编码是否出现了静态值漂移。这个坑在流感预测里比在其他 NLP 任务里更常见因为序列长度短且数值变化剧烈注意力分数更容易饱和。5.4 爆发预测的峰值永远被低估现象模型在秋冬高峰时预测值总是比实际值低 20% 到 30%特殊年份更是低得离谱。原因训练时用的损失函数是 MAE 或 MSE它们对高频尖峰不敏感模型为了降低整体误差选择把预测拉到中间值附近。解决改用 Huber 损失或者对数变换后的回归问题配合HuberLoss(delta1.0)。如果峰值依旧偏低可以在最终还原时对预测结果做一步后处理乘以一个由历史同期中位数比例校正的系数。这不算严谨的统计学修正但在业务预报里是常用的兜底手段。5.5 测试集数据被意外混入训练窗口现象模型在测试集上 MAE 低得不像话但你明明没有显式打乱数据。原因在构造滑动窗口时窗口跨越了切分边界。例如一个窗口的开头在训练集末尾已经落到测试集后面又被当成完整样本训练。解决在make_window里传入train_end参数强制窗口的右端点严格小于切分点。类似问题也可能出现在差分操作上如果你在全序列上先做了差分再切分未来值已经参与计算当前值泄漏就又回来了。正确的顺序永远是先切分、再差分或缩放每一折独立做。6. 把模型真正用起来滚动回测、集成策略与置信区间的最后一块拼图滚动回测是检验流感预测模型能否上线的唯一标准。静态划分测试集只能做一次评估而流感预测的实际使用方式是每周更新数据、重新预测未来四周。正确的做法是用 5 折时间序列切分每一折里模型都在历史数据上重新训练再预测未来一段不重叠的时间然后累加所有折的误差得到接近真实业务的指标。遇到爆发年份时用固定切分会因为训练集里没看到完整爆发而高估误差或者因为测试集恰好是低谷而低估误差滚动回测能把这个偏差摊开到整个时间区间里。模型集成方面我使用一个相对简单但有效的权重方案先用 SARIMA 预测出线性趋势和季节部分然后用 LSTM 或 Transformer 对 SARIMA 的残差做二次预测最后把两个预测相加。这样做的逻辑很清楚——ARIMA 负责它擅长的周期与趋势深度模型负责学习它无法表达的非线性局部爆发特征两者互补。平均权重时不要固定 0.5 对 0.5而是在验证集上测试不同组合通常 SARIMA 占 0.4LSTM 与 Transformer 各占 0.3 是比较稳妥的起点。你也完全可以把 SARIMA 的输出作为 Transformer 的一个额外输入特征让模型自己学会两者如何交互。置信区间可以用一个简单技巧来构建对训练集残差按季度分组统计每个季度的残差标准差然后在预测点上做加减 1.28 倍标准差得到 80% 区间。这里的季度分组很重要因为流感低谷期残差小、爆发期残差大用一个全局标准差会把低谷期的区间撑得过度保守让人误判风险。画图时把预测中位数、80% 置信区间和历史同期均值线放在同一张图里业务团队能一眼看出哪些周超出了历史正常波动范围。最后一季度的教训是我第一次做流感预测时迷信 Transformer 一定最强结果在验证集上被 SARIMA 和 LSTM 双双反超。后来才想明白所有深度模型在小样本时间序列上的优势都是“有条件的”只有在传统统计模型完全无法覆盖的非线性区域才体现出来。所以现在我做任何时序项目都先跑传统模型、再跑深度学习、最后做集成顺序反了就会在调参黑匣子里浪费大量时间。希望这篇笔记能帮你避开这些坑把流感预测老老实实做成一套能复现、能解释、能上线的方案。本文还有配套的精品资源点击获取
RELATED

相关推荐

Python股票预测毕业设计:数据清洗与标签构造实战指南

Python股票预测毕业设计:数据清洗与标签构造实战指南

简介:本资源是一套高分(98分)毕业设计级项目,面向计算机及相关专业本科生、研究生及机器学习初学者,聚焦股票价格预测与量化分析实战需求,提供从数据获取、特征工程、模型训练到结果可视化的完整技术闭环。…

📅 2026/10/12 15:44:26
从建造者到定义者:AI编程时代的程序员转型指南

从建造者到定义者:AI编程时代的程序员转型指南

1. 变化不是未来,已经发生在今天的工位上 这两年我越来越强烈地感觉到:AI编程已经不是概念演示,而是实实在在挤进了每天的工位。打开编辑器,代码补全不再是简单的关键字联想,而是整段整段往外冒;遇到不熟的…

📅 2026/10/12 15:44:26
为了搞个 AI 助手,我在 Windows 上折腾了整整一天:从 PowerShell 到 TaoToken 的排错记录

为了搞个 AI 助手,我在 Windows 上折腾了整整一天:从 PowerShell 到 TaoToken 的排错记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 15:44:26
MORE NEWS

更多资讯

📰

OpenClaw 2.7.9 对接飞书机器人完整分步实操教程(含安装包)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

C语言循环控制:break、continue、goto的跳转机制与实战陷阱

不少学C语言的朋友走到系列第11篇,已经把顺序、分支这些基础结构拿捏得差不多了,一进入循环嵌套的实战场景就发愁:到底什么时候用break,什么时候用continue,那个被无数人念叨“不要用”的goto又是怎么回事。这篇就把循…

📰

AI编程工具深入使用:从代码补全到稳定高效工作流

1. 先把AI编程工具用明白:核心能力与选型思路AI编程工具这两年几乎是每个开发者的日常话题,但绝大多数人还停留在"让AI帮我写个函数、补全一段代码"的层面。跟你实话实说,我在早期也是这样,装上某款AI编程助手之后&…

📰

AI编程工具实战:从需求到上线的人机协作方法论

说实话,AI编程工具刚火起来那阵子,我心里是带着问号的。代码补全工具我试过,结论是“偶尔惊艳,经常添乱”。后来真正改变我想法的,不是哪一款工具突然变得多聪明,而是我调整了使用方式——从“让AI替我写代…

📰

TCN时间卷积神经网络在MATLAB故障诊断中的落地实践

简介:基于TCN时间卷积神经网络实现故障诊断的Matlab资源包,面向计算机、电子信息工程、数学等专业大学生,适用于课程设计、期末大作业或毕业设计。资源共8个文件,包含m主程序、xlsx案例数据集、png运行结果图和zip完整源码&#x…

📰

零基础AI漫剧制作全流程:从文案到量产的核心链路

1. 我在创作营里学到了什么:AI漫剧的核心生产链路先说结论:零基础做AI漫剧,最难的不是技术,而是“不知道完整流程长什么样”。我参加这个创作营之前,以为AI漫剧就是“AI画图配音”这么简单,真正上手才发现&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬