Introductory Tutorial — Mesa .1 documentation (2023)

Tutorial Description

Mesa is a Python framework foragent-basedmodeling. Gettingstarted with Mesa is easy. In this tutorial, we will walk throughcreating a simple model and progressively add functionality which willillustrate Mesa’s core features.

Note: This tutorial is a work-in-progress. If you find any errors orbugs, or just find something unclear or confusing, let usknow!

The base for this tutorial is a very simple model of agents exchangingmoney. Next, we add space to allow agents to move. Then, we’ll covertwo of Mesa’s analytic tools: the data collector and batch runner.After that, we’ll add an interactive visualization which lets us watchthe model as it runs. Finally, we go over how to write your ownvisualization module, for users who are comfortable with JavaScript.

You can also find all the code this tutorial describes in theexamples/boltzmann_wealth_model directory of the Mesa repository.

Sample Model Description

The tutorial model is a very simple simulated agent-based economy, drawnfrom econophysics and presenting a statistical mechanics approach towealth distribution [Dragulescu2002]. The rules of our tutorial model:

  1. There are some number of agents.

  2. All agents begin with 1 unit of money.

  3. At every step of the model, an agent gives 1 unit of money (if theyhave it) to some other agent.

Despite its simplicity, this model yields results that are oftenunexpected to those not familiar with it. For our purposes, it alsoeasily demonstrates Mesa’s core features.

Let’s get started.

Installation

To start, install Mesa. We recommend doing this in a virtualenvironment,but make sure your environment is set up with Python 3. Mesa requiresPython3 and does not work in Python 2 environments.

To install Mesa, simply:

$ pip install mesa

When you do that, it will install Mesa itself, as well as anydependencies that aren’t in your setup yet. Additional dependenciesrequired by this tutorial can be found in theexamples/boltzmann_wealth_model/requirements.txt file, which can beinstalled directly form the github repository by running:

$ pip install -r https://raw.githubusercontent.com/projectmesa/mesa/main/examples/boltzmann_wealth_model/requirements.txt

This will install the dependencies listed in the requirements.txt filewhich are:

- jupyter (Ipython interactive notebook)

- matplotlib (Python’s visualization library)

- mesa (this ABM library – if not installed)

- numpy (Python’s numerical python library)

Building a sample model

Once Mesa is installed, you can start building our model. You can writemodels in two different ways:

  1. Write the code in its own file with your favorite text editor, or

  2. Write the model interactively in JupyterNotebook cells.

Either way, it’s good practice to put your model in its own folder –especially if the project will end up consisting of multiple files (forexample, Python files for the model and the visualization, a Notebookfor analysis, and a Readme with some documentation and discussion).

Begin by creating a folder, and either launch a Notebook or create a newPython source file. We will use the name money_model.py here.

Setting up the model

To begin writing the model code, we start with two core classes: one forthe overall model, the other for the agents. The model class holds themodel-level attributes, manages the agents, and generally handles theglobal level of our model. Each instantiation of the model class will bea specific model run. Each model will contain multiple agents, all ofwhich are instantiations of the agent class. Both the model and agentclasses are child classes of Mesa’s generic Model and Agentclasses. This is seen in the code with class MoneyModel(mesa.Model)or class MoneyAgent(mesa.Agent). If you want you can specificallythe class being imported by looking at themodeloragentcode in the mesa repo.

Each agent has only one variable: how much wealth it currently has.(Each agent will also have a unique identifier (i.e., a name), stored inthe unique_id variable. Giving each agent a unique id is a goodpractice when doing agent-based modeling.)

There is only one model-level parameter: how many agents the modelcontains. When a new model is started, we want it to populate itselfwith the given number of agents.

The beginning of both classes looks like this:

import mesaclass MoneyAgent(mesa.Agent): """An agent with fixed initial wealth.""" def __init__(self, unique_id, model): super().__init__(unique_id, model) self.wealth = 1class MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N): self.num_agents = N # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self)

Adding the scheduler

Time in most agent-based models moves in steps, sometimes also calledticks. At each step of the model, one or more of the agents –usually all of them – are activated and take their own step, changinginternally and/or interacting with one another or the environment.

The scheduler is a special model component which controls the orderin which agents are activated. For example, all the agents may activatein the same order every step; their order might be shuffled; we may tryto simulate all the agents acting at the same time; and more. Mesaoffers a few different built-in scheduler classes, with a commoninterface. That makes it easy to change the activation regime a givenmodel uses, and see whether it changes the model behavior. This may notseem important, but scheduling patterns can have an impact on yourresults [Comer2014].

For now, let’s use one of the simplest ones: RandomActivation*,which activates all the agents once per step, in random order. Everyagent is expected to have a step method. The step method is theaction the agent takes when it is activated by the model schedule. Weadd an agent to the schedule using the add method; when we call theschedule’s step method, the model shuffles the order of the agents,then activates and executes each agent’s step method.

*Unlike mesa.model or mesa.agent, mesa.time has multipleclasses (e.g.RandomActivation, StagedActivation etc). To ensurecontext, time is used in the import as evidenced below withmesa.time.Randomactivation. You can see the different time classesasmesa.time.

(Video) MOTOTRBO CPS 2.0 (GMVN6241A) Introduction, User Guide & Tutorial (UK & Europe)

With that in mind, the model code with the scheduler added looks likethis:

import mesaclass MoneyAgent(mesa.Agent): """An agent with fixed initial wealth.""" def __init__(self, unique_id, model): super().__init__(unique_id, model) self.wealth = 1 def step(self): # The agent's step will go here. # For demonstration purposes we will print the agent's unique_id print("Hi, I am agent " + str(self.unique_id) + ".")class MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N): self.num_agents = N self.schedule = mesa.time.RandomActivation(self) # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) self.schedule.add(a) def step(self): """Advance the model by one step.""" self.schedule.step()

At this point, we have a model which runs – it just doesn’t do anything.You can see for yourself with a few easy lines. If you’ve been workingin an interactive session, you can create a model object directly.Otherwise, you need to open an interactive session in the same directoryas your source code file, and import the classes. For example, if yourcode is in money_model.py:

from money_model import MoneyModel

Then create the model object, and run it for one step:

empty_model = MoneyModel(10)empty_model.step()
Hi, I am agent 6.Hi, I am agent 2.Hi, I am agent 1.Hi, I am agent 0.Hi, I am agent 4.Hi, I am agent 5.Hi, I am agent 3.Hi, I am agent 9.Hi, I am agent 8.Hi, I am agent 7.

Exercise

Try modifying the code above to have every agent print out itswealth when it is activated. Run a few steps of the model to see howthe agent activation order is shuffled each step.

Agent Step

Now we just need to have the agents do what we intend for them to do:check their wealth, and if they have the money, give one unit of it awayto another random agent. To allow the agent to choose another agent atrandom, we use the model.random random-number generator. This worksjust like Python’s random module, but with a fixed seed set when themodel is instantiated, that can be used to replicate a specific modelrun later.

To pick an agent at random, we need a list of all agents. Notice thatthere isn’t such a list explicitly in the model. The scheduler, however,does have an internal list of all the agents it is scheduled toactivate.

With that in mind, we rewrite the agent step method, like this:

class MoneyAgent(mesa.Agent): """An agent with fixed initial wealth.""" def __init__(self, unique_id, model): super().__init__(unique_id, model) self.wealth = 1 def step(self): if self.wealth == 0: return other_agent = self.random.choice(self.model.schedule.agents) other_agent.wealth += 1 self.wealth -= 1

Running your first model

With that last piece in hand, it’s time for the first rudimentary run ofthe model.

If you’ve written the code in its own file (money_model.py or adifferent name), launch an interpreter in the same directory as the file(either the plain Python command-line interpreter, or the IPythoninterpreter), or launch a Jupyter Notebook there. Then import theclasses you created. (If you wrote the code in a Notebook, obviouslythis step isn’t necessary).

from money_model import *

Now let’s create a model with 10 agents, and run it for 10 steps.

model = MoneyModel(10)for i in range(10): model.step()

Next, we need to get some data out of the model. Specifically, we wantto see the distribution of the agent’s wealth. We can get the wealthvalues with list comprehension, and then use matplotlib (or anothergraphics library) to visualize the data in a histogram.

If you are running from a text editor or IDE, you’ll also need to addthis line, to make the graph appear.

plt.show()
# For a jupyter notebook add the following line:%matplotlib inline# The below is needed for both notebooks and scriptsimport matplotlib.pyplot as pltagent_wealth = [a.wealth for a in model.schedule.agents]plt.hist(agent_wealth)
(array([2., 0., 0., 0., 0., 6., 0., 0., 0., 2.]), array([0. , 0.2, 0.4, 0.6, 0.8, 1. , 1.2, 1.4, 1.6, 1.8, 2. ]), <BarContainer object of 10 artists>)
Introductory Tutorial — Mesa .1 documentation (1)

You’ll should see something like the distribution above. Yours willalmost certainly look at least slightly different, since each run of themodel is random, after all.

To get a better idea of how a model behaves, we can create multiplemodel runs and see the distribution that emerges from all of them. Wecan do this with a nested for loop:

all_wealth = []# This runs the model 100 times, each model executing 10 steps.for j in range(100): # Run the model model = MoneyModel(10) for i in range(10): model.step() # Store the results for agent in model.schedule.agents: all_wealth.append(agent.wealth)plt.hist(all_wealth, bins=range(max(all_wealth) + 1))
(array([433., 304., 150., 71., 29., 13.]), array([0, 1, 2, 3, 4, 5, 6]), <BarContainer object of 6 artists>)
Introductory Tutorial — Mesa .1 documentation (2)

This runs 100 instantiations of the model, and runs each for 10 steps.(Notice that we set the histogram bins to be integers, since agents canonly have whole numbers of wealth). This distribution looks a lotsmoother. By running the model 100 times, we smooth out some of the‘noise’ of randomness, and get to the model’s overall expected behavior.

(Video) Libre Office 7 Writer - Ultimate Beginners Tutorial - Free Microsoft Word Alternative

This outcome might be surprising. Despite the fact that all agents, onaverage, give and receive one unit of money every step, the modelconverges to a state where most agents have a small amount of money anda small number have a lot of money.

Adding space

Many ABMs have a spatial element, with agents moving around andinteracting with nearby neighbors. Mesa currently supports two overallkinds of spaces: grid, and continuous. Grids are divided into cells, andagents can only be on a particular cell, like pieces on a chess board.Continuous space, in contrast, allows agents to have any arbitraryposition. Both grids and continuous spaces are frequentlytoroidal, meaningthat the edges wrap around, with cells on the right edge connected tothose on the left edge, and the top to the bottom. This prevents somecells having fewer neighbors than others, or agents being able to go offthe edge of the environment.

Let’s add a simple spatial element to our model by putting our agents ona grid and make them walk around at random. Instead of giving their unitof money to any random agent, they’ll give it to an agent on the samecell.

Mesa has two main types of grids: SingleGrid and MultiGrid*.SingleGrid enforces at most one agent per cell; MultiGrid allowsmultiple agents to be in the same cell. Since we want agents to be ableto share a cell, we use MultiGrid.

*However there are more types of space to include HexGrid,NetworkGrid, and the previously mentioned ContinuousSpace.Similar to mesa.time context is retained withmesa.space.[enter class]. You can see the different classes asmesa.space

We instantiate a grid with width and height parameters, and a boolean asto whether the grid is toroidal. Let’s make width and height modelparameters, in addition to the number of agents, and have the gridalways be toroidal. We can place agents on a grid with the grid’splace_agent method, which takes an agent and an (x, y) tuple of thecoordinates to place the agent.

class MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N, width, height): self.num_agents = N self.grid = mesa.space.MultiGrid(width, height, True) self.schedule = mesa.time.RandomActivation(self) # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) self.schedule.add(a) # Add the agent to a random grid cell x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(a, (x, y))

Under the hood, each agent’s position is stored in two ways: the agentis contained in the grid in the cell it is currently in, and the agenthas a pos variable with an (x, y) coordinate tuple. Theplace_agent method adds the coordinate to the agent automatically.

Now we need to add to the agents’ behaviors, letting them move aroundand only give money to other agents in the same cell.

First let’s handle movement, and have the agents move to a neighboringcell. The grid object provides a move_agent method, which like you’dimagine, moves an agent to a given cell. That still leaves us to get thepossible neighboring cells to move to. There are a couple ways to dothis. One is to use the current coordinates, and loop over allcoordinates +/- 1 away from it. For example:

neighbors = []x, y = self.posfor dx in [-1, 0, 1]: for dy in [-1, 0, 1]: neighbors.append((x+dx, y+dy))

But there’s an even simpler way, using the grid’s built-inget_neighborhood method, which returns all the neighbors of a givencell. This method can get two types of cell neighborhoods:Moore (includesall 8 surrounding squares), and VonNeumann(onlyup/down/left/right). It also needs an argument as to whether to includethe center cell itself as one of the neighbors.

With that in mind, the agent’s move method looks like this:

class MoneyAgent(mesa.Agent): #... 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)

Next, we need to get all the other agents present in a cell, and giveone of them some money. We can get the contents of one or more cellsusing the grid’s get_cell_list_contents method, or by accessing acell directly. The method accepts a list of cell coordinate tuples, or asingle tuple if we only care about one cell.

class MoneyAgent(mesa.Agent): #... def give_money(self): cellmates = self.model.grid.get_cell_list_contents([self.pos]) if len(cellmates) > 1: other = self.random.choice(cellmates) other.wealth += 1 self.wealth -= 1

And with those two methods, the agent’s step method becomes:

class MoneyAgent(mesa.Agent): # ... def step(self): self.move() if self.wealth > 0: self.give_money()

Now, putting that all together should look like this:

class MoneyAgent(mesa.Agent): """An agent with fixed initial wealth.""" def __init__(self, unique_id, model): super().__init__(unique_id, model) self.wealth = 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 give_money(self): cellmates = self.model.grid.get_cell_list_contents([self.pos]) if len(cellmates) > 1: other_agent = self.random.choice(cellmates) other_agent.wealth += 1 self.wealth -= 1 def step(self): self.move() if self.wealth > 0: self.give_money()class MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N, width, height): self.num_agents = N self.grid = mesa.space.MultiGrid(width, height, True) self.schedule = mesa.time.RandomActivation(self) # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) self.schedule.add(a) # Add the agent to a random grid cell x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(a, (x, y)) def step(self): self.schedule.step()

Let’s create a model with 50 agents on a 10x10 grid, and run it for 20steps.

model = MoneyModel(50, 10, 10)for i in range(20): model.step()

Now let’s use matplotlib and numpy to visualize the number of agentsresiding in each cell. To do that, we create a numpy array of the samesize as the grid, filled with zeros. Then we use the grid object’scoord_iter() feature, which lets us loop over every cell in thegrid, giving us each cell’s coordinates and contents in turn.

import numpy as npagent_counts = np.zeros((model.grid.width, model.grid.height))for cell in model.grid.coord_iter(): cell_content, x, y = cell agent_count = len(cell_content) agent_counts[x][y] = agent_countplt.imshow(agent_counts, interpolation="nearest")plt.colorbar()# If running from a text editor or IDE, remember you'll need the following:# plt.show()
<matplotlib.colorbar.Colorbar at 0x2505197baf0>
Introductory Tutorial — Mesa .1 documentation (3)

Collecting Data

So far, at the end of every model run, we’ve had to go and write our owncode to get the data out of the model. This has two problems: it isn’tvery efficient, and it only gives us end results. If we wanted to knowthe wealth of each agent at each step, we’d have to add that to the loopof executing steps, and figure out some way to store the data.

Since one of the main goals of agent-based modeling is generating datafor analysis, Mesa provides a class which can handle data collection andstorage for us and make it easier to analyze.

