流行の伝播の可視化の改善


以前の投稿で,流行伝播モデルというものを見た.

今回はその発展として状態推移を折れ線グラフとして可視化した.こうすることで数という観点からの推移がわかりやすくなる.

コードは下記.

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  # 感染者が回復するまでのステップ数
np.random.seed(0)
# 個体の状態を表すクラス
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()
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  # 感染者が回復するまでのステップ数
np.random.seed(0)
# 個体の状態を表すクラス
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: Susceptible、1: Infected、2: Recovered)
        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

# 各状態のエージェント数を記録するリスト
susceptible_counts = []
infected_counts = []
recovered_counts = []

# シミュレーションの実行とデータ収集
for step in range(steps):
    # 各個体の状態を更新
    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

    # 各状態の個体数をカウント
    susceptible_count = sum(agent.state == 0 for agent in agents)
    infected_count = sum(agent.state == 1 for agent in agents)
    recovered_count = sum(agent.state == 2 for agent in agents)

    susceptible_counts.append(susceptible_count)
    infected_counts.append(infected_count)
    recovered_counts.append(recovered_count)

# 折れ線グラフのアニメーションを作成
fig, ax = plt.subplots()
ax.set_title('Number of Agents Over Time')
ax.set_xlabel('Time Step')
ax.set_ylabel('Number of Agents')
ax.set_xlim(0, steps)
ax.set_ylim(0, N)

line_susceptible, = ax.plot([], [], 'b-', label='Susceptible')
line_infected, = ax.plot([], [], 'r-', label='Infected')
line_recovered, = ax.plot([], [], 'g-', label='Recovered')
ax.legend(loc='upper right')

def init():
    line_susceptible.set_data([], [])
    line_infected.set_data([], [])
    line_recovered.set_data([], [])
    return line_susceptible, line_infected, line_recovered

def update(frame):
    x = np.arange(frame + 1)
    line_susceptible.set_data(x, susceptible_counts[:frame + 1])
    line_infected.set_data(x, infected_counts[:frame + 1])
    line_recovered.set_data(x, recovered_counts[:frame + 1])
    return line_susceptible, line_infected, line_recovered

ani = FuncAnimation(fig, update, frames=steps, init_func=init, blit=True)

# GIFとして保存
ani.save('sir_line_graph.gif', writer='pillow')

plt.show()

参考文献

コメントを残す

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