流行の伝播を可視化する
流行伝播モデルというものがある.
次の3つを想定してそれぞれの状態のシミュレーションを行うモデルである.
• S (Susceptible): 感受性者。まだ感染しておらず、感染の可能性がある人。
• I (Infectious): 感染者。感染しており、他者に感染させる可能性がある人。
• R (Removed/Recovered): 除去者。回復して免疫を獲得した人、または死亡・隔離された人。
今回はこれをやってみた.コードは下記.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 個体数を設定
N = 200
# 感染の初期設定
infected_ratio = 0.05 # 初期感染者の割合
initial_infected = int(N * infected_ratio)
# シミュレーションパラメータ
steps = 200 # シミュレーションのステップ数
infection_radius = 0.02 # 感染が起こる距離の範囲
infection_probability = 0.2 # 接触時の感染確率
recovery_time = 50 # 感染者が回復するまでのステップ数
# 個体の状態を表すクラス
class Agent:
def __init__(self):
# 個体の初期位置をランダムに設定
self.position = np.random.rand(2)
# ランダムな移動方向を設定
angle = np.random.uniform(0, 2 * np.pi)
self.velocity = np.array([np.cos(angle), np.sin(angle)]) * 0.01
# 状態の初期設定(0: 感受性者、1: 感染者、2: 除去者)
self.state = 0
# 感染してからの経過時間
self.infected_time = 0
def move(self):
# 個体を移動させる
self.position += self.velocity
# 境界条件(トーラス状にするために座標を0-1の範囲に収める)
self.position = self.position % 1.0
def update(self):
if self.state == 1:
# 感染者の経過時間を増加
self.infected_time += 1
if self.infected_time >= recovery_time:
# 回復して除去者になる
self.state = 2
# 個体のリストを作成
agents = [Agent() for _ in range(N)]
# 初期感染者を設定
for agent in np.random.choice(agents, initial_infected, replace=False):
agent.state = 1
# 可視化の準備
fig, ax = plt.subplots(figsize=(6,6))
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_title('SIR Model Simulation')
ax.set_xticks([])
ax.set_yticks([])
# 状態ごとにプロットを用意
scat_susceptible, = ax.plot([], [], 'bo', markersize=4, label='Susceptible')
scat_infected, = ax.plot([], [], 'ro', markersize=4, label='Infected')
scat_recovered, = ax.plot([], [], 'go', markersize=4, label='Recovered')
ax.legend(loc='upper right')
# アニメーションの初期化関数
def init():
scat_susceptible.set_data([], [])
scat_infected.set_data([], [])
scat_recovered.set_data([], [])
return scat_susceptible, scat_infected, scat_recovered
# アニメーションのフレーム更新関数
def update(frame):
susceptible_x = []
susceptible_y = []
infected_x = []
infected_y = []
recovered_x = []
recovered_y = []
# 各個体の状態を更新
for agent in agents:
agent.move()
agent.update()
# 感染の判定
positions = np.array([agent.position for agent in agents])
states = np.array([agent.state for agent in agents])
for i, agent in enumerate(agents):
if agent.state == 1:
# 感受性者との距離を計算
distances = np.linalg.norm(positions - agent.position, axis=1)
for j, other_agent in enumerate(agents):
if states[j] == 0 and distances[j] < infection_radius:
if np.random.rand() < infection_probability:
other_agent.state = 1
# 状態ごとに位置を集計
for agent in agents:
if agent.state == 0:
susceptible_x.append(agent.position[0])
susceptible_y.append(agent.position[1])
elif agent.state == 1:
infected_x.append(agent.position[0])
infected_y.append(agent.position[1])
else:
recovered_x.append(agent.position[0])
recovered_y.append(agent.position[1])
scat_susceptible.set_data(susceptible_x, susceptible_y)
scat_infected.set_data(infected_x, infected_y)
scat_recovered.set_data(recovered_x, recovered_y)
return scat_susceptible, scat_infected, scat_recovered
# アニメーションの作成
ani = FuncAnimation(fig, update, frames=steps, init_func=init, blit=True, interval=50)
# GIFとして保存
ani.save('sir_agent_simulation.gif', writer='pillow')
plt.show()
参考文献
- MAS コミュニティ 流行伝播モデルhttps://mas.kke.co.jp/model/trend_model/