SEIR и эффект карантина
У многих болезней между заражением и заразностью проходит время. Чтобы это учесть, к модели SIR добавляют ещё одну группу — и получают SEIR.
Модель SEIR — расширение SIR с дополнительным классом E (Exposed): человек уже заразился, но пока не заразен — он находится в инкубационном периоде. Переходы идут по цепочке S → E → I → R.
В SIR заражённый человек становится заразным мгновенно. Но у кори, гриппа и многих других болезней есть инкубационный период: возбудитель уже в организме, а передавать его человек ещё не может. Класс E (Exposed, «контактировавший») как раз описывает эту фазу. Зачем это нужно? Игнорировать инкубацию — значит ускорять модель: без задержки эпидемия в расчётах разгоняется раньше и пик приходит быстрее, чем в реальности. SEIR делает динамику точнее для болезней с заметным скрытым периодом.
Новый класс E и коэффициент sigma
Добавляется ещё один резервуар между S и I:
S --> E --> I --> R
| |
заразился, переходит в
не заразен заразную фазу
Скорость перехода E → I задаёт коэффициент sigma. Он обратен средней длительности инкубации: если sigma = 0.2, человек проводит в группе E в среднем 1/sigma = 5 дней, а потом становится заразным. Заражение теперь переводит людей из S в E (а не сразу в I), и заражают по-прежнему только те, кто в группе I.
Считаем SEIR
def seir(S, E, I, R, beta, sigma, gamma, days):
N = S + E + I + R
out = []
for d in range(days):
new_exp = beta * S * I / N
new_inf = sigma * E
new_rec = gamma * I
S -= new_exp
E += new_exp - new_inf
I += new_inf - new_rec
R += new_rec
out.append((d, S, E, I, R))
return out
res = seir(990, 0, 10, 0, 0.5, 0.2, 0.1, 80)
print(f"{'день':>4} {'S':>7} {'E':>7} {'I':>7} {'R':>7}")
for d, S, E, I, R in res[::15]:
print(f"{d:>4} {S:>7.1f} {E:>7.1f} {I:>7.1f} {R:>7.1f}")
peak = max(res, key=lambda t: t[3])
print(f"Пик заражённых: день {peak[0]}, I={peak[3]:.1f}")
Вывод:
день S E I R 0 985.0 5.0 9.0 1.0 15 818.5 79.5 64.3 37.7 30 228.9 201.1 289.8 280.1 45 21.4 40.6 219.5 718.5 60 7.4 3.9 65.1 923.6 75 5.6 0.5 15.5 978.4 Пик заражённых: день 35, I=319.2
Видно, как группа E «бежит впереди» I: число контактировавших нарастает раньше, чем число заразных, ведь людям нужно сначала пройти инкубацию. Из-за этой задержки пик заражённых приходит позже, чем пришёл бы в SIR с теми же параметрами.
Эффект карантина: снижаем beta
Карантин, маски, дистанция, ограничение контактов — всё это уменьшает число встреч «восприимчивый — заражённый», то есть снижает коэффициент beta. Посмотрим на модели SIR, что даёт снижение beta вдвое (с 0.3 до 0.15), сравнив день и высоту пика.
def sir_peak(beta, gamma=0.1, days=200):
S, I, R, N = 990.0, 10.0, 0.0, 1000.0
peak_day, peak_I = 0, I
for d in range(days):
new_inf = beta * S * I / N
new_rec = gamma * I
S -= new_inf
I += new_inf - new_rec
R += new_rec
if I > peak_I:
peak_I, peak_day = I, d
return peak_day, peak_I
for label, beta in (("без мер", 0.3), ("карантин", 0.15)):
d, pi = sir_peak(beta)
print(f"{label:>10}: R0={beta/0.1:.1f} пик день {d:>3} I={pi:.1f}")
Вывод:
без мер: R0=3.0 пик день 27 I=315.9 карантин: R0=1.5 пик день 65 I=70.7
Что такое «сглаживание кривой»
Сравним два сценария. Без мер R0 = 3.0: пик приходит уже на 27-й день и достигает почти 316 заражённых одновременно. С карантином beta снижается вдвое, R0 падает до 1.5: пик сдвигается на 65-й день и составляет всего около 71 заражённого. Это и есть сглаживание кривой (англ. flatten the curve): мера не обязательно уменьшает итоговое число переболевших до нуля, но делает пик ниже (315.9 → 70.7) и позже (день 27 → день 65).
Почему это важно с точки зрения моделирования? Высота пика — это число людей, которым помощь нужна одновременно. Растягивая эпидемию во времени, мы распределяем эту нагрузку на больший период, и в каждый отдельный момент она ниже. Площадь под кривой (всего случаев) меняется не так сильно, как её высота, но именно высота определяет одномоментную нагрузку. Поэтому снижение beta — ключевой рычаг в моделях эпидемий.
Как работает под капотом
В функции seir добавлен один поток: new_exp = beta * S * I / N переводит людей из S в E, а отдельный поток new_inf = sigma * E — из E в I. Заметьте, что заражают по-прежнему только люди из группы I: в члене заражения стоит I, а не E, ведь в инкубации человек ещё не заразен. Группа E получает приток из S и отдаёт в I — отсюда её «горб», смещённый влево относительно горба I.
В функции sir_peak мы не сохраняем всю историю, а на ходу запоминаем максимум: условие if I > peak_I обновляет рекорд, как только текущее I превышает прежний максимум. Это экономный способ найти высоту и день пика, не храня список всех дней. Снижение beta вдвое уменьшает R0 с 3 до 1.5 — и пик становится и ниже, и позже.
Частые ошибки
- Думать, что люди из E заражают других. В инкубационном периоде человек заразиться уже успел, но передавать болезнь ещё не может — в члене заражения стоит I, не E.
- Считать, что карантин всегда обнуляет эпидемию. Снижение beta сглаживает и откладывает пик; полностью остановить вспышку оно может, только если опустит R0 ниже 1.
- Сравнивать сценарии лишь по итоговому числу переболевших. Главный эффект сглаживания — в высоте и времени пика, а не в площади под кривой.
- Путать sigma и gamma. sigma управляет выходом из инкубации (E → I), gamma — выздоровлением (I → R).
- Забывать, что добавление E замедляет старт эпидемии: при тех же beta и gamma пик в SEIR приходит позже, чем в SIR.
Итоги
- SEIR добавляет к SIR класс E (Exposed) — заразившихся, но ещё не заразных; цепочка переходов S → E → I → R.
- Коэффициент sigma задаёт скорость выхода из инкубации; средняя длительность инкубации равна 1/sigma.
- SEIR нужен для болезней с заметным инкубационным периодом — он замедляет и сдвигает пик.
- Карантин и ограничение контактов снижают beta, а значит и R0.
- Сглаживание кривой (flatten the curve): пик ниже (315.9 → 70.7) и позже (день 27 → 65), нагрузка растягивается во времени.