SEICR模型

使用Python实现SEICR模型,模拟流行病传播过程


日期

1 概述

1.1 模型描述

SEICR模型适用于具有慢性期的传染病,其中S代表易感个体(Susceptible),E代表潜伏期个体(Exposed),I代表急性期感染个体(Infected),C代表慢性期个体(Chronic),R代表恢复个体(Recovered)。SEICR模型的基本原理是通过一系列参数化的传播、进展和恢复速率来描述易感个体被感染,潜伏期个体发展为急性感染,急性感染个体转变为慢性感染,以及感染个体最终恢复的过程。

1.2 模型假设

(1)急性感染病例与慢性感染病例具有相同的感染力,急性或慢性感染病例的传染率系数表示为β

(2)潜伏期为$\frac{1}{ω}$,则在t时刻,由E进展为I的人数为ωE

(3)感染个体进展到慢性期的比例为q,从 ICR 的速率为γ,则在t时刻,由 I 进展到 CR 的人数分别为 pγI(1−p)γI

(4)急性感染期通常症状较轻,不会危及生命,因此急性期不考虑因病死亡。

(5)假设所有的新生儿都易感,自然出生率为br,自然死亡率为dr,疾病的病死率为f

1.3 模型仓室及参数含义

表1 模型仓室含义

仓室 含义
易感者(S 尚未感染但易感的个体
潜伏者(E 已经被感染,处于潜伏期尚未具有传染性的个体
急性期感染者(I 感染后进入急性期出现症状并具有传染性的个体
慢性期感染者(C 感染后从急性期进入慢性期并具有传染性的个体
康复者(R 已经从疾病中恢复并获得免疫力的个体

表2 模型参数含义

参数 含义
β 病毒的传染率系数
ω 从暴露状态转为感染状态的速率
p 感染者进入慢性期的比例
γ 急性期感染者的恢复/进展速率
f 疾病的病死率
br 人群自然出生率
dr 人群自然死亡率
N 总人口数

2 模型流程图及方程

2.1 模型图

SEICR模型图

图1 SEICR传播动力学模型图

2.2 模型方程

$$ \begin{cases} \frac{dS}{dt}=b_rN-\frac{βS(I+C)}{N}-d_rS \\
\frac{dE}{dt}=\frac{βS(I+C)}{N}-ωE-d_rE \\
\frac{dI}{dt}=ωE-γI-d_rI \\
\frac{dC}{dt}=pγI-(d_r+f)C \\
\frac{dR}{dt}=(1-p)γI-d_rR \\
\end{cases} $$

3 适用疾病流行条件

SEICR模型适用于具有急性期与慢性期特征的传染病,特别是那些感染后可能发展为慢性状态,同时在急性期或慢性期具有传染性的疾病(如丙型肝炎)。该模型通过区分易感、潜伏、急性感染、慢性感染和恢复等不同状态,描述个体从感染到慢性状态的转变过程,以及疾病传播动态。该模型适用于能够通过有效治疗恢复的疾病,同时也考虑了慢性期感染者的疾病相关死亡风险。

4 代码

4.1 条件设定

表3 模型初始条件

仓室 初始值 单位
易感人群(S 99864
潜伏者(E 100
急性期感染者(I 36
慢性期感染者(C 0
康复者(R 0

表4 模型参数取值

参数 定义 取值 单位
β 病毒的传播率系数 0.3 1
ω 从暴露状态转为感染状态的速率 1/1.5 -1
p 急性感染者进入慢性期的比例 0.7 1
γ 急性期感染者的恢复/进展速率 1/6 -1
f 疾病的病死率 0.15 1
br 人群自然出生率 0.00021 1
dr 人群自然死亡率 0.00016 1
N 总人口数 100000

4.2 代码

这段代码以丙肝为例,使用 Python 实现了一个基于 SEICR 模型(Susceptible-Exposed-Infectious-Chronic-Recovered)的传染病动力学模拟,旨在通过实际观测数据(每日新增感染病例)拟合模型参数,特别是传染率系数β,以模拟和预测疾病的传播动态。以下是代码的工作流程:

(1)模型定义:通过 SEICR_model 函数定义传染病的动力学模型;

(2)准备数据:导入观测数据(I_obs)并设置初始条件;

(3)拟合模型:定义 model_fit 函数,用于计算模型输出(每日新增病例)并与观测数据进行比较,利用 solve_ivp 求解微分方程组,使用 lmfit 库的 Parameters 类设置模型参数及其初始值和边界,使模型输出与实际数据吻合,最后使用 lmfitModel 类进行拟合,调用 model.fit 方法优化参数;

(4)求解模型:带入拟合得到的参数使用 solve_ivp 求解微分方程,得到模型的状态变量。

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
import pandas as pd
from lmfit import Model, Parameters

# 定义ODE函数
def SEICR_model(t, y, beta, p, omega, gamma, f, br, dr, N):
    S, E, I, C, R, X = y

    dSdt = br * N - beta * S * (I + C) / N - dr * S
    dEdt = beta * S * (I + C) / N - omega * E - dr * E
    dIdt = omega * E - gamma * I - dr * I
    dCdt = p * gamma * I - (dr + f) * C
    dRdt = (1-p) * gamma * I - dr * R
    dXdt = omega * E          # 累计新发病例
    
    return [dSdt, dEdt, dIdt, dCdt, dRdt, dXdt]

# 原始数据
I_obs = [
    36, 37, 58, 55, 39, 52, 56, 38, 54, 34, 48, 51, 34, 38, 46, 49, 40, 65, 55, 61,
    59, 46, 57, 85, 64, 41, 78, 72, 67, 75, 63, 74, 77, 56, 81, 71, 52, 69, 83, 100,
    112, 95, 97, 114, 103, 90, 102, 106, 82, 70, 118, 113, 131, 120, 120, 153, 156, 124,
    117, 138, 139, 124, 149, 171, 176, 182, 176, 165, 200, 150, 186, 186, 165, 115, 219,
    234, 218, 235, 269, 191, 232, 176, 254, 282, 189, 132, 265, 246, 238, 257, 235, 254,
    249, 244, 250, 270, 180, 182, 296, 252, 266, 293, 271, 253, 247, 239, 284, 269, 252,
    145, 320, 304, 308, 267, 290, 300, 303, 244, 361, 339
]

# 初始参数设置参数 
beta = 0.3        # 病毒的传播率系数
omega = 1/1.5     # 相对潜伏率
gamma = 1/6       # 急性期感染者的恢复/进展速率
p = 0.7           # 感染者进入慢性期的比例
br = 0.00021      # 人群自然出生率
dr = 0.00016      # 人群自然死亡率
f = 0.15          # 疾病的病死率
N = 100000        # 总人口数

# 初始条件
E0 = 100
I0 = I_obs[0]
S0 = N - E0 - I0
C0 = 0
R0 = 0
X0 = I0

# 初始状态向量
initial_state = [S0, E0, I0, C0, R0, X0]

# 定义拟合函数
def model_fit(t, beta, p, omega, gamma, f, br, dr, N):

    # 调用ode求解
    result = solve_ivp(SEICR_model, (0, max(t)), initial_state, t_eval=t, args=(beta, p, omega, gamma, f, br, dr, N))

    # 计算每日新发病例:dX 的差分
    dX = np.diff(result.y[-1])               # X是累计新发病例,取其差值获得新发病例
    return np.concatenate([[I_obs[0]], dX])  # 保证返回的数组与原始长度一致

# 创建 lmfit 模型
model = Model(model_fit)

# 设置拟合参数及初始值和边界
params = Parameters()
params.add('beta', value=0.0005, min=0, max=1)

# 固定参数,不参与拟合
params.add('omega', value=1/1.5, vary=False)
params.add('gamma', value=1/6, vary=False)
params.add('p', value=0.7, vary=False)
params.add('br', value=0.00021, vary=False)
params.add('dr', value=0.00016, vary=False)
params.add('f', value=0.15, vary=False)
params.add('N', value=100000, vary=False)

# 模拟月份数
t = np.linspace(0, 119, 120)

# 使用 lmfit 进行拟合
result = model.fit(I_obs, params, t=t)

# 输出拟合报告
print(result.fit_report())

# 使用 solve_ivp 求解微分方程
solution = solve_ivp(SEICR_model, (0, max(t)), initial_state, args=(result.params['beta'], p, omega, gamma, f, br, dr, N), t_eval=t, method='RK45')
[[Model]]
    Model(model_fit)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 29
    # data points      = 120
    # variables        = 1
    chi-square         = 248907.034
    reduced chi-square = 2091.65574
    Akaike info crit   = 918.481160
    Bayesian info crit = 921.268652
    R-squared          = 0.74402581
[[Variables]]
    beta:   0.12785792 +/- 3.6004e-04 (0.28%) (init = 0.0005)
    omega:  0.6666667 (fixed)
    gamma:  0.1666667 (fixed)
    p:      0.7 (fixed)
    br:     0.00021 (fixed)
    dr:     0.00016 (fixed)
    f:      0.15 (fixed)
    N:      100000 (fixed)

4.3 结果可视化

这段代码使用 Matplotlib 库绘制了传染病模型的拟合结果,具体解决了以下问题:

  1. 可视化拟合效果
    • 通过绘制散点图(plt.plot(t, I_obs, 'ro'))展示实际的每日新增病例数据(I_obs)。
    • 通过绘制曲线图(plt.plot(t, result.best_fit, 'b-'))展示模型拟合的每日新增病例数据(result.best_fit)。
  2. 图像标注与保存
    • 使用 plt.xlabelplt.ylabel 分别标注横轴(时间,单位为月)和纵轴(每日新增病例数)。
    • 使用 plt.legend 添加图例,区分实际数据和拟合数据。
    • 使用 plt.savefig 将绘制的图像保存为 PNG 文件(fitted_results.png)。
  3. 展示图像
    • 使用 plt.show 在屏幕上显示绘制的图像。
# 绘制拟合结果
plt.figure(figsize=(10,6))
plt.plot(t, I_obs, 'ro', label='Actual Daily Cases')
plt.plot(t, result.best_fit, 'b-', label='Fitted Daily Cases')
plt.xlabel('Time (months)')
plt.ylabel('Daily Cases')
plt.legend()

# 保存图像
plt.savefig("fitted_results.png")  # 保存为 PNG 文件

plt.show()

fitted_results

图2 模型拟合效果图

这段代码使用 Matplotlib库对SEICR 模型的模拟结果进行可视化,具体解决了以下问题:

  1. 可视化模型结果
    • 代码从 solution 对象中提取了时间 t 和各状态变量(S, E, I, C, R, X),分别表示易感者、暴露者、感染者、慢性感染者、康复者和累计新发病例。
    • 使用 Matplotlib 创建了一个 2x1 的子图布局:
      • 第一个子图:绘制易感者(S)随时间的变化,展示易感人群的动态。
      • 第二个子图:绘制暴露者(E)、感染者(I)、慢性感染者(C)和康复者(R)随时间的变化,展示其他人群的动态。
  2. 图像标注与美化
    • 使用 set_xlabelset_ylabel 为每个子图添加横轴(时间,单位为月)和纵轴(人数)的标签。
    • 使用 set_title 为每个子图添加标题。
    • 使用 legend 添加图例,区分不同的状态变量。
    • 使用 grid(True) 为每个子图添加网格线,便于观察数据趋势。
  3. 保存与展示图像
    • 使用 plt.tight_layout() 调整子图布局,避免重叠。
    • 使用 plt.savefig 将绘制的图像保存为 PNG 文件(SEICR.png)。
    • 使用 plt.show 在屏幕上显示图像。
import numpy as np
import matplotlib.pyplot as plt

# 提取结果
t = solution.t
S, E, I, C, R, X = solution.y

# 创建一个2x1的子图
fig, axs = plt.subplots(2, 1, figsize=(12, 12))

# 绘制易感人群子图 (S)
axs[0].plot(t, S, label="Susceptible (S)", color="blue")
axs[0].set_xlabel("Time (months)")
axs[0].set_ylabel("Number of people")
axs[0].set_title("SEICR Simulation (S)")
axs[0].legend()
axs[0].grid(True)

# 绘制剩余人群部分的子图 (E, I, C, R)
axs[1].plot(t, E, label="Exposed (E)", color="orange")
axs[1].plot(t, I, label="Infected (I)", color="red")
axs[1].plot(t, C, label="Chronic (C)", color="gray")
axs[1].plot(t, R, label="Recovered (R)", color="green")
axs[1].set_xlabel("Time (months)")
axs[1].set_ylabel("Number of people")
axs[1].set_title("SEICR Simulation (E, I, C, R)")
axs[1].legend()
axs[1].grid(True)

# 调整布局
plt.tight_layout()

# 保存图像
plt.savefig("SEICR.png")  # 保存为 PNG 文件

# 显示图像
plt.show()

SEICR

图3 模型仿真结果图

4.4 结果分析

(1)易感人群(S:易感人群数量呈持续下降趋势,从接近10万人减少到约8.4万人左右。这种下降是因为易感人群逐渐通过暴露(E)转化为感染者(I)或慢性患者(C),最终减少了总易感人群。这一结果表明疾病正在社区传播,健康个体逐渐被暴露于疾病的风险中,这可能是由于传染性强或者接触率较高。

(2)暴露人群(E:暴露人群缓慢上升,但数量较低,始终在较低水平。这表明暴露阶段较短,个体快速转化为感染者(I),符合丙肝潜伏期较短的特性。

(3)感染人群(I:感染人群增长显著,约在60个月后(5年),感染人群达到高峰,随后增速减缓。

(4)慢性患者(C:慢性患者人数缓慢增加,到120个月(10年)时达到稳定值。这表明部分急性感染者转化为慢性患者,符合丙肝的特点(急性转慢性几率高)。

(5)恢复人群(R:恢复人群显著增长,到120个月时成为最大人群。通过自然免疫或治疗措施,感染者逐渐康复,形成免疫,减少了传播链。

5 扩展

(1)疫苗接种:疫苗接种可以使一部分易感者直接获得免疫力,从而从易感人群(S)仓室转移到康复者(R)仓室(假设疫苗提供完全免疫)。这相当于减少了初始的易感人群数量。在模型中,可以通过增加疫苗接种率 φS→R 的流向来表示。

(2)引入抗病毒治疗:引入针对感染者 I 和慢性感染者 C 的抗病毒治疗机制,将部分感染者转化为恢复者R。假设治疗比例为假设治疗比例为θ,且慢性患者治疗成功比例为θc,参数 θθc 分别用于调整感染者(I)和慢性感染者(C)转化为康复者(R)的速率,体现在模型中对 IC 的动态方程中。可以用于模拟抗病毒药物的推广效果,评估治疗覆盖率和治疗成功率对疾病流行的影响。

(3)隔离措施(减少 I 仓室的人群数量):引入隔离措施,增加隔离比例q、隔离仓室 Q 以及 IQCQ 的流向,模拟将急性和慢性期病人隔离后的传播能力。

(4)引入免疫衰退机制:考虑部分恢复者的免疫会随着时间衰退,重新回到易感状态,添加免疫衰退率 δRS 的流向。

柯妍姝
发呆业务爱好者