Agent-Based Modeling in Python: Guida Completa a Mesa per Simulare Sistemi Complessi

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Guida pratica alla libreria Mesa per ABM

Avete mai guardato un ingorgo stradale chiedendovi chi sia il colpevole? Spesso non c’è un incidente, né un semaforo rotto. È solo il risultato di tante piccole frenate individuali che, sommate, bloccano un’intera autostrada. Se provassimo a spiegare questo caos con una singola formula matematica, probabilmente falliremmo: la realtà è troppo disordinata per essere racchiusa in un’equazione statica. È qui che entra in gioco l’Agent-Based Modeling (ABM). Invece di guardare la foresta dall’alto, l’ABM si concentra sui singoli alberi  o meglio, sugli individui, dando loro delle regole semplici e osservando cosa succede quando iniziano a interagire.

In questa guida vedremo come tradurre questo concetto in codice usando Mesa, la libreria che ha portato la simulazione complessa nel linguaggio di programmazione più amato del momento: Python.

Cos’è l’Agent-Based Modeling (ABM)?

Prima di parlare di Mesa, facciamo un passo indietro. L’Agent-Based Modeling (Modellazione Basata su Agenti) è un approccio di simulazione che studia il comportamento di un sistema complesso partendo dal basso. Invece di scrivere equazioni che descrivono il sistema dall’alto, si definiscono le regole di comportamento dei singoli componenti, chiamati agenti, e si osserva come dal loro interagire emerga spontaneamente il comportamento del sistema nel suo insieme.

Immagina di studiare il traffico. Invece di usare formule matematiche perfette ma irrealistiche (che presuppongono tutti i guidatori razionali con velocità costante), un ABM creerà una simulazione con centinaia di auto, ognuna con il suo guidatore.

Ogni guidatore ha regole: “se l’auto davanti rallenta, io freno” e “se c’è uno spazio a destra, cambio corsia”. Osservando questa moltitudine di interazioni locali, è possibile far emergere fenomeni macroscopici e spesso complessi, come un ingorgo. Niente equazioni che lo descrivono direttamente, solo tante piccole regole individuali che generano un effetto globale.

Pubblicità

🧐 Cos’è Mesa e cosa lo rende uno “standard de facto”?

Mesa è proprio una libreria Python progettata per rendere semplice e veloce la creazione di queste simulazioni ad agenti. Fornisce tutti gli “ingredienti” di base per costruire un ABM: creare gli agenti, gestire lo spazio (griglie o reti), programmare l’ordine delle azioni e raccogliere i dati. Lo scopo principale di Mesa è essere l’alternativa Python a framework storicamente importanti come NetLogo, Repast e MASON, ma con un occhio di riguardo per le moderne pratiche di programmazione e data analysis.

Considerarlo uno “standard de facto” in Python è più che giustificato per queste ragioni:

  • È il più diffuso e maturo: Mesa è il framework Python per ABM più completo e utilizzato. La sua lunga storia (il progetto è iniziato nel 2014) lo ha reso estremamente stabile e ricco di funzionalità. Avere una vasta comunità e un ecosistema consolidato è fondamentale per essere uno standard.

  • È il più citato in ambito accademico e nei corsi: Se cerchi “Agent-Based Modeling in Python”, è praticamente certo che troverai Mesa. Molte università, come l’Università di Bologna e il Montana Tech, lo utilizzano per insegnare la simulazione ad agenti nei loro corsi. Viene anche ampiamente utilizzato in ricerche scientifiche pubblicate, come per lo studio della diffusione di opinioni sui vaccini a New York.

  • Ha un design moderno e ben integrato: A differenza di altri framework, Mesa è nato per integrarsi perfettamente con l’ecosistema Python. Questo significa che puoi utilizzare tutte le potenti librerie di analisi dati che già conosci, come Pandas, NumPy e Matplotlib, direttamente sulle simulazioni create con Mesa.

 Le caratteristiche principali di Mesa

