流行の伝播を可視化する


流行伝播モデルというものがある.

次の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()

参考文献

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です