使用Python实现跨年龄组SEPIAR模型,模拟流行性腮腺炎等传染病的传播及恢复过程
该模型将人群分为0-14岁组(youth,简称y)和14岁以上组(old people,简称o)
以0-14岁组为例:
1.一例染病者与易感者有效接触后即具有一定传染力,传染率系数为β;则单位时间内产生新病例(易感者变为染病者)的速度为 $S_yβ_yy(I_y+k_1A_y+k_2P_y)+S_yβ_oy(I_o+k_1A_o+k_2P_o$;
2.无症状感染者的比例为ρ,暴露的个体分别经过潜伏期(1/ω_1)、潜伏期(1/ωv2)、潜伏期(1/ω_3)后成为无症状、症状前、有症状的病例;t时刻,从E变为A和P的人数分别为$ρω_1E_m$和$(1-ρ)ω_2E_m$,从P变为I的人数为ω_3P_m;模型假设潜伏期等于潜隐期;
3.有症状和无症状的病例分别在感染期为1/γ和1/γ_1后转移到恢复/清除的人。
4.恢复者在研究期间内具有免疫力,不会被感染;
5.不考虑种群流动性,考虑自然出生和死亡,自然出生率为b_r,自然死亡率为d_r;自然出生的个体均为易感者。
易感者-暴露者-症状前者-显性感染者-隐性感染者-恢复者(Susceptible–Exposed–Pre-symptomatic–Infectious–Asymptomatic–Recovered,SEPIAR)模型是基于人群在传染病传播过程中的不同状态划分来描述疾病动态变化的一种数学模型。它假设人群可以被分为易感者(Susceptible,S)、潜伏者(Exposed,E)、症状前期者(Pre-symptomatic,P)感染者(Infectious,I)、潜伏期者(Asymptomatic,A)康复者(Recovered,R)这几个相互关联的仓室。这些仓室之间通过一定的转移速率相互联系,反映了疾病传播、发展等过程。
仓室 | 含义 |
---|---|
S(Susceptible) | 易感者,指在一个特定人群中,那些没有对某种传染病病原体产生特异性免疫,且在接触到足够量的病原体时具有感染风险的个体集合。 |
E(Exposed) | 潜伏者,指已经感染了传染病病原体,但尚未出现临床症状,也暂时不具有传染性的个体集合。 |
P(Pre-symptomatic) | 症状前期者,指已经感染了传染病病原体,尚未出现临床症状,但具有传染性的个体集合,未来将呈现临床症状。 |
I(Infectious) | 感染者,指已经感染病原体并且开始出现临床症状,能够将病原体传播给易感人群的个体集合。 |
A(Asymptomatic) | 隐性感染者,指已经感染病原体,且具有传染性,但始终无临床症状的个体集合。 |
R(Recovered) | 康复者,指曾经感染了传染病病原体,经过自身免疫系统的作用或者医疗干预后,临床症状消失并且在研究期间内具有免疫力的个体集合。 |
参数 | 含义 | 单位 |
---|---|---|
d_r | 出生率 | 月^-1 |
b_r | 死亡率 | 月^-1 |
β_yy | 0 - 14岁组间传播能力系数 | 月^-1 |
β_oy | 14岁以上对0 - 14岁组间传播能力系数 | 月^-1 |
β_oo | 14岁以上组间传播能力系数 | 月^-1 |
β_yo | 0 - 14岁对14岁以上组间传播能力系数 | 月^-1 |
k_1 | 无症状个体与有症状个体的相对传播率 | 1 |
k_2 | 无症状前个体与有症状个体的相对传播率 | 1 |
ρ | 无症状个体比例 | 1 |
ω_1 | 潜伏期相对率 | 月^-1 |
ω_2 | 非传染性相对率 | 月^-1 |
ω_3 | 传染性相对率 | 月^-1 |
γ | 隐性感染者恢复速率 | 月^-1 |
γ_1 | 显性感染者恢复速率 | 月^-1 |
以下是SEPIAR模型的流程图 图1 SEITA模型的流程图
$$
\begin{align*}
\frac{dS_y}{dt}&=N_ybr - S_y\beta_{yy}\frac{(I_y + k_1A_y + k_2P_y)}{N_y}-S_y\beta_{oy}\frac{(I_o + k_1A_o + k_2P_o)}{N_y}-drS_y\\
\frac{dE_y}{dt}&=S_y\beta_{yy}\frac{(I_y + k_1A_y + k_2P_y)}{N_y}+S_y\beta_{oy}(I_o + k_1A_o + k_2P_o)-N_y\rho\omega_1E_y-(1-\rho)\omega_2E_y-drE_y\\
\frac{dA_y}{dt}&=\rho\omega_1E_y-\gamma A_y-drA_y\\
\frac{dP_y}{dt}&=(1-\rho)\omega_2E_y-\omega_3P_y-drP_y\\
\frac{dI_y}{dt}&=\omega_3P_y-\gamma_1I_y-drI_y\\
\frac{dR_y}{dt}&=\gamma A_y+\gamma_1I_y-drR_y\\
\frac{dS_o}{dt}&=N_obr - S_o\beta_{oo}\frac{(I_o + k_1A_o + k_2P_o)}{N_o}-S_{yi}o\beta_{yo}\frac{(I_{yi}+k_1A_{yi}+k_2P_{yi})}{N_o}-drS_o\\
\frac{dE_o}{dt}&=S_o\beta_{oo}\frac{(I_o + k_1A_o + k_2P_o)}{N_o}+S_{yi}o\beta_{yo}\frac{(I_{yi}+k_1A_{yi}+k_2P_{yi})}{N_o}-\rho\omega_1E_o-(1-\rho)\omega_2E_o-drE_o\\
\frac{dA_o}{dt}&=\rho\omega_1E_o-\gamma A_o-drA_o\\
\frac{dP_o}{dt}&=(1-\rho)\omega_2E_o-\omega_3P_o-drP_o\\
\frac{dI_o}{dt}&=\omega_3P_o-\gamma_1I_o-drI_o\\
\frac{dR_o}{dt}&=\gamma A_o+\gamma_1I_o-drR_o
\end{align*}
$$
SEPIAR模型适合在传染病暴发或流行疫情中模拟,且该传染病有一定潜伏期、潜伏期内具有传染病、具有一定比例的隐性感染者、在研究期间恢复者对病原体有免疫力,例如流行性腮腺炎、新型冠状病毒肺炎等。
在此代码中,我们使用以下条件进行 SEITA 模型模拟:
#4.1 代码
#导入包
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
import pandas as pd
from lmfit import Model, Parameters
# 定义带季节性参数的传播模型
def f(t, y, br, dr, ny, no, betayy_base, betaoy_base, betaoo_base, betayo_base, rho, omega1, omega2, omega3, gamma, gamma1, k1, k2):
Sy, Ey, Ay, Py, Iy, Ry, So, Eo, Ao, Po, Io, Ro = y
# 计算季节性调整的 beta 值,以12个月为一个周期,t - 20用于调节高峰位置,用sin函数模拟季节性波动,其中该函数“+1”是为保证该调整因子始终大于0
betayy = betayy_base * (1 + np.sin((t - 20) * 2 * np.pi / 12))
betaoy = betaoy_base * (1 + np.sin((t - 20) * 2 * np.pi / 12))
betaoo = betaoo_base * (1 + np.sin((t - 20) * 2 * np.pi / 12))
betayo = betayo_base * (1 + np.sin((t - 20) * 2 * np.pi / 12))
# 计算传播动力学模型
dSy_dt = ny * br - Sy * betayy * (Iy + k1 * Ay + k2 * Py) / ny - Sy * betaoy * (Io + k1 * Ao + k2 * Po) / ny - dr * Sy
dEy_dt = Sy * betayy * (Iy + k1 * Ay + k2 * Py) / ny + Sy * betaoy * (Io + k1 * Ao + k2 * Po) / ny - rho * omega1 * Ey - (1 - rho) * omega2 * Ey - dr * Ey
dAy_dt = rho * omega1 * Ey - gamma * Ay - dr * Ay
dPy_dt = (1 - rho) * omega2 * Ey - omega3 * Py - dr * Py
dIy_dt = omega3 * Py - gamma1 * Iy - dr * Iy
dRy_dt = gamma * Ay + gamma1 * Iy - dr * Ry
dSo_dt = So * betaoo * (Io + k1 * Ao + k2 * Po) / no - So * betayo * (Iy + k1 * Ay + k2 * Py) / no - dr * So
dEo_dt = So * betaoo * (Io + k1 * Ao + k2 * Po) / no + So * betayo * (Iy + k1 * Ay + k2 * Py) / no - rho * omega1 * Eo - (1 - rho) * omega2 * Eo - dr * Eo
dAo_dt = rho * omega1 * Eo - gamma * Ao - dr * Ao
dPo_dt = (1 - rho) * omega2 * Eo - omega3 * Po - dr * Po
dIo_dt = omega3 * Po - gamma1 * Io - dr * Io
dRo_dt = gamma * Ao + gamma1 * Io - dr * Ro
# 返回微分方程的结果
return [dSy_dt, dEy_dt, dAy_dt, dPy_dt, dIy_dt, dRy_dt, dSo_dt, dEo_dt, dAo_dt, dPo_dt, dIo_dt, dRo_dt]
# 拟合函数,计算季节性参数影响后的结果
def fit_func(t, betayy_base, betaoy_base, betaoo_base, betayo_base):
# 初始条件假设,可根据实际情况调整
Ey0 = 100
Ay0 = 5
Py0 = 10
Ry0 = 0
Eo0 = 20
Ao0 = 1
Po0 = 2
Ro0 = 0
Sy0 = ny - Ey0 - Iy0 - Ay0 - Py0 - Ry0
So0 = no - Eo0 - Io0 - Ao0 - Po0 - Ro0
y0 = [Sy0, Ey0, Ay0, Py0, Iy0, Ry0, So0, Eo0, Ao0, Po0, Io0, Ro0]
# 求解微分方程组,使用四阶龙格-库塔法
result = solve_ivp(f, [t[0], t[-1]], y0, args=(
br, dr, ny, no, betayy_base, betaoy_base, betaoo_base, betayo_base, rho, omega1, omega2, omega3, gamma, gamma1, k1, k2), t_eval=t)
return [result.y[4], result.y[10]]
# 读取数据
data = pd.read_csv('./SEPIAR_data.csv', encoding='gbk')
t_data = np.arange(0, 48)
Iy_data = data.iloc[:, 1]
Io_data = data.iloc[:, 2]
Iy0 = Iy_data[0]
Io0 = Io_data[0]
# 模型参数设置
ny = 3350788 #0-14岁人口数
no = 23918526 #14岁以上人口数
br = 0.00789/12 #出生率
dr = 0.00532/12 #死亡率
k1 = 0.3 #无症状个体与有症状个体的相对传播率
k2 = 0.3 #无症状前个体与有症状个体的相对传播率
rho = 0.2 #无症状个体比例
omega1 = 1/3 #E至A的速率
omega2 = 1/3 #E至P的速率
omega3 = 1 #P至I的速率
gamma = 1/2 #A至R的速率
gamma1 = 1/2 #I至R的速率
params = Parameters()
params.add('betayy_base',min = 0.55, max = 1)
params.add('betayo_base', min = 0.1, max = 0.5)
params.add('betaoo_base', min = 0.05, max = 0.1)
params.add('betaoy_base', min = 0.1, max = 0.5)
#拟合
fit_model = Model(fit_func)
result1 = fit_model.fit([Iy_data, Io_data], params, t=t_data)
#输出拟合结果
result1
Model: Model(fit_func)
fitting method | leastsq |
# function evals | 184 |
# data points | 96 |
# variables | 4 |
chi-square | 5306.04840 |
reduced chi-square | 57.6744391 |
Akaike info crit. | 393.176429 |
Bayesian info crit. | 403.433821 |
R-squared | 0.82195060 |
name | value | standard error | relative error | initial value | min | max | vary |
---|---|---|---|---|---|---|---|
betayy_base | 0.55000020 | 0.72893103 | (132.53%) | 0.55 | 0.55000000 | 1.00000000 | True |
betayo_base | 0.11545244 | 1.27156585 | (1101.38%) | 0.1 | 0.10000000 | 0.50000000 | True |
betaoo_base | 0.09998737 | 8.61764998 | (8618.74%) | 0.05 | 0.05000000 | 0.10000000 | True |
betaoy_base | 0.28027886 | 4.43025605 | (1580.66%) | 0.1 | 0.10000000 | 0.50000000 | True |
Parameter1 | Parameter 2 | Correlation |
---|---|---|
betayy_base | betaoy_base | -1.0000 |
betayo_base | betaoo_base | +0.9999 |
betayo_base | betaoy_base | +0.2901 |
betaoo_base | betaoy_base | +0.2900 |
betayy_base | betayo_base | -0.2865 |
betayy_base | betaoo_base | -0.2864 |
#绘图
plt.figure(figsize=(10, 6))
plt.plot(t_data, Iy_data, label='Iy Data')
plt.plot(t_data, Io_data, label='Io Data')
plt.plot(t_data, result1.best_fit[0], 'r-', label='Best Iy Fit')
plt.plot(t_data, result1.best_fit[1], label='Best Io Fit')
plt.xlabel('Time (days)')
plt.ylabel('Infected')
plt.title('Model Fit to Data')
plt.legend()
plt.grid(True)
# plt.savefig("C:/Users/86187/Desktop/图.svg")
plt.show()
图2 拟合结果图
# 绘制舱室的变化曲线
plt.figure(figsize=(10, 6))
# 使用拟合函数计算所有状态变量
all_states = fit_func(t_data, result1.params['betayy_base'].value, result1.params['betayo_base'].value, result1.params['betaoo_base'].value, result1.params['betaoy_base'].value)
Ey0 = 80
Ay0 = 10
Py0 = 10
Ry0 = 0
Eo0 = 10
Ao0 = 2
Po0 = 2
Ro0 = 0
Sy0 = ny - Ey0 - Iy0 - Ay0 - Py0 - Ry0
So0 = no - Eo0 - Io0 - Ao0 - Po0 - Ro0
y0 = [Sy0, Ey0, Ay0, Py0, Iy0, Ry0, So0, Eo0, Ao0, Po0, Io0, Ro0]
# 求解 ODE 以获取所有状态变量
result = solve_ivp(f, [t_data[0], t_data[-1]], y0, args=(br, dr, ny, no, result1.params['betayy_base'].value, result1.params['betayo_base'].value, result1.params['betaoo_base'].value, result1.params['betaoy_base'].value, rho, omega1, omega2, omega3, gamma, gamma1, k1, k2), t_eval=t_data)
Sy_fit, Ey_fit, Py_fit, Iy_fit, Ay_fit, Ry_fit, So_fit, Eo_fit, Po_fit, Io_fit, Ao_fit, Ro_fit = result.y
#plt.plot(t_data, Sy_fit, label='Sy')
plt.plot(t_data, Ey_fit, label='Ey')
plt.plot(t_data, Py_fit, label='Py')
plt.plot(t_data, Iy_fit, label='Iy')
plt.plot(t_data, Ay_fit, label='Ay')
plt.plot(t_data, Ry_fit, label='Ry')
#plt.plot(t_data, So_fit, label='So')
plt.plot(t_data, Eo_fit, label='Eo')
plt.plot(t_data, Po_fit, label='Po')
plt.plot(t_data, Io_fit, label='Io')
plt.plot(t_data, Ao_fit, label='Ao')
plt.plot(t_data, Ro_fit, label='Ro')
plt.xlabel('Time(days)')
plt.ylabel('Individuals')
plt.legend()
plt.title('SEPIAR Model Dynamics')
plt.tight_layout()
#plt.savefig("SEPIAR dynamic")
plt.show()
图3 仓室动态图
1.拟合效果:R2=0.82,拟合效果良好
2.betayy=0.55,betayo=0.12,betaoo=0.09,betaoy=0.28,即0-14岁组间的传染率系数最高,14岁以上组间的传染率系数最低
3.若维持现有的知晓率、治疗率、治疗有效率,发病人数将逐年增加
在SEPIAR模型中,易感者(S)转变为潜伏者(E)的主要驱动力是易感者与感染者(I)的接触。通过社交隔离,如限制人群聚集活动、关闭公共场所、要求人们保持社交距离等方式,可以降低易感者和感染者之间的有效接触率。在模型中,这可以通过降低感染率参数来体现。
及时发现并隔离感染者,可以减少他们与易感人群的接触机会,从而降低他们的有效传播能力。在模型中,可以通过降低感染率β来模拟这种干预措施。此外,对密切接触者进行追踪和隔离,能够进一步减少疾病的传播途径,这相当于从源头上减少了从S到E的流量。
疫苗接种可以使一部分易感者直接获得免疫力,从而从易感人群(S)仓室转移到康复者(R)仓室(假设疫苗提供完全免疫)。这相当于减少了初始的易感人群数量。在模型中,可以通过在初始条件中降低S的数量或者设置一个随时间变化的函数来表示疫苗接种导致的S的减少。