流行の伝播の可視化の改善
以前の投稿で,流行伝播モデルというものを見た.
今回はその発展として状態推移を折れ線グラフとして可視化した.こうすることで数という観点からの推移がわかりやすくなる.
コードは下記.
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()
参考文献
- MAS コミュニティ 流行伝播モデルhttps://mas.kke.co.jp/model/trend_model/