Agent Management Through AgentSet#

The Boltzmann Wealth Model#

If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) Colab
(No Google Account) Binder (This can take 30 seconds to 5 minutes to load)

If you are running locally, please ensure you have the latest Mesa version installed.

Tutorial Description#

This tutorial extends the Boltzmann wealth model from the Collecting Data tutorial, by demonstrating Mesa’s AgentSet functionality.

In this portion, we will demonstrate how users can employ AgentSet for different purposes.

If you are starting here please see the Running Your First Model tutorial for dependency and start-up instructions

IN COLAB? - Run the next cell#

Import Dependencies#

This includes importing of dependencies needed for the tutorial.

# Has multi-dimensional arrays and matrices.
# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np

# Data manipulation and analysis.
import pandas as pd

# Data visualization tools.
import seaborn as sns

import mesa

Agent Management Through AgentSet#

Background: Mesa uses a set based approach, AgentSet to allow users efficiently and intuitively manage their agents. For the most part users will never explicitly call AgentSet and in fact, we have already used the AgentSet methods functionality when we used shuffle_do(move) to reorder the agents and then do(exchange) to have the agents exchange money in sequence. Although you will likely never interact with AgentSent directly it is important to know the Mesa uses a set based approach for agent management.

Beyond the method functionality there are additional ways AgentSet can help you manage your agents and we will look at two additional examples in this tutorial, but you can see more in the Getting Started Section of Mesa.

Model-specific information: We will show two agent management techniques just to demonstrate the capability

  1. Selecting We will institute a policy that has the rich agents give money to the poor agents

  2. GroupBy We will group agents together based on wealth

A big thanks to @Ewout for his exceptional work on developing and implementing AgentSet

Selecting#

Model-specific Information: For this variation of the model we are going to institute a policy that only rich agents give money to poor agent

Code Implementation: We will use agents.select to separate the agents into rich and poor agents. If there are rich agents then they are the only ones who give money.

# Get lists of rich and poor agents

  • Description: Uses AgentSet.select with a function (in this case a lambda function) to select agents with greater than 3 units of wealth and less than three units of wealth. This will give us two lists of agents rich agent and poor agent which we can then use to execute the give_money method.

  • API: AgentSet.select

def compute_gini(model):
    agent_wealths = [agent.wealth for agent in model.agents]
    x = sorted(agent_wealths)
    n = model.num_agents
    B = sum(xi * (n - i) for i, xi in enumerate(x)) / (n * sum(x))
    return 1 + (1 / n) - 2 * B


class MoneyAgent(mesa.Agent):
    """An agent with fixed initial wealth."""

    def __init__(self, model):
        super().__init__(model)
        self.wealth = 1

    def give_money(self, poor_agents):
        if self.wealth > 0:
            other_agent = self.random.choice(poor_agents)
            other_agent.wealth += 1
            self.wealth -= 1


class MoneyModel(mesa.Model):
    """A model with some number of agents."""

    def __init__(self, n):
        super().__init__()
        self.num_agents = n

        # Create agents
        MoneyAgent.create_agents(model=self, n=n)

        self.datacollector = mesa.DataCollector(
            model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}
        )

    def step(self):
        self.datacollector.collect(self)
        # Get lists of rich and poor agents
        rich_agents = model.agents.select(lambda a: a.wealth >= 3)
        poor_agents = model.agents.select(lambda a: a.wealth < 3)
        # When there is rich agents only have them give money to poor agents
        if len(rich_agents) > 0:
            rich_agents.shuffle_do("give_money", poor_agents)
        else:
            poor_agents.shuffle_do("give_money", poor_agents)

We now run the model, collect the data, and plot the results.

model = MoneyModel(100)
for _ in range(20):
    model.step()


data = model.datacollector.get_agent_vars_dataframe()
# Use seaborn
g = sns.histplot(data["Wealth"], discrete=True)
g.set(title="Wealth distribution", xlabel="Wealth", ylabel="number of agents");
../_images/32f00299a95f4cad5fd418be75e97a8b14594baa45b8fe6b27938871ba6675d3.png

Group By#

Model-specific implementation: In this case we will give agents an attribute of ethnicity of Green, Blue or Mixed. Green and Blue agents only give money to their ethnicity while Mixed can give money to anyone.

Code Implementation: Using groupby we will execute the above logic in our code by passing a list of grouped agents into our give_money function. To ensure we can plot wealth by group we also need to add ethnicity to our datacollector.

# Create dictionary of agents groupby

Description: Uses AgentSet.groupby to group agents by their ethnicity attribute. This will give us a dictionary where the keys are the different ethnicities and the values are an AgentSet. In this case we will then use the AgentSet class and leverage its shuffle_do capability to then give money to the target groups.

  • API: AgentSet.select

  • Note: AgentSet has a lot of functionality and similar to discrete_space has the ability to add new features and make Mesa models more user-friendly. We strongly encourage you to check out the AgentSet API to see all the functionality and if you have an idea feel free to contribute

class MoneyAgent(mesa.Agent):
    """An agent with fixed initial wealth."""

    def __init__(self, model, ethnicity):
        super().__init__(model)
        self.wealth = 1
        self.ethnicity = ethnicity

    def give_money(self, similars):
        if self.wealth > 0:
            other_agent = self.random.choice(similars)
            other_agent.wealth += 1
            self.wealth -= 1


class MoneyModel(mesa.Model):
    """A model with some number of agents."""

    def __init__(self, n):
        super().__init__()
        self.num_agents = n

        # Create a list of our different ethnicities
        ethnicities = ["Green", "Blue", "Mixed"]

        # Create agents
        MoneyAgent.create_agents(
            model=self,
            n=self.num_agents,
            ethnicity=self.random.choices(ethnicities, k=self.num_agents),
        )

        self.datacollector = mesa.DataCollector(
            model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": "wealth", "Ethnicity": "ethnicity"},
        )

    def step(self):
        self.datacollector.collect(self)
        # Create dictionary of agents groupby
        grouped_agents = model.agents.groupby("ethnicity")
        for ethnic, similars in grouped_agents:
            if ethnic != "Mixed":
                similars.shuffle_do("give_money", similars)
            else:
                similars.shuffle_do(
                    "give_money", self.agents
                )  # This allows mixed to trade with anyone
# Run the model
model = MoneyModel(100)
for _ in range(20):
    model.step()

# get the data
data = model.datacollector.get_agent_vars_dataframe()
# assign histogram colors
palette = {"Green": "green", "Blue": "blue", "Mixed": "purple"}
g = sns.histplot(data=data, x="Wealth", hue="Ethnicity", discrete=True, palette=palette)
g.set(title="Wealth distribution", xlabel="Wealth", ylabel="number of agents");
../_images/db35231124f3954a4a6b86ea01f6f6c5ad19c2850990ce4b3b679382d7bc35fb.png

Exercises#

  • Create a new policy or alter an existing policy in this model to see the impact

  • Use a different feature in AgentSet and integrate into this model

Next Steps#

Check out the basic visualization tutorial on how to build interactive dashboards for your models.

[Comer2014] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer_gmu_0883E_10539.pdf

[Dragulescu2002] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.