The data collector stores three categories of data: model-levelvariables, agent-level variables, and tables (which are a catch-all foreverything else). Model- and agent-level variables are added to the datacollector along with a function for collecting them. Model-levelcollection functions take a model object as an input, while agent-levelcollection functions take an agent object as an input. Both then returna value computed from the model or each agent at their current state.When the data collector’s collect method is called, with a modelobject as its argument, it applies each model-level collection functionto the model, and stores the results in a dictionary, associating thecurrent value with the current step of the model. Similarly, the methodapplies each agent-level collection function to each agent currently inthe schedule, associating the resulting value with the step of themodel, and the agent’s unique_id.

Let’s add a DataCollector to the model withmesa.DataCollector,and collect two variables. At the agent level, we want to collect everyagent’s wealth at every step. At the model level, let’s measure themodel’s GiniCoefficient, ameasure of wealth inequality.

def compute_gini(model): agent_wealths = [agent.wealth for agent in model.schedule.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 * Bclass MoneyAgent(mesa.Agent): """An agent with fixed initial wealth.""" def __init__(self, unique_id, model): super().__init__(unique_id, model) self.wealth = 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 give_money(self): cellmates = self.model.grid.get_cell_list_contents([self.pos]) if len(cellmates) > 1: other = self.random.choice(cellmates) other.wealth += 1 self.wealth -= 1 def step(self): self.move() if self.wealth > 0: self.give_money()class MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N, width, height): self.num_agents = N self.grid = mesa.space.MultiGrid(width, height, True) self.schedule = mesa.time.RandomActivation(self) # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) self.schedule.add(a) # Add the agent to a random grid cell x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(a, (x, y)) self.datacollector = mesa.DataCollector( model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"} ) def step(self): self.datacollector.collect(self) self.schedule.step()
(Video) How to Change Margins | Google Docs Tutorial

At every step of the model, the datacollector will collect and store themodel-level current Gini coefficient, as well as each agent’s wealth,associating each with the current step.

We run the model just as we did above. Now is when an interactivesession, especially via a Notebook, comes in handy: the DataCollectorcan export the data its collected as a pandas* DataFrame, for easyinteractive analysis.

*If you are new to Python, please be aware that pandas is alreadyinstalled as a dependency of Mesa and thatpandas is a “fast, powerful,flexible and easy to use open source data analysis and manipulationtool”. pandas is great resource to help analyze the data collected inyour models

model = MoneyModel(50, 10, 10)for i in range(100): model.step()

To get the series of Gini coefficients as a pandas DataFrame:

gini = model.datacollector.get_model_vars_dataframe()gini.plot()
<AxesSubplot:>
Introductory Tutorial — Mesa .1 documentation (4)

Similarly, we can get the agent-wealth data:

agent_wealth = model.datacollector.get_agent_vars_dataframe()agent_wealth.head()
Wealth
Step AgentID
0 0 1
1 1
2 1
3 1
4 1

You’ll see that the DataFrame’s index is pairings of model step andagent ID. You can analyze it the way you would any other DataFrame. Forexample, to get a histogram of agent wealth at the model’s end:

end_wealth = agent_wealth.xs(99, level="Step")["Wealth"]end_wealth.hist(bins=range(agent_wealth.Wealth.max() + 1))
<AxesSubplot:>
Introductory Tutorial — Mesa .1 documentation (5)

Or to plot the wealth of a given agent (in this example, agent 14):

one_agent_wealth = agent_wealth.xs(14, level="AgentID")one_agent_wealth.Wealth.plot()
<AxesSubplot:xlabel='Step'>
Introductory Tutorial — Mesa .1 documentation (6)

You can also use pandas to export the data to a CSV (comma separatedvalue), which can be opened by any common spreadsheet application oropened by pandas.

If you do not specify a file path, the file will be saved in the localdirectory. After you run the code below you will see two files appear(model_data.csv and agent_data.csv)

# save the model data (stored in the pandas gini object) to CSVgini.to_csv("model_data.csv")# save the agent data (stored in the pandas agent_wealth object) to CSVagent_wealth.to_csv("agent_data.csv")

Batch Run

Like we mentioned above, you usually won’t run a model only once, butmultiple times, with fixed parameters to find the overall distributionsthe model generates, and with varying parameters to analyze how theydrive the model’s outputs and behaviors. Instead of needing to writenested for-loops for each model, Mesa provides a batch_runfunction which automates it for you.

The batch runner also requires an additional variable self.runningfor the MoneyModel class. This variable enables conditional shut off ofthe model once a condition is met. In this example it will be set asTrue indefinitely.

def compute_gini(model): agent_wealths = [agent.wealth for agent in model.schedule.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 * Bclass MoneyModel(mesa.Model): """A model with some number of agents.""" def __init__(self, N, width, height): self.num_agents = N self.grid = mesa.space.MultiGrid(width, height, True) self.schedule = mesa.time.RandomActivation(self) self.running = True # Create agents for i in range(self.num_agents): a = MoneyAgent(i, self) self.schedule.add(a) # Add the agent to a random grid cell x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(a, (x, y)) self.datacollector = mesa.DataCollector( model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"} ) def step(self): self.datacollector.collect(self) self.schedule.step()

We call batch_run with the following arguments:

  • model_cls The model class that is used for the batch run.

  • parameters A dictionary containing all the parameters of themodel class and desired values to use for the batch run as key-valuepairs. Each value can either be fixed (e.g.{"height": 10, "width": 10}) or an iterable(e.g.{"N": range(10, 500, 10)}). batch_run will thengenerate all possible parameter combinations based on this dictionaryand run the model iterations times for each combination.

  • number_processes If not specified, defaults to 1. Set it toNone to use all the available processors. Note: Multiprocessingdoes make debugging challenging. If your parameter sweeps areresulting in unexpected errors set number_processes = 1.

  • iterations The number of iterations to run each parametercombination for. Optional. If not specified, defaults to 1.

  • data_collection_period The length of the period (number of steps)after which the model and agent reporters collect data. Optional. Ifnot specified, defaults to -1, i.e.only at the end of each episode.

    (Video) VÍDEO 1 - 3.2 Configuración Monitores

  • max_steps The maximum number of time steps after which the modelhalts. An episode does either end when self.running of the modelclass is set to False or whenmodel.schedule.steps == max_steps is reached. Optional. If notspecified, defaults to 1000.

  • display_progress Display the batch run progress. Optional. If notspecified, defaults to True.

In the following example, we hold the height and width fixed, and varythe number of agents. We tell the batch runner to run 5 instantiationsof the model with each number of agents, and to run each for 100 steps.

We want to keep track of

  1. the Gini coefficient value and

  2. the individual agent’s wealth development.

Since for the latter changes at each time step might be interesting, weset data_collection_period = 1.

Note: The total number of runs is 245 (= 49 different populations * 5iterations per population). However, the resulting list of dictionarieswill be of length 6186250 (= 250 average agents per population * 49different populations * 5 iterations per population * 101 steps periteration).

Note for Windows OS users: If you are running this tutorial inJupyter, make sure that you set number_processes = 1 (singleprocess). If number_processes is greater than 1, it is lessstraightforward to set up. You can read Mesa’s collection of usefulsnippets,in ‘Using multi-process batch_run on Windows’ section for how to doit.

params = {"width": 10, "height": 10, "N": range(10, 500, 10)}results = mesa.batch_run( MoneyModel, parameters=params, iterations=5, max_steps=100, number_processes=1, data_collection_period=1, display_progress=True,)
245it [00:34, 7.02it/s]

To further analyze the return of the batch_run function, we convertthe list of dictionaries to a Pandas DataFrame and print its keys.

import pandas as pdresults_df = pd.DataFrame(results)print(results_df.keys())
Index(['RunId', 'iteration', 'Step', 'width', 'height', 'N', 'Gini', 'AgentID', 'Wealth'], dtype='object')

First, we want to take a closer look at how the Gini coefficient at theend of each episode changes as we increase the size of the population.For this, we filter our results to only contain the data of one agent(the Gini coefficient will be the same for the entire population at anytime) at the 100th step of each episode and then scatter-plot the valuesfor the Gini coefficient over the the number of agents. Notice there arefive values for each population size since we set iterations=5 whencalling the batch run.

results_filtered = results_df[(results_df.AgentID == 0) & (results_df.Step == 100)]N_values = results_filtered.N.valuesgini_values = results_filtered.Gini.valuesplt.scatter(N_values, gini_values)
<matplotlib.collections.PathCollection at 0x250bd5b41c0>
Introductory Tutorial — Mesa .1 documentation (7)

Second, we want to display the agent’s wealth at each time step of onespecific episode. To do this, we again filter our large data frame, thistime with a fixed number of agents and only for a specific iteration ofthat population. To print the results, we convert the filtered dataframe to a string specifying the desired columns to print.

Pandas has built-in functions to convert to a lot of different dataformats. For example, to display as a table in a Jupyter Notebook, wecan use the to_html() function which takes the same arguments asto_string() (see commented lines).

# First, we filter the resultsone_episode_wealth = results_df[(results_df.N == 10) & (results_df.iteration == 2)]# Then, print the columns of interest of the filtered data frameprint( one_episode_wealth.to_string( index=False, columns=["Step", "AgentID", "Wealth"], max_rows=25 ))# For a prettier display we can also convert the data frame to html, uncomment to test in a Jupyter Notebook# from IPython.display import display, HTML# display(HTML(one_episode_wealth.to_html(index=False, columns=['Step', 'AgentID', 'Wealth'], max_rows=25)))
 Step AgentID Wealth 0 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 1 0 6 1 0 7 1 0 8 1 0 9 1 1 0 2 1 1 1... ... ... 99 8 4 99 9 1 100 0 0 100 1 0 100 2 1 100 3 0 100 4 1 100 5 1 100 6 0 100 7 2 100 8 4 100 9 1

Lastly, we want to take a look at the development of the Ginicoefficient over the course of one iteration. Filtering and printinglooks almost the same as above, only this time we choose a differentepisode.

results_one_episode = results_df[ (results_df.N == 10) & (results_df.iteration == 1) & (results_df.AgentID == 0)]print(results_one_episode.to_string(index=False, columns=["Step", "Gini"], max_rows=25))
 Step Gini 0 0.00 1 0.18 2 0.18 3 0.18 4 0.18 5 0.32 6 0.32 7 0.32 8 0.42 9 0.42 10 0.42 11 0.42... ... 89 0.66 90 0.66 91 0.66 92 0.66 93 0.56 94 0.56 95 0.56 96 0.56 97 0.56 98 0.56 99 0.56 100 0.56

Happy Modeling!

This document is a work in progress. If you see any errors, exclusionsor have any problems please contactus.

virtual environment:http://docs.python-guide.org/en/latest/dev/virtualenvs/

[Comer2014] Comer, Kenneth W. “Who Goes First? An Examination of theImpact of Activation on Outcome Behavior in AgentBased Models.” GeorgeMason 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.

Videos

1. Sony A7R IV Tutorial - Exposure, Aperture, Shutter Speed, Manual Mode, and Bulb Mode Explained
(Jason Hermann)
2. Get Perfect 3D Prints on Any Resin Printer With the Exposure Finder!
(Slice Print Roleplay)
3. Manual Water Pump .1
(PhilipStephens007)
4. My DMX 2.0 Tutorial Español
(Icono 3D)
5. Tutorial: Simple way of creating (numbering) headings and subheadings in Word
(thelittlemoments)
6. 9 Lines of Code Every CNC Machinist Needs To Know! - Haas Automation Tip of the Day
(Haas Automation, Inc.)
Top Articles
Latest Posts
Article information

Author: Ray Christiansen

Last Updated: 03/10/2023

Views: 6493

Rating: 4.9 / 5 (69 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Ray Christiansen

Birthday: 1998-05-04

Address: Apt. 814 34339 Sauer Islands, Hirtheville, GA 02446-8771

Phone: +337636892828

Job: Lead Hospitality Designer

Hobby: Urban exploration, Tai chi, Lockpicking, Fashion, Gunsmithing, Pottery, Geocaching

Introduction: My name is Ray Christiansen, I am a fair, good, cute, gentle, vast, glamorous, excited person who loves writing and wants to share my knowledge and understanding with you.