When we want to model a given phenomenon, we could employ a mathematical underlying structure which 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 which 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 which 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 which offers many tools to build an ABM framework, and if you are interested about 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.

• Phenomenon to be modeled. My goal is observing what happens when a given information about, namely, a product (useful in marketing campaign), an event or similar, is spread among a population of individual. 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 neighborhood).
• Agents. In this scenario, agents are simple human being 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
#to collect features during the #simulation
from mesa.space import MultiGrid
#to generate the environment

#for computation and visualization purpose
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

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

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])

#now let's define the model

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)
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]
#5 agents are aware of the product
if i in l: #only agents with id in the list are aware of the product
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.

``````'''Run the model '''
model = News_Model(100, 50, 50)
for i in range(100):
model.step()

#let's inspect the results:
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: