Understanding Agent-Based Model
By: Valentina Alto
Tags: Modeling, Mesa, Simulation, Python, Agent Based Modeling

Understanding Agent-Based Model

An implementation with Python

When we want to model a given phenomenon, we could employ a mathematical underlying structure that we believe describes the scenario. Then, we can parametrize and calibrate it so that our model is able to reproduce patterns seen in data.

This technique is appealing since it provides us with a set of parameters that can be tuned properly, yet it has a caveat: it does not take into account the individual, idiosyncratic behavior of each and every agent in the model. Indeed, it considers a population of individuals as a homogeneous entity, with the risk of losing important, heterogeneous features.

The idea of Agent-Based Model (ABM) is that of bypassing this caveat: with this modeling technique, we are able to initialize a population of agents with a set of behaviors (rules), living in an environment governed by a set of laws (again rules) and then let the agents “behave” without intervening. The interesting fact about this modeling technique is that just observing agents behave according to their inner features (hence, idiosyncratic characteristics), it is possible to anticipate emergent phenomena that are not very intuitive if considered at a macro-level.

In this article, I’m going to propose a very basic ABM, using the Python module Mesa: it is a powerful package that offers many tools to build an ABM framework, and if you are interested in the topic I recommend you to read the official documentation here.

Defining ABM framework

Before diving into the code, I will briefly describe the framework of our ABM.

The phenomenon to be modeled. My goal is to observe what happens when given information about, namely, a product (useful in a marketing campaign), an event or similar, is spread among a population of individuals. In this case, we will stick to the example of a product, let’s say just introduced into the market.

My goal is to observe what happens when given information about, namely, a product (useful in a marketing campaign), an event or similar, is spread among a population of individuals. In this case, we will stick to the example of a product, let’s say just introduced into the market. Environment. I will initialize a grid space where agents can move around, one cell at the time, in one of the neighbor cells (according to the Moore definition of a neighborhood).

I will initialize a grid space where agents can move around, one cell at the time, in one of the neighbor cells (according to the Moore definition of a neighborhood). Agents. In this scenario, agents are simple human beings which are endowed with only two rules: 1) they can move in one of the neighbor cell, and 2) they can influence with their knowledge that of their neighbors, which get influenced with probability p. The agents’ ability to influence others depends on their “knowledge” feature: if it is equal to 1, it means the agent is aware of the product (in that case, the agent can influence others), otherwise it is 0.

So the idea is initializing in a grid space a population of agents. Each agent has an internal state of knowledge which can be either 1 (if aware of the product) or 0 (if not aware). Agents with product knowledge can influence those with which they have more contacts (probably their neighbors) about the existence of that product, and this influence will have an impact with a given probability p.

The graphical representation of what I’ve been describing so far can be seen as:

Now let’s implement it in Python.

Implementation with Python

As mentioned above, for our purpose we are going to employ Mesa, a “modular framework for building, analyzing and visualizing agent-based models” (official documentation here). You can easily install it via pip.

So let’s first import the necessary packages:

from mesa import Agent, Model

from mesa.time import RandomActivation

from mesa.datacollection import DataCollector

from mesa.space import MultiGrid from mesa.batchrunner import BatchRunner import random

import numpy as np

import sys

import matplotlib.pyplot as plt

import random

Now I will initialize the class of my Agent as follows:

class Agent(Agent):

""" An agent with fixed initial wealth."""

def __init__(self, unique_id, model):

super().__init__(unique_id, model)

self.knowledge = 0



def spread_news(self):

if self.knowledge == 0:

return

neighbors = self.model.grid.get_neighbors(self.pos,moore = True, include_center=True)

neig_agents = [a for n in neighbors for a in self.model.grid.get_cell_list_contents(n.pos)]

for a in neig_agents:

if random.random()<0.3:

a.knowledge = 1



def move(self):

possible_steps = self.model.grid.get_neighborhood(

self.pos,

moore=True,

include_center=False)

new_position = self.random.choice(possible_steps)

self.model.grid.move_agent(self, new_position) def step(self):

self.move()

self.spread_news()

As anticipated, our agents are endowed with two main rules:

spread_news(): this function allows those agents which have a knowledge=1 to spread the information about the product. The neighbors get influenced with probability p=0.3.

move(): with this function, agents can move in one of the neighbor cells, according to the Moore definition of neighborhood.

Finally, the function step() allows the agent to perform both spread_news() and move() at each step of the simulation.

Now let’s define the model:

#let's define a function which is able to count, at each step, how #many agents are aware of the product def compute_informed(model):

return sum([1 for a in model.schedule.agents if a.knowledge == 1]) class News_Model(Model):

def __init__(self, N, width, height):

self.num_agents = N

self.grid = MultiGrid(width, height, True)

self.schedule = RandomActivation(self)

self.running = True # Create agents

for i in range(self.num_agents):

a = Agent(i, self)

self.schedule.add(a)

x = self.random.randrange(self.grid.width)

y = self.random.randrange(self.grid.height)

self.grid.place_agent(a, (x, y))

l = [1,2,3,4,5]

if i in l: #only one agent is informed

a.knowledge = 1 self.datacollector = DataCollector(

model_reporters = {"Tot informed": compute_informed},

agent_reporters={"Knowledge": "knowledge"}) def step(self):

self.datacollector.collect(self)

self.schedule.step()

Now we can run the model. I will initialize it with 100 agents, in a grid with height = width = 50. Hence, 2500 will be available to place agents. Plus, I will also inspect the output of the model: I’m interested in seeing whether the number of aware agents increases after many steps.

model = News_Model(100, 50, 50)

for i in range(100):

model.step() out = model.datacollector.get_agent_vars_dataframe().groupby('Step').sum()

out

It seems that the number of aware agents actually increases. Let’s also visualize it:

out.plot()

So after 100 steps, more than 80% of the initial population got influenced, starting only with 5 agents aware of the product.

This was a very naive model, yet it provides us with meaningful insight. In a more complex framework for the same scenario, one might be interested in inspecting if the position of the initial agents aware of the product is relevant in terms of the speed of diffusion. Plus, this scenario would be very well modeled with a network framework as underlying structure: we could inspect which are the most important nodes (aka agents) to target first, in order for the knowledge of the product to spread faster.

ABM are powerful modeling techniques and they leave room for creativity to the modeler: you can make them as complex as you please, play some sensitivity analysis with parameters, modeling intervention strategies and so forth. With Mesa, this becomes easier and more intuitive.

References: