ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

微分方程建模实战:从传染病SIR模型到数学建模竞赛应用

微分方程建模实战:从传染病SIR模型到数学建模竞赛应用 1. 从“板凳龙闹元宵”到“病毒传播”微分方程建模的实战价值如果你最近关注过数学建模竞赛无论是国赛、美赛还是亚太杯大概率会看到一个高频词微分方程。从2024年高教社杯C题的“生产过程中的最优控制”到2025年国赛C题可能涉及的复杂系统分析再到网络热议的“板凳龙闹元宵”这类充满传统文化背景的赛题微分方程模型几乎是无处不在的“硬通货”。我参加过多次竞赛也带过不少队伍一个深刻的体会是队伍之间拉开差距的关键往往不在于谁用了更炫酷的AI算法而在于谁能把微分方程这个“老伙计”用得扎实、用得巧妙。很多同学一听到“微分”、“偏微分”就头疼觉得这是纯数学理论离实际建模很远。但实际上微分方程是连接数学建模中“定性描述”与“定量预测”最直接的桥梁。它能把“感染人数增长越来越快”、“种群数量最终会稳定”这些模糊的直觉变成可以计算、可以模拟、可以优化的一组方程。简单来说微分方程建模的核心思想就是用变化率来描述事物演化的规律。我们不直接说“明天有多少病人”而是说“今天病人的增加速度与当前的病人数和易感者数成正比”。这个关于“速度”的方程就是微分方程。解出它你就得到了对未来情况的完整预测。这比单纯的数据拟合更有说服力因为它包含了我们对系统内在机理的理解。无论是研究传染病扩散、种群竞争、经济增长还是分析化学反应、热量传导、甚至金融资产价格波动如随机微分方程这套方法论都是相通的。这篇笔记我不想堆砌复杂的数学定理而是想结合我这些年打比赛、看优秀论文、以及辅导学生的实战经验和你聊聊微分方程建模的核心套路、常见坑点以及让论文出彩的关键细节。我们会从最经典的模型出发拆解每一步的思考过程并看看如何用MATLAB或Python把这些想法变成可运行的代码和直观的图表。你会发现掌握几个经典的模型框架并理解其变通之道远比死记硬背一百个公式有用得多。2. 微分方程模型的核心骨架以传染病模型为例的深度拆解几乎所有微分方程建模的入门都绕不开传染病模型。这不是因为它简单而是因为它完美地诠释了如何从实际背景中抽象出关键因素并构建方程。我们以最经典的SIR模型为例把它掰开揉碎了讲。2.1 模型假设比建立方程更重要的第一步很多论文在这里一笔带过但这是决定模型成败的起点。假设必须清晰、合理、且与后续的方程严格对应。人群分类Compartmentalization我们将总人口N分为三类。易感者 (S)未患病但缺乏免疫力可能被感染。感染者 (I)已患病且具有传染性。移除者 (R)从感染中恢复或死亡并假定永久免疫不再参与疾病传播。注意这里“移除”是学术术语并非不人道而是指其脱离了传染系统。在论文中需明确说明。均匀混合Homogeneous Mixing这是一个强假设。它认为人群中任何两个个体接触的机会均等。这显然不符合现实你接触家人的频率远高于陌生人但对于宏观趋势的初步分析这是一个合理且必要的简化。在论文中必须明确指出此假设并在模型改进部分讨论其局限性如引入网络结构。参数常数化在基础SIR模型中我们假设传染率 β一个感染者单位时间内有效接触并传染给易感者的概率。通常表示为β * S * I / N意味着新感染人数与易感者数量S和感染者数量I的乘积成正比基于均匀混合。移除率 γ单位时间内感染者被移出康复或死亡的比例。其倒数1/γ的平均感染期。这些假设不是凭空来的。β包含了病毒的传播能力和人群的接触频率γ则与疾病的病理周期有关。在论文中你需要引用文献或数据来支持这些参数的大致范围。2.2 方程构建从文字描述到数学公式的翻译基于上述假设我们可以用“流入-流出”的思想来建立每个仓室的变化率方程。易感者S的变化S只会减少。减少的速率等于新感染发生的速率即β * S * I / N。dS/dt -β * S * I / NdS/dt表示S随时间t的变化率即导数感染者I的变化I有流入也有流出。流入是来自S的新感染者 (β * S * I / N)流出是康复或死亡的移除者 (γ * I)。dI/dt β * S * I / N - γ * I移除者R的变化R只增加增加速率就是感染者的移除速率。dR/dt γ * I总人口约束S I R N(常数)。你可以验证将上面三个方程相加d(SIR)/dt 0。这一组方程就是SIR模型的核心。看到这里你可能觉得很简单。但真正的功夫在下一步理解方程背后的动力学行为而不是急着去解方程。2.3 核心洞察基本再生数R0与平衡点分析不解方程我们也能获得至关重要的定性结论这是论文建模分析部分的亮点。基本再生数 R0这是传染病学中最重要的概念。它表示在一个完全易感的人群中一个感染者在其整个传染期内平均能传染的人数。在SIR模型中如何推导初始时刻假设几乎所有人都是易感者即S ≈ N。一个感染者的传染能力是β其平均传染期是1/γ。因此R0 β / γ。R0的意义R0 1疾病会爆发流行每个感染者能传染超过一个人。R0 1疾病会逐渐消亡。 在论文中你必须计算并解释你模型中R0的值。例如COVID-19早期的R0估计在2-3之间麻疹高达12-18。通过干预如戴口罩减少β隔离缩短传染期即增大γ来降低R0至1以下是防控的理论基础。平衡点与稳定性令方程组右边等于0可以解出系统不再变化的状态即平衡点。无病平衡点(S, I, R) (N, 0, 0)。即没有感染者。地方病平衡点当R0 1时存在一个I 0的平衡点意味着疾病将持续存在。 通过线性化求雅可比矩阵和分析特征值可以证明当R0 1时无病平衡点是稳定的疾病消失当R0 1时无病平衡点不稳定而地方病平衡点稳定疾病流行。这部分分析能极大提升论文的理论深度即使你只是定性地描述这个结论。3. 从SIR到实战模型变体与赛题适配策略SIR是骨架但实际赛题千变万化。生搬硬套SIR必然失败。关键在于如何根据题目信息对骨架进行“外科手术”式的改造。3.1 常见模型变体库你需要一个“模型工具箱”根据题目关键词快速匹配和调整。SI模型最简单只有易感者和感染者如某些无法治愈或观察期极短的场景。dI/dt β * S * I / N。结果永远是所有人被感染。SIS模型感染后可康复但无免疫力直接变回易感者如普通感冒。方程变为dI/dt β * S * I / N - γ * I,S N - I。存在一个阈值决定疾病是消亡还是形成地方病。SEIR模型这是SIR的重要扩展增加了潜伏者E。感染者被感染后不是立即具有传染性而是先进入潜伏期E经过一段时间后才变为感染者I。这更符合COVID-19、流感等疾病。方程增加dE/dt β * S * I / N - σ * EdI/dt σ * E - γ * I。其中σ是潜伏期到发病期的转化率1/σ是平均潜伏期。赛题应用但凡题目提到“潜伏期”、“无症状感染者”、“隔离观察期”SEIR是首选。2020年左右的很多赛题都涉及此模型。考虑人口动力学如果赛题时间跨度很长如几年需要考虑出生和自然死亡。在SIR每个方程中加入μ*N(出生进入S) 和-μ*S, -μ*I, -μ*R(自然死亡)。考虑疫苗接种可以视为直接将一部分易感者S以一定速率转移到移除者R中。考虑年龄结构、空间扩散这会将常微分方程ODE升级为偏微分方程PDE难度激增。除非赛题明确要求或有充足时间和能力否则谨慎使用。3.2 赛题适配实战以“生产储运销”类题目为例我们看一类常见赛题比如“某产品的生产、库存、销售系统优化”、“能源生产与消耗的动态平衡”。这看起来和传染病无关但建模思想是相通的。识别“仓室”将系统分解为几个状态变量。P(t): 生产线的在制品数量或生产率。S(t): 仓库库存量。D(t): 市场需求量或已销售量。分析“流”生产线的产出是库存的“流入”。市场的销售是库存的“流出”同时是已销售量的“流入”。市场需求可能受库存、价格、时间影响。建立方程dP/dt u(t) - α*P。u(t)是控制输入如加大生产力度α*P表示生产完成进入库存的速率。dS/dt α*P - β*S * f(D)。α*P是库存流入β*S * f(D)是流出到销售f(D)是需求函数。dD/dt β*S * f(D) - γ*D。γ*D表示需求被满足或衰减的速率。核心参数与优化这里的α, β, γ类似于传染病模型中的速率常数。题目往往要求设计u(t)使得成本最低、利润最大这就转化成了一个最优控制问题通常需要用到庞特里亚金极大值原理或动态规划来求解。在论文中即使你无法求出精确解析解用数值方法如MATLAB的fmincon进行仿真优化并展示不同策略下的结果对比也是完整的解决方案。关键技巧拿到赛题后先问自己系统中有哪些“状态”它们之间如何“转化”或“流动”哪些是输入可控哪些是输出观测回答清楚这些问题微分方程的框架就自然浮现了。4. 数值求解与MATLAB/Python实现把方程变成图表绝大多数竞赛中的微分方程模型是求不出解析解的必须依靠数值求解。这里MATLAB是绝对的主流Python的SciPy库也很强大。4.1 算法选择ODE45为什么是万金油对于大多数常微分方程组MATLAB的ode45函数是首选。它基于Runge-Kutta (4,5)算法是一种自适应步长的单步法。为什么自适应步长重要系统变化快时如疫情爆发期步长自动调小以保证精度系统变化慢时如疫情平稳期步长自动调大以提高计算速度。你不需要手动调步长避免了因步长太大导致发散或步长太小计算太慢的问题。什么情况下不用ode45如果你的方程组是“刚性”的即系统中不同变量的变化速率差异巨大例如化学反应中某些中间产物寿命极短ode45会为了稳定性将步长缩得非常小导致计算极慢。此时应换用刚性求解器如MATLAB的ode15s或ode23s。4.2 MATLAB代码模板与解读下面是一个完整的SEIR模型求解与绘图模板包含参数设置、方程定义、求解和可视化。我加了大量注释你可以把它存为一个脚本文件直接修改使用。% SEIR模型模拟 - MATLAB实现 % 清除环境 clear; close all; clc; %% 1. 参数设置根据题目或文献调整 N 1000; % 总人口 I0 1; % 初始感染者 E0 0; % 初始潜伏者 R0 0; % 初始移除者 S0 N - I0 - E0 - R0; % 初始易感者 beta 0.6; % 传染率 (R0 beta/gamma 可调整) sigma 0.2; % 潜伏期转化率 (平均潜伏期 1/sigma 5天) gamma 0.1; % 移除率 (平均感染期 1/gamma 10天) tspan [0, 200]; % 模拟时间范围 [起始天, 结束天] y0 [S0; E0; I0; R0]; % 初始条件列向量 [S; E; I; R] %% 2. 定义微分方程组 (保存在函数seir_ode中) % 新建一个文件 seir_ode.m 内容如下 % function dydt seir_ode(t, y, beta, sigma, gamma, N) % S y(1); % E y(2); % I y(3); % R y(4); % % dSdt -beta * S * I / N; % dEdt beta * S * I / N - sigma * E; % dIdt sigma * E - gamma * I; % dRdt gamma * I; % % dydt [dSdt; dEdt; dIdt; dRdt]; % end %% 3. 数值求解 % 使用匿名函数传递参数给ode求解器 odefun (t, y) seir_ode(t, y, beta, sigma, gamma, N); [t, y] ode45(odefun, tspan, y0); % 提取结果 S y(:, 1); E y(:, 2); I y(:, 3); R y(:, 4); %% 4. 计算关键指标 R0_effective beta / gamma; fprintf(基本再生数 R0 %.2f\n, R0_effective); % 寻找感染峰值 [I_max, idx] max(I); t_peak t(idx); fprintf(感染峰值出现在第 %.1f 天 峰值感染人数为 %.0f\n, t_peak, I_max); %% 5. 绘图可视化 figure(Position, [100, 100, 1200, 500]) % 设置图形窗口大小 % 子图1四类人群随时间变化 subplot(1,2,1); plot(t, S, b-, LineWidth, 2); hold on; plot(t, E, m--, LineWidth, 1.5); plot(t, I, r-, LineWidth, 2); plot(t, R, g-, LineWidth, 2); hold off; grid on; xlabel(时间 (天)); ylabel(人数); title(SEIR模型人群动态); legend(易感者 S, 潜伏者 E, 感染者 I, 移除者 R, Location, best); % 标记峰值点 hold on; plot(t_peak, I_max, ro, MarkerSize, 10, MarkerFaceColor, r); text(t_peak5, I_max, sprintf(峰值: %.0f, I_max), FontSize, 10); hold off; % 子图2新增病例曲线 (dE/dt 或 dI/dt) subplot(1,2,2); % 新增潜伏者即新感染人数 beta*S*I/N new_cases beta * S .* I / N; plot(t, new_cases, k-, LineWidth, 2); grid on; xlabel(时间 (天)); ylabel(每日新增感染人数); title(每日新增感染人数曲线); % 可以添加移动平均线让曲线更平滑 % window 7; % 7天移动平均 % new_cases_smooth movmean(new_cases, window); % hold on; % plot(t, new_cases_smooth, b--, LineWidth, 1.5); % legend(每日新增, 7天移动平均, Location, best); % hold off; sgtitle([SEIR模型模拟 (R0, num2str(R0_effective, %.2f), )]); % 总标题代码要点与避坑指南函数定义必须将微分方程组单独写成一个函数文件如seir_ode.m输入是时间t和状态变量y输出是导数dydt。这是ode45要求的格式。参数传递使用匿名函数(t,y) seir_ode(t,y,beta,sigma,gamma,N)来将主程序中的参数传递给方程函数。这是最清晰的方式。初始条件y0必须是列向量。结果提取ode45返回的时间t和状态y都是列向量y的每一列对应一个状态变量。注意索引。绘图细节清晰的图例、标签、网格线和关键点标记如峰值能让你论文中的图表专业度提升一个档次。使用subplot对比不同曲线是常用技巧。4.3 Python (SciPy) 实现对比对于习惯Python的同学用scipy.integrate.solve_ivp可以实现同样功能语法也很类似。import numpy as np from scipy.integrate import solve_ivp import matplotlib.pyplot as plt # 参数设置 N 1000 I0, E0, R0 1, 0, 0 S0 N - I0 - E0 - R0 beta, sigma, gamma 0.6, 0.2, 0.1 t_span (0, 200) y0 [S0, E0, I0, R0] # 定义微分方程组 def seir_ode(t, y): S, E, I, R y dSdt -beta * S * I / N dEdt beta * S * I / N - sigma * E dIdt sigma * E - gamma * I dRdt gamma * I return [dSdt, dEdt, dIdt, dRdt] # 数值求解 sol solve_ivp(seir_ode, t_span, y0, methodRK45, dense_outputTrue, max_step1) t sol.t S, E, I, R sol.y # 计算R0和峰值 R0_eff beta / gamma I_max I.max() t_peak t[I.argmax()] print(f基本再生数 R0 {R0_eff:.2f}) print(f感染峰值出现在第 {t_peak:.1f} 天峰值感染人数为 {I_max:.0f}) # 绘图 plt.figure(figsize(14, 5)) plt.subplot(1, 2, 1) plt.plot(t, S, b-, labelSusceptible S, linewidth2) plt.plot(t, E, m--, labelExposed E, linewidth1.5) plt.plot(t, I, r-, labelInfectious I, linewidth2) plt.plot(t, R, g-, labelRemoved R, linewidth2) plt.scatter(t_peak, I_max, colorred, s100, zorder5) plt.text(t_peak5, I_max, fPeak: {I_max:.0f}, fontsize10) plt.grid(True) plt.xlabel(Time (days)) plt.ylabel(Population) plt.title(SEIR Model Dynamics) plt.legend() plt.subplot(1, 2, 2) new_cases beta * S * I / N plt.plot(t, new_cases, k-, linewidth2) plt.grid(True) plt.xlabel(Time (days)) plt.ylabel(Daily New Cases) plt.title(Daily New Infections) plt.suptitle(fSEIR Model Simulation (R0{R0_eff:.2f})) plt.tight_layout() plt.show()注意Python中solve_ivp返回的sol.y是一个形状为(4, n_points)的数组需要解包。methodRK45对应MATLAB的ode45。对于刚性问题可以尝试methodBDF。5. 参数估计与模型检验让模型“落地”这是建模中最容易失分也最能体现功力的环节。你建立了一个漂亮的模型但参数β, γ等是随便设的结果就毫无说服力。5.1 参数估计的两种主要思路基于文献与先验知识这是最常用的方法。例如对于流感平均感染期1/γ约为3-7天对于COVID-19潜伏期1/σ约为5-6天。R0值在疫情初期已有大量流行病学研究。在论文中你应该引用可靠的参考文献来说明你选取的参数范围是合理的。可以给出一个基准值然后进行灵敏度分析即观察参数在小范围内变动时结果如峰值人数、到达时间如何变化。这能说明模型的稳健性。基于数据的拟合如果题目提供了时间序列数据如每日新增病例数你可以用这些数据来反推模型参数。这本质上是一个优化问题寻找一组参数使得模型输出的曲线与实际数据的误差最小。目标函数通常采用最小二乘法最小化模型预测的新增病例数C_model(t)与实际数据C_data(t)的误差平方和min Σ [C_model(t) - C_data(t)]^2。优化算法MATLAB的fminsearch,lsqcurvefit或全局优化算法如ga(遗传算法)Python的scipy.optimize.curve_fit或lmfit库。实操步骤 a. 编写模型函数输入参数输出预测的时间序列。 b. 编写误差函数目标函数。 c. 调用优化函数进行求解。 d.非常重要优化结果对初始猜测值很敏感。多试几组不同的初始值避免陷入局部最优。同时参数必须有明确的物理意义和范围约束如所有速率必须为正数。5.2 模型检验你的模型靠谱吗参数拟合好后不能只用拟合的数据来评价模型。必须进行模型检验。内禀检验平衡点验证计算你模型的理论平衡点然后从平衡点附近的一个小扰动开始运行模拟看系统是否会回到该平衡点稳定性验证。守恒律验证对于总人口守恒的模型检查模拟结束时的SEIR是否始终等于初始总人口N允许有极小的数值误差。外部检验更具说服力预留数据法如果你有100天的数据只用前70天的数据来拟合参数。然后用拟合好的模型去“预测”后30天的情况并与实际的后30天数据对比。计算预测误差如均方根误差RMSE。如果预测效果尚可说明模型有一定的泛化能力。交叉验证将数据分成多份轮流用其中一部分拟合另一部分检验综合评估。在论文中你需要有一个独立的“模型检验”部分来展示这些工作。一张“拟合曲线与预测曲线对比图”加上误差分析远比干巴巴地说“模型良好”有力得多。6. 论文写作与可视化如何清晰呈现你的工作模型和求解做得再好如果表达不清评委也很难给出高分。6.1 论文中的模型表述公式排版使用公式编辑器LaTeX或Word的公式工具规范地书写微分方程。变量用斜体常数可用正体。给出每个变量的定义和单位如果适用。流程图在模型假设部分画一个仓室模型的流程图。用方框表示仓室箭头表示流动在箭头上标注转移速率。这能让人一眼看懂模型结构。例如[S] --βSI/N-- [I] --γI-- [R]。参数表格制作一个清晰的参数表列出所有符号、含义、单位、取值或取值范围、以及取值依据如“参考文献[1]”、“根据题目数据拟合”。符号含义单位取值/范围依据S(t)t时刻易感者数量人变量-β传染率天⁻¹0.4 - 0.8根据R0范围1.5-3.0及γ0.2反推1/γ平均感染期天5参考文献[2]R0基本再生数无量纲β/γ定义6.2 结果可视化技巧一图胜千言除了基本的人群动态图可以尝试以下更有信息量的图相图以S为横轴I为纵轴画出解曲线。可以直观展示系统演化的轨迹并标出平衡点。参数敏感性分析图用子图或三维曲面图展示关键结果如总感染人数、峰值时间随某个参数如β变化的趋势。干预措施对比图在同一张图上画出无干预、隔离降低β、缩短确诊时间增大γ等不同场景下的感染曲线。用不同线型和颜色区分并配以清晰图例。图表规范确保所有图表都有编号、标题坐标轴有明确的标签和单位。图中的线条、标记要清晰可辨。避免使用过于花哨的颜色和样式保持学术图表的简洁和严谨。6.3 灵敏度分析与模型讨论这是提升论文层次的关键部分。不要只给出一个结果要分析结果的可靠性。局部灵敏度分析计算某个输出变量对某个输入参数的偏导数或弹性。可以用“龙卷风图”来直观展示哪些参数对结果影响最大。情景分析基于参数的不确定性设计几种不同的情景如乐观、基准、悲观分别运行模型给出结果的范围。这比只给出一个“点估计”更科学。模型局限性讨论必须诚实地指出你模型的不足。例如“本文模型假设了均匀混合忽略了实际社交网络的结构特性”“未考虑年龄差异导致的易感性和传染性不同”“参数估计基于有限的历史数据存在不确定性”。指出局限性并给出可能的改进方向体现了批判性思维是加分项。7. 从经典到前沿随机微分方程与智能体建模浅析在掌握了确定性微分方程ODE之后如果你想在更复杂的赛题或研究生阶段建模中深入有两个方向值得了解。7.1 随机微分方程引入不确定性现实世界充满随机性。一个人的感染、康复时间并非完全确定。随机微分方程在确定性方程的基础上加入了随机项通常是布朗运动。核心思想将变化率dX/dt f(X,t)改为dX f(X,t)dt g(X,t)dW其中dW是随机噪声。应用场景金融资产定价如著名的Black-Scholes模型、种群动力学在随机环境下的演化、有噪声的物理系统。求解通常使用数值方法如Euler-Maruyama方法。MATLAB和Python都有相关工具箱。在建模中的价值你可以通过多次随机模拟得到结果的概率分布如疫情峰值有90%的可能性落在1000-1500人之间而不仅仅是一个确定值。这使预测更丰富也更符合实际。7.2 基于智能体的建模从宏观到微观ABM是另一种强大的建模范式与微分方程互补。核心思想不再关注群体的平均数量而是为系统中的每个个体智能体定义规则如移动规则、接触规则、状态转换规则通过大量个体的并行模拟自下而上地涌现出宏观现象。与微分方程对比特征微分方程模型基于智能体的模型视角宏观、自上而下微观、自下而上核心群体平均数量的变化率个体行为规则与交互异质性难以处理需用偏微分方程天然支持每个智能体属性可不同空间结构需显式引入扩散项易于实现在网格或连续空间移动计算成本低高取决于智能体数量输出确定性的平滑曲线随机的、可能重复模拟取平均如何选择如果你的赛题强调个体差异如不同年龄、职业、移动模式、复杂的空间互动或网络结构ABM可能是更好的选择。如果系统相对均匀关注宏观趋势微分方程更简洁高效。在论文中也可以将两者结合例如用微分方程做快速全局分析用ABM对特定复杂场景进行精细模拟。微分方程建模是数学建模的基石它强迫你去思考系统内在的动力学机制而不仅仅是数据的表面关联。从看懂一个经典的SIR模型到能根据具体问题灵活改造方程再到用代码实现求解、参数估计和结果分析这个过程本身就是一次完整的科研训练。我建议你不要止步于看懂这篇笔记而是打开MATLAB或Python把里面的代码敲一遍改变几个参数看看图形如何变化。然后找一道往年的赛题比如提到“传播”、“扩散”、“增长”、“控制”的尝试用微分方程的视角去分析哪怕先建立一个最简单的模型。实战中的一次次调试和迭代才是理解最深的学习方式。最后在论文写作时时刻想着你的读者用清晰的逻辑、直观的图表和严谨的分析带领他们理解你构建的这个“数学世界”。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进