Mesa fornisce una serie di moduli che coprono gli aspetti essenziali di una simulazione:

  • Agenti: La classe mesa.Agent è il cuore della simulazione. La sua specializzazione (sottoclasse) definisce il comportamento degli agenti, tipicamente attraverso un metodo step() che viene eseguito a ogni “tick” della simulazione.

  • Modello: La classe mesa.Model è il contenitore della simulazione. Gestisce gli agenti, l’ambiente, i parametri e coordina l’esecuzione. La funzionalità AgentSet è uno strumento moderno per filtrare, raggruppare e gestire i tuoi agenti in modo efficiente.

  • Spazio: Gli agenti vivono in uno spazio condiviso. Mesa supporta spazi discreti come griglie esagonali e spazi continui, che permettono movimenti realistici e interazioni tra agenti. La PropertyLayer è una feature avanzata che permette di gestire proprietà ambientali complesse (ad esempio, la mappa delle risorse o dei pericoli) in modo molto efficiente.

  • Scheduler: Lo scheduler definisce l’ordine in cui gli agenti agiscono. Puoi far agire gli agenti in ordine casuale, sequenziale o a fasi, per modellare l’aspetto temporale della simulazione.

  • DataCollector: Uno strumento integrato per raccogliere e salvare i dati durante la simulazione (ad esempio, la ricchezza media di tutti gli agenti o le coordinate di uno specifico tipo di agente).

  • Visualizzazione: Mesa include SolaraViz, un’interfaccia interattiva che si apre nel browser e permette di visualizzare la simulazione in tempo reale, muovere la visuale in diversi assi e modificare alcuni parametri al volo, con il supporto a schemi di colore scuro.

Forse potrebbe interessarti anche:  Capire il Teorema di Bayes passo a passo

I 5 passi spiegati in modo semplice

Immagina di costruire una simulazione Mesa come se stessi creando un piccolo mondo virtuale.

1. L’Agente = il personaggio del gioco

Pensa agli agenti come a persone dentro un videogioco.

Ogni agente:

  • ha delle caratteristiche (es. soldi, energia, stato)
  • prende decisioni

👉 Il metodo step() è semplicemente:

Cosa faccio adesso?”

Esempio:

  • Se ho soldi → compro qualcosa
  • Se sono stanco → mi fermo

👉 È qui che nasce il comportamento.

2. Il Modello = il mondo + il regista

Il modello è:

  • il mondo di gioco
  • il regista invisibile

Fa due cose fondamentali:

  1. Crea tutto all’inizio (agenti, spazio)
  2. Fa avanzare il tempo

👉 Ogni “tick” (passo temporale):
dice a tutti:

Ok ragazzi, ora tocca a voi agire

3. Spazio + Scheduler = dove e quando

Qui succede la magia vera.

 Spazio (dove stanno gli agenti)

È la mappa:

  • griglia tipo scacchiera → MultiGrid
  • spazio continuo → tipo coordinate reali

👉 Senza spazio:
gli agenti non possono incontrarsi → niente interazioni

 Scheduler (ordine di azione)

Decide:

Chi si muove prima?

⚠️ Importantissimo:
Se sempre lo stesso agente parte per primo → risultati falsati

👉 Per questo si usa:

  • RandomActivation → ordine casuale (più realistico)

4. DataCollector = il ricercatore

Qui smetti di “giocare” e inizi a misurare

Serve per rispondere a domande tipo:

  • Quanti agenti sono ricchi?
  • Come cambia il sistema nel tempo?

Due livelli:

  • globale → totale ricchezza
  • individuale → ricchezza di ogni agente

👉 Senza questo:
hai una simulazione… ma non impari nulla

5. Il ciclo = far vivere il mondo

Ora premi “play” ▶️

Ogni ciclo:

  1. Gli agenti agiscono
  2. Il modello aggiorna
  3. I dati vengono salvati

👉 Dopo tanti cicli:
emerge un comportamento globale

💡 Il concetto chiave (importantissimo)

👉 Mesa non simula direttamente il sistema
👉 Simula regole locali semplici

E poi succede qualcosa di potente:

Comportamenti complessi emergono da regole semplici

Esempio:

  • ogni agente copia i vicini → boom, viralità
  • ogni agente scambia soldi → nascono disuguaglianze

 Riassunto super semplice

Componente Traduzione intuitiva
Agente Personaggio
Modello Mondo + regista
Spazio Mappa
Scheduler Turni di gioco
DataCollector Analista
Ciclo Il tempo che scorre

Un cambio di mentalità

L’idea fondamentale (spiegata bene)

Quando usi Mesa non stai programmando il risultato.

👉 Non dici:

“voglio la viralità”
“voglio la disuguaglianza”

👉 Dici invece:

ogni individuo segue queste piccole regole

E poi osservi cosa succede.

Differenza chiave

Approccio classico (top-down)

  • Parti dal sistema globale
  • Scrivi equazioni (es. crescita, medie, curve)

👉 Esempio:

  • “La domanda cresce del 10%”
  • “La ricchezza media aumenta”

⚠️ Problema: perdi i comportamenti individuali

Approccio ABM (bottom-up)

  • Parti dagli individui
  • Definisci regole locali
Forse potrebbe interessarti anche:  Che cosa si intende per scienza dei dati

👉 Esempio:

  • “Se il mio vicino compra, forse compro anche io”
  • “Se incontro qualcuno, posso scambiare soldi”

👉 Il sistema globale non è scritto da nessuna parte

La magia: emergenza

Questo fenomeno si chiama:

👉 emergenza (emergent behavior)

Significa:

pattern complessi nascono da interazioni semplici

 Esempio 1: Viralità (marketing)

Regola locale

Ogni agente:

  • guarda i vicini
  • se qualcuno ha adottato → copia con probabilità

👉 Sembra banale, ma…

Cosa emerge?

Fase 1 → lenta

  • pochi adottano
  • diffusione quasi invisibile

Fase 2 → accelerazione

  • più adottanti → più influenza
  • effetto valanga

Fase 3 → saturazione

  • quasi tutti adottano

Nel marketing reale…

Questa dinamica è:

  • passaparola
  • network effects
  • crescita “a S” (sigmoide)

👉 Nessuno ha programmato la curva
👉 È emersa da regole locali

Esempio 2: Disuguaglianza (economia)

Regola locale

Ogni agente:

  • incontra un altro agente
  • scambia una piccola quantità di denaro casuale

👉 Fine. Niente altro.

Cosa ti aspetteresti?

👉 “Tutti restano più o meno uguali”

Sembra logico, no?

Cosa succede davvero 😮

Dopo tanti step:

  • pochi diventano molto ricchi
  • molti diventano poveri

👉 Nasce una distribuzione tipo:

  • Pareto / power law

💡 Quindi…

Questo modello spiega perché:

  • le disuguaglianze emergono anche senza “cattive intenzioni”
  • il sistema stesso genera squilibri

👉 Non serve:

  • truffa
  • sfruttamento
  • strategie complesse

Bastano:

interazioni casuali ripetute

Perché succede tutto questo?

Ci sono 3 ingredienti chiave:

1. Interazioni locali

Gli agenti vedono solo:

  • vicini
  • contatti diretti

👉 Nessuna visione globale

2. Non linearità

Piccoli cambiamenti → grandi effetti

Esempio:

  • probabilità 0.2 → niente viralità
  • probabilità 0.3 → esplosione

3. Feedback (effetto moltiplicatore)

Viralità:

più utenti → più influenza → più utenti

Ricchezza:

più soldi → più possibilità → ancora più soldi

👉 È qui che nasce la complessità


Ricorda..

“Non simuliamo il sistema.
Simuliamo le interazioni che lo generano.”

Collegamento diretto al marketing

Questo approccio ti permette di capire:

Viralità

  • quando un prodotto “decolla”
  • soglia critica (tipping point)

 Segmentazione

  • non tutti reagiscono uguale
  • alcuni diventano influencer naturali

ROI campagne

  • meglio 1000 utenti casuali?
  • o 10 super connessi?

👉 ABM ti permette di testarlo


In Sintesi

La cosa controintuitiva è questa:

Più il modello è semplice, più può generare risultati complessi.

Non serve aggiungere mille regole.

Spesso:

  • troppe regole → sistema rigido
  • poche regole → sistema realistico

Primo esempio: agenti che si muovono casualmente in una griglia

Questo è il classico “Hello World” degli ABM: pochi concetti, ma fondamentali.

from mesa import Agent, Model
from mesa.space import MultiGrid
import random

# ======================
# Agente
# ======================
class RandomAgent(Agent):
    def __init__(self, model):
        super().__init__(model)

    def step(self):
        # Celle vicine (anche diagonali)
        neighbors = self.model.grid.get_neighborhood(
            self.pos,
            moore=True,
            include_center=False
        )
        
        # Movimento casuale
        new_position = random.choice(neighbors)
        self.model.grid.move_agent(self, new_position)


# ======================
# Modello
# ======================
class RandomModel(Model):
    def __init__(self, n_agents, width, height):
        super().__init__()
        
        self.grid = MultiGrid(width, height, torus=True)
        self.agents_list = []

        # Creazione agenti
        for _ in range(n_agents):
            agent = RandomAgent(self)
            self.agents_list.append(agent)

            x = random.randrange(width)
            y = random.randrange(height)
            self.grid.place_agent(agent, (x, y))

    def step(self):
        # Attivazione casuale
        random.shuffle(self.agents_list)
        for agent in self.agents_list:
            agent.step()

Esecuzione

model = RandomModel(n_agents=10, width=10, height=10)

for step in range(5):
    model.step()
    print(f"Step {step+1} completato")
Step 1 completato
Step 2 completato
Step 3 completato
Step 4 completato
Step 5 completato

Cosa sta succedendo

Questo esempio, per quanto semplice, contiene tutti i mattoni base dell’Agent-Based Modeling:

  • Agenti (RandomAgent)
    • hanno comportamento locale (step)
    • non conoscono il sistema globale
  • Ambiente (MultiGrid)
    • spazio discreto 2D
    • supporta interazioni locali
  • Dinamica
    • ogni agente si muove casualmente
    • l’ordine di attivazione è random

