在本文中,我使用我为 Python 中基于代理的建模开发的库在 Python 中实现了 SIR 模型。换句话说,我使用现有的框架来实现基于代理的 SIR 模型。
介绍基于代理的 SIR 模型
SIR 代表易感者、感染者和康复者。如下图所示,在 SIR 模型中,代理可以经历以下状态转换:从易感到感染,从感染到恢复,从恢复到易感。
上图所示的状态转换通常以随机分布和特定概率实现。此外,您不必允许所有状态转换。例如,在本文中,我将不允许代理从恢复状态回退到易感状态。下面是本文实现的SIR模型。
以同样的方式,您还可以制定一个 SIR 模型,在该模型中,您允许从恢复状态回退到感染状态,而不仅仅是易感状态。
Python中基于代理的建模框架
我为基于代理的建模创建了一个框架。该框架旨在随着时间的推移进行扩展和升级。它目前支持允许将代理、模拟环境和人口放置在基于网格的模型中的设置。模拟结果可以以标准化格式写入 SQLite 数据库,并根据存储在该数据库中的数据生成可视化和动画。该框架以多个 Python 文件(模块)的形式出现,可以对其进行编辑以添加自定义功能。
如果您想查看该框架,您可以在GitHub 上关注它。链接在这里:
这里需要特别注意的是,该框架支持基于网格的基于代理的建模。代理在 2D 网格中交互。这个 2D 网格有助于模拟环境。一个或多个代理可以位于同一单元格中,具体取决于模型设置。代理可以与指定邻域内的其他代理进行交互。在本文中,相互作用是指疾病转移,导致疾病传播。
代理具有属性和功能,由内部动态、变量和状态表示。代理的内部运作会影响其行为、决策以及与其他代理的交互。这些交互也会受到交互环境的影响。
我现在将继续用 Python 记录相关的 ABM 模型实现。
在 Python 中实现基于代理的 SIR 模型
在下面的代码中,我使用了基于代理的建模框架。我设置了一个持续 300 次迭代的模拟运行。每次遇到受感染的代理时,易感代理被感染的概率为 7%。另一方面,对于每次迭代,受感染的代理有 3% 的恢复概率。
__author__ = "Linnart Felkl"
__email__ = "LinnartSF@gmail.com"
if __name__ == "__main__":
print("demo starts")
import sys
from pathlib import Path
file = Path(__file__).resolve()
parent, root = file.parent, file.parents[1]
sys.path.append(str(root))
# remove the current file's directory from sys.path, unless already removed
try:
sys.path.remove(str(parent))
except ValueError:
pass
import data
import stats
import config
import framework
import random
import animation
# setup database manager and connection
db = data.Database("sqlite3", config.path_databasefile)
db_manager = data.Manager(db)
# create an empty environment
env = framework.Environment(1, True, 20, 20, db_manager) # Environment constructor implicitly resets environment table in database
# create initial population of healthy humans
pops = framework.Populations(amount = 1, env = env, db_manager = db_manager, attributes = ["infected","recovered"], datatypes = ["INTEGER","INTEGER"])
pops.add_population(name = "humans",
size = 200,
attributes = ["infected","recovered"],
datatypes = ["INTEGER","INTEGER"],
initialvals = [0, 0]
)
# randomly infect 5%
pop = pops.Populations["humans"]
sampleagents = pop.get_agents(int(0.05*pop.Size))
for agent in sampleagents: agent.Attributes["infected"] = 1
_prob_infection = 0.07
_prob_recovery = 0.03
# setup simulation
sim = framework.Simulation(300)
# make sure that environment and agents tables in database are setup at this time
pops.write_env_to_db(sim.Iteration)
pops.write_agents_to_db(sim.Iteration)
# execute simulation run, store every 10th run into the database
while sim.run():
# look at every agent
for agent in pop.get_agents():
if agent.get_attr_value("infected") == 1:
neighbours = env.get_neighbourhood(agent)
for neighbour in neighbours:
if neighbour.get_attr_value("infected") == 0 and neighbour.get_attr_value("recovered") == 0:
# this neighbour is not resistant and not infected; infect with specified probability
if random.uniform(0, 1) < _prob_infection: neighbour.set_attr_value("infected", 1)
# the infected agent recovers with a specified probability
if random.uniform(0, 1) < _prob_recovery:
agent.set_attr_value("recovered", 1)
agent.set_attr_value("infected", 0)
# update results in database, for agents and for environment
pops.write_agents_to_db(sim.Iteration)
pops.write_env_to_db(sim.Iteration)
pops.write_density_to_db(sim.Iteration)
# get dataframes with simulation results
humans_df = db_manager.get_populationdf(pop = "humans")
env_df = db_manager.get_environmentdf()
density_df = db_manager.get_densitydf()
# visualize simulation data
stats.set_fontsizes(8,10,12)
stats.plot_agentattr_lines("infected", humans_df)
stats.save_plot("infection_curves")
stats.plot_agentattr_lines("recovered", humans_df)
stats.save_plot("recovery_curves")
stats.plot_grid_occupation(env_df, ["humans"])
stats.save_plot("human_locations")
stats.plot_density_markersize(density_df, "infected", 50, "red")
stats.save_plot("infection_density")
stats.plot_density_markersize(density_df, "recovered", 50, "green")
stats.save_plot("recovery_density")
stats.plot_avgattr_lines(["infected","recovered"], humans_df)
stats.save_plot("avginfectedavgrecovered")
# create and save animations
animation.animate_density(
df = density_df,
filename = "infectionanimation",
attr = "infected",
defaultsize = 50,
color = "red",
tpf = 0.05
)
animation.animate_density(
df = density_df,
filename = "recoveryanimation",
attr = "recovered",
defaultsize = 50,
color = "green",
tpf = 0.05
)
# end program
db.close()
print("demo ends")
以上基于代理的 SIR 模型实现生成存储在 SQLite 数据库中的结果。该数据库随后用于可视化。这些可视化可以在单独的脚本中由另一位分析师在不同的时间点实施。即模型执行和数据可视化是由数据库分离的两个独立活动。
基于Agent的SIR模型仿真结果
我现在终于可以查看基于网格的基于代理的 SIR 模型生成的结果了。下面是整个模拟运行过程中代理位置的可视化。
下面的动画显示了整个时间段内感染了哪些特工。动画还显示代理位置。在这个简单的示例中,代理位置是静态的。
接下来,在整个模拟时间内代理恢复的动画。
下图可视化了在给定模拟时间代理被感染或恢复的平均可能性。
代理恢复可确保并非所有代理都受到感染。但是,此模型中的代理具有静态位置。在另一个模拟运行中,我们可以允许动态代理位置,甚至是某种扩散/迁移。这很可能会增加在整个模拟运行过程中被感染的代理总数。
本文应用的基于代理的建模框架可以提供额外的图表。此外,模拟结果仍存储在 SQLite 数据库中,可以以任何自定义方式进行分析。然而,这将需要一些额外的定制/适应,即编码。
结语及相关内容
基于代理的模拟是一种模拟方法,旨在通过描述微观系统级别的代理动力学和相互作用来解释复杂的宏观系统行为。这是一种相当抽象的方法,通常用于理解复杂系统。复杂系统比复杂系统更复杂,另一方面,也没有混沌系统复杂。美国经济,在宏观层面上以国内生产总值的形式可见,是复杂系统的一个例子。例如,基于代理的模型可用于了解美国经济中某些现象和趋势的出现。
在本文中,我实施了一个最近非常流行的疾病传播模型。这实际上是另一个经常应用基于代理的建模的有趣领域。使用基于代理的建模框架,我实现了基于代理的 SIR 模型。该框架的可视化和动画功能用于审查模拟结果。该框架本身可用于实现其他类型的基于代理的仿真模型——该框架将随着时间的推移进行升级和定期扩展。
以下是与基于代理的模拟相关的其他一些 SCDA :
- 链接:SCM分析师的模拟方法
- 链接:在 Python 中使用 Matplotlib 可视化的基于代理的简单模拟运行
- 链接:Python 中基于代理的建模
- 链接:在 Python 中开发一个简单的基于代理的模拟模型
- 链接:在 Python 中使用 Matplotlib 可视化 2D 网格和数组
专业领域为优化和仿真的工业工程师(R,Python,SQL,VBA)
Leave a Reply