👉 Non c’è nessuna equazione globale.
👉 Eppure stai già simulando un sistema dinamico.

Questo esempio può sembrare banale, ma è esattamente da qui che nascono simulazioni molto più complesse: epidemie, mercati finanziari, traffico urbano o diffusione delle opinioni. E’ la base della diffusione spaziale.

Rappresenta l’entropia.

In fisica si chiama “Random Walk” ed è fondamentale per modellare come i gas si espandono in una stanza o come i cercatori di cibo si muovono in un territorio inesplorato. Serve a capire il “punto zero”: cosa succede se non ci sono regole sociali, ma solo movimento?

Basta cambiare le regole locali degli agenti… e il comportamento globale del sistema cambia radicalmente.


Esempio 2: diffusione di un’informazione

Idea

Ogni agente può essere:

  • 🟢 Ignaro (S) → non conosce l’informazione
  • 🔴 Informato (I) → la diffonde agli altri
Forse potrebbe interessarti anche:  Analisi di Serie Storiche Azionarie in Python: Da Pandas al Calcolo di Alfa e Beta

Regola:

Se un agente informato è vicino a uno ignaro → può “contagiarlo”

Codice completo

from mesa import Agent, Model
from mesa.space import MultiGrid
import random

# ======================
# Agente
# ======================
class PersonAgent(Agent):
    def __init__(self, model, state="S"):
        super().__init__(model)
        self.state = state  # S = ignaro, I = informato

    def step(self):
        neighbors = self.model.grid.get_neighbors(
            self.pos,
            moore=True,
            include_center=False
        )

        # Se sono informato, provo a contagiare
        if self.state == "I":
            for neighbor in neighbors:
                if neighbor.state == "S":
                    if random.random() < self.model.infection_prob:
                        neighbor.state = "I"

        # Movimento casuale
        possible_steps = self.model.grid.get_neighborhood(
            self.pos,
            moore=True,
            include_center=False
        )
        new_position = random.choice(possible_steps)
        self.model.grid.move_agent(self, new_position)


# ======================
# Modello
# ======================
class InfoSpreadModel(Model):
    def __init__(self, n_agents, width, height, infection_prob=0.3):
        super().__init__()
        
        self.grid = MultiGrid(width, height, torus=True)
        self.agents_list = []
        self.infection_prob = infection_prob

        # Creazione agenti
        for i in range(n_agents):
            # uno solo parte informato
            state = "I" if i == 0 else "S"
            agent = PersonAgent(self, state)
            self.agents_list.append(agent)

            x = random.randrange(width)
            y = random.randrange(height)
            self.grid.place_agent(agent, (x, y))

    def step(self):
        random.shuffle(self.agents_list)
        for agent in self.agents_list:
            agent.step()

    def count_informed(self):
        return sum(1 for a in self.agents_list if a.state == "I")

Esecuzione

model = InfoSpreadModel(n_agents=20, width=10, height=10, infection_prob=0.4)

for step in range(10):
    model.step()
    informed = model.count_informed()
    print(f"Step {step+1}: Informati = {informed}")
Step 1: Informati = 1
Step 2: Informati = 1
Step 3: Informati = 1
Step 4: Informati = 3
Step 5: Informati = 5
Step 6: Informati = 7
Step 7: Informati = 7
Step 8: Informati = 8
Step 9: Informati = 9
Step 10: Informati = 11

Cosa dimostra

Qui succede qualcosa di molto più interessante rispetto al primo esempio:

1. Interazione locale → effetto globale

Gli agenti:

  • vedono solo i vicini
  • prendono decisioni semplici

👉 ma emerge una dinamica globale:
la diffusione dell’informazione

Non linearità

Cambiando leggermente:

infection_prob = 0.1 lenta diffusione
infection_prob = 0.6  esplosione rapida

piccoli cambiamenti nelle regole locali possono generare effetti macroscopici completamente diversi.

Questo esempio è praticamente:

  • una base per modelli epidemiologici (SIR)
  • una simulazione di viralità sui social
  • un modello di diffusione delle opinioni

Questo esercizio è affascinante perché introduce la Soglia di Criticità. Se imposti la probabilità di contagio al 5%, l’informazione muore quasi subito. Se la imposti al 30%, invade il sistema. È il cuore del marketing virale e dell’epidemiologia: permette di trovare il “tipping point”, ovvero quel valore minimo per cui un fenomeno locale diventa una pandemia (o un trend su TikTok).

 

🌐 Dalle reti agli agenti: capire (e simulare) la complessità

Prima di simulare sistemi complessi con Mesa, devi capire come nascono: dalle connessioni tra individui, dati e comportamenti.

Pubblicità