Il Modello di Leslie in Python: Guida Pratica all’Algebra Lineare per la Dinamica delle Popolazioni

Cerca nel sito

Altri risultati..

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Cerca nelle Categorie

Il Modello di Leslie Algebra Lineare: per la Dinamica delle Popolazioni

Ci hanno sempre raccontato una bugia sull’algebra lineare: che serve a risolvere sistemi di equazioni su un foglio a quadretti. La verità è molto più sporca e interessante. Quelle righe e colonne non sono scatole vuote; sono il codice genetico di un sistema dinamico.

Immaginate di dover gestire una riserva di pesca o di dover calcolare se l’INPS reggerà tra trent’anni. Non vi serve una sfera di cristallo, vi serve una matrice. Il Modello di Leslie è esattamente questo: lo strumento che prende una fotografia statica di oggi — quanti giovani, adulti e anziani abbiamo — e proietta un film sul loro futuro.

Il Modello di Leslie non è un semplice esercizio da lavagna: è il ponte che collega la matematica pura alla vita reale. È lo strumento che permette a un biologo, a un ecologo o a un moderno Data Scientist di guardare una popolazione oggi e “vedere” la sua evoluzione tra cinquant’anni.

In questo articolo, smontiamo il giocattolo. Partiamo dalla matematica pura, la traduciamo in Python e poi, visto che la realtà è caotica, la bombardiamo con disastri simulati per vedere se il sistema regge.

 


1. Oltre il numero: la popolazione strutturata

In natura, non tutti gli individui sono uguali. Un cucciolo consuma risorse, un adulto produce prole, un anziano ha probabilità di sopravvivenza diverse. Per questo dividiamo la popolazione in classi di età.

Immaginiamo una popolazione divisa in tre gruppi:

  • Classe 1: Giovani (fase di crescita)
  • Classe 2: Adulti giovani (picco riproduttivo)
  • Classe 3: Adulti anziani (fase finale)

Il vettore stato al tempo [math]t[/math] è rappresentato da:

[math]
\displaystyle x(t) = \begin{pmatrix} x_1(t) \\ x_2(t) \\ x_3(t) \end{pmatrix}
[/math]


2. La Matrice di Leslie: Il motore del sistema

Il destino di questa popolazione è scritto in una matrice [math]L[/math] che contiene due informazioni vitali:

  • Fertilità ([math]f_k[/math]): Quanti nuovi nati produce in media un individuo della classe [math]k[/math].
  • Sopravvivenza ([math]s_k[/math]): Qual è la probabilità che un individuo passi alla classe d’età successiva.

La struttura standard della matrice è:

[math]
\displaystyle \begin{pmatrix}
f_1 & f_2 & f_3 \\
s_1 & 0 & 0 \\
0 & s_2 & 0
\end{pmatrix}
[/math]

La dinamica è un sistema iterativo: [math]x(t+1) = L \cdot x(t)[/math]. In pratica, stiamo dicendo che il futuro è un’elaborazione lineare del presente.


3. Autovalori e Autovettori: Il destino e la forma

Perché un Data Scientist dovrebbe interessarsi agli autovalori di questa matrice? Perché essi rispondono alle due domande fondamentali di ogni modello predittivo:

L’Autovalore Dominante ([math]\lambda[/math]): “Quanto cresceremo?”

L’autovalore reale positivo più grande ci dice tutto sul destino a lungo termine:

  • [math]\lambda > 1[/math]: La popolazione esplode (crescita esponenziale).
  • [math]\lambda = 1[/math]: La popolazione è in equilibrio (stazionaria).
  • [math]\lambda < 1[/math]: La popolazione è destinata all’estinzione.

L’Autovettore ([math]v[/math]): “Come saremo fatti?”

Mentre il numero totale di individui cambia, la proporzione tra le classi tende a stabilizzarsi. Questa “struttura stabile per età” è esattamente l’autovettore corrispondente a [math]\lambda[/math]. Indica, ad esempio, che col tempo avremo sempre il 60% di giovani, il 30% di adulti e il 10% di anziani, indipendentemente dal numero iniziale.


4. Esercizio Pratico e Analisi

Prendiamo una popolazione con questi parametri:

  • Nessuna nascita dai giovani; gli adulti producono 4 figlie; gli anziani 2.
  • Sopravvivenza dei giovani: 50%; sopravvivenza degli adulti: 60%.

La nostra matrice sarà:

[math]
\displaystyle L = \begin{pmatrix} 0 & 4 & 2 \\ 0.5 & 0 & 0 \\ 0 & 0.6 & 0 \end{pmatrix}
[/math]

Calcolando il polinomio caratteristico [math]\det(L – \lambda I) = 0[/math], otteniamo l’equazione:

[math]
\displaystyle \lambda^3 – 2\lambda – 0.6 = 0
[/math]

Risolvendo, troviamo l’autovalore dominante [math]\lambda \approx 1.55[/math].

Analisi: La popolazione cresce del 55% ogni ciclo temporale. È un tasso altissimo, tipico di specie pioniere o situazioni di assenza di predatori.


5. Implementazione in Python con NumPy

Per un Data Scientist, risolvere equazioni di terzo grado a mano non è efficiente. NumPy ci permette di analizzare popolazioni enormi in millisecondi.

import numpy as np

# Definiamo la matrice di Leslie
L = np.array([
    [0,   4,   2],
    [0.5, 0,   0],
    [0,   0.6, 0]
])

# Calcoliamo autovalori e autovettori
eigenvalues, eigenvectors = np.linalg.eig(L)

# Cerchiamo l'autovalore reale dominante
dominant_idx = np.argmax(np.real(eigenvalues))
lambda_dom = np.real(eigenvalues[dominant_idx])
v_dom = np.real(eigenvectors[:, dominant_idx])

# Normalizziamo l'autovettore per avere le percentuali (somma = 1)
stable_age_dist = v_dom / np.sum(v_dom)

print(f"Tasso di crescita (lambda): {lambda_dom:.2f}")
print(f"Struttura stabile (percentuali): {stable_age_dist}")

# Simulazione di 10 anni partendo da 100 giovani
pop = np.array([100, 0, 0])
for t in range(10):
    pop = L @ pop
    print(f"Anno {t+1}: {pop.astype(int)}")
Tasso di crescita (lambda): 1.55
Struttura stabile (percentuali): [0.69005655 0.223262   0.08668145]
Anno 1: [ 0 50  0]
Anno 2: [200   0  30]
Anno 3: [ 60 100   0]
Anno 4: [400  30  60]
Anno 5: [240 200  18]
Anno 6: [836 120 120]
Anno 7: [720 418  72]
Anno 8: [1816  360  250]
Anno 9: [1941  908  216]
Anno 10: [4064  970  544]

Perché questo approccio è interessante?

  • Scalabilità: Puoi gestire matrici con 100 classi d’età (es. demografia umana anno per anno) senza sforzo.
  • Simulazione: Oltre agli autovalori, puoi simulare l’effetto di “shock” esterni (es. una pandemia che dimezza [math]s_k[/math]) e vedere come reagisce il sistema.
  • Ottimizzazione: Puoi capire quale classe d’età proteggere per massimizzare la sopravvivenza della specie.
Ti potrebbe interessare anche:  Esercizi Matrici: Guida Completa con Soluzioni e Teoria per Principianti ed Esperti

Il passaggio dal modello lineare a quello non lineare segna il momento in cui la matematica smette di descrivere un mondo ideale e inizia a mappare la complessità della natura. Se il modello di Leslie classico è una “linea retta” verso l’infinito, l’introduzione dei vincoli di risorse introduce il concetto di feedback.

In Data Science, questo significa passare da una semplice moltiplicazione matriciale a un sistema dinamico in cui i parametri cambiano a ogni step.


Il Limite della Crescita: La “Density Dependence”

In un ambiente reale, il cibo, lo spazio e l’accumulo di rifiuti agiscono come freni. Questo fenomeno si chiama dipendenza dalla densità. Esistono due modi principali per rendere il modello di Leslie non lineare:

    • Modello di Beverton-Holt: La sopravvivenza o la fertilità diminuiscono progressivamente all’aumentare della popolazione.

    • Fattore di Feedback Globale: Si moltiplica l’intera matrice per un fattore che dipende dalla popolazione totale [math]N(t)[/math].


La Logica Matematica

Definiamo [math]N(t)[/math] come la somma di tutti gli individui nel vettore [math]x(t)[/math].
Introduciamo un fattore di smorzamento [math]q(N)[/math]:

[math]\displaystyle
\begin{aligned}
q(N(t)) = \frac{1}{1 + a \cdot N(t)}
\end{aligned}
[/math]

Dove [math]a[/math] è un parametro che rappresenta la scarsità di risorse.
La nuova equazione di stato diventa:

[math]\displaystyle
\begin{aligned}
x(t+1) = \left[ q(N(t)) \cdot L \right] \cdot x(t)
\end{aligned}
[/math]


Implementazione in Python: Leslie + Feedback

Ecco come possiamo modificare il codice precedente per simulare una popolazione che si scontra con il “tetto” delle risorse (la cosiddetta Carrying Capacity).

import numpy as np
import matplotlib.pyplot as plt

# Parametri originali (Matrice di Leslie ideale)
L = np.array([
    [0,   4,   2],
    [0.5, 0,   0],
    [0,   0.6, 0]
])

# Parametri del vincolo (Non-linearità)
K = 1000  # Capacità portante teorica dell'ambiente
a = 0.001 # Coefficiente di competizione

def simulate_nonlinear(steps, initial_pop):
    history = []
    current_pop_vector = initial_pop
    
    for _ in range(steps):
        # 1. Calcoliamo la popolazione totale attuale
        total_n = np.sum(current_pop_vector)
        history.append(total_n)
        
        # 2. Calcoliamo il fattore di smorzamento (non-lineare)
        # Più N è grande, più damping si avvicina a 0
        damping = 1 / (1 + a * total_n)
        
        # 3. Applichiamo la matrice con il feedback
        current_pop_vector = (damping * L) @ current_pop_vector
        
    return history

# Simulazione
steps = 50
initial_v = np.array([10, 5, 2])
pop_history = simulate_nonlinear(steps, initial_v)

# Visualizzazione
plt.figure(figsize=(10, 5))
plt.plot(pop_history, label="Popolazione con vincoli (Non-lineare)", color='teal', lw=2)
plt.axhline(y=520, color='r', linestyle='--', label="Equilibrio dinamico stimato") # Valore indicativo
plt.title("Evoluzione della Popolazione: Verso l'Equilibrio")
plt.xlabel("Tempo (Anni)")
plt.ylabel("Numero totale di individui")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

evoluzione della popolazione

Perché questo approccio è fondamentale per un Data Scientist?

Implementare vincoli non lineari trasforma il modello da uno strumento puramente descrittivo a uno strumento decisionale e predittivo avanzato:

  1. Identificazione dei Punti di Equilibrio: Mentre nel modello lineare la popolazione o esplode o muore, qui il sistema tende a un punto fisso. In Data Science, questo è l’equivalente di trovare lo “stato stazionario” di un sistema economico o biologico.

  2. Analisi di Sensibilità: Puoi testare come cambia il destino della popolazione se <strong>[math]a[/math]</strong> (la competizione) aumenta a causa del cambiamento climatico o della perdita di habitat.

  3. Gestione del Rischio: Nelle assicurazioni o nella gestione delle risorse ittiche, questi modelli servono a calcolare il Maximum Sustainable Yield (il prelievo massimo che non distrugge la popolazione).

Ti potrebbe interessare anche:  Ottimizzazione Matematica: Approfondimento su scipy.optimize.minimize

Una curiosità applicativa: L’instabilità

Se aumenti drasticamente la fertilità nella matrice di Leslie in un modello non lineare, potresti osservare comportamenti caotici o oscillazioni cicliche. È lo stesso principio alla base dei modelli meteo e dei mercati finanziari.


Nel mondo reale, i modelli deterministici sono “fotografie” di un ufficio perfettamente in ordine. Ma la natura assomiglia più a un cantiere aperto: piove quando non dovrebbe, scoppiano epidemie e le risorse fluttuano.

Per un Data Scientist, “sporcare” il modello con la stocasticità significa passare dalla previsione singola alla gestione del rischio. Non ci interessa più solo sapere cosa accadrà, ma cosa potrebbe accadere nel peggiore o nel migliore dei casi.

La Matematica dell’Incertezza

Esistono due modi principali per inserire il caso nel Modello di Leslie:

  • Stocasticità Ambientale (Shocks): Eventi rari ma catastrofici (siccità, incendi, epidemie) che colpiscono l’intera popolazione contemporaneamente.
  • Variazione Parametrica: Piccole fluttuazioni annuali nei tassi di sopravvivenza e fertilità (un anno più freddo, un anno con più cibo).

In termini di calcolo, la nostra equazione diventa:

[math]\displaystyle \begin{aligned} x(t+1) = \left[ \epsilon_t \cdot q(N(t)) \cdot L \right] \cdot x(t) \end{aligned} [/math]

Dove [math]\epsilon_t[/math] è una variabile casuale che rappresenta lo “stato del mondo” al tempo [math]t[/math].

Implementazione in Python: Simulazione Monte Carlo

Per analizzare un modello stocastico, non facciamo una sola simulazione, ma ne facciamo migliaia. Questo metodo è chiamato Simulazione Monte Carlo.

import numpy as np
import matplotlib.pyplot as plt

# Matrice di Leslie e parametri non lineari
L = np.array([[0, 4, 2], [0.5, 0, 0], [0, 0.6, 0]])
a = 0.001  # Competizione

def simulate_stochastic(steps, initial_pop, p_disaster=0.05, impact=0.4):
    history = []
    current_pop = initial_pop
    
    for _ in range(steps):
        total_n = np.sum(current_pop)
        damping = 1 / (1 + a * total_n)
        
        # Introduciamo l'evento casuale (Epidemia/Siccità)
        # Se esce un numero < p_disaster, accade il disastro
        shock = 1.0
        if np.random.rand() < p_disaster:
            shock = impact # La sopravvivenza/fertilità crolla al 40%
            
        # Applichiamo anche una piccola variazione annuale standard (rumore bianco)
        noise = np.random.normal(1.0, 0.05) 
        
        current_pop = (damping * shock * noise * L) @ current_pop
        history.append(np.sum(current_pop))
        
    return history

# Eseguiamo 100 simulazioni diverse (Scenari possibili)
n_simulations = 100
plt.figure(figsize=(12, 6))

all_histories = []
for i in range(n_simulations):
    hist = simulate_stochastic(steps=60, initial_pop=np.array([50, 20, 10]))
    all_histories.append(hist)
    plt.plot(hist, color='gray', alpha=0.2) # Linee sottili per ogni scenario

# Calcoliamo e visualizziamo la media degli scenari
mean_history = np.mean(all_histories, axis=0)
plt.plot(mean_history, color='red', lw=3, label="Andamento Medio")

plt.title("Simulazione Monte Carlo: Impatto di Epidemie Casuali sulla Popolazione")
plt.xlabel("Anni")
plt.ylabel("Popolazione Totale")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

simulazione Monte Carlo impatto delle epidemie

Interpretazione del Grafico Monte Carlo

Guardando il risultato delle 100 simulazioni (le linee grigie), un analista trae conclusioni strategiche che la media (linea rossa) non può fornire:

  • Rischio di Estinzione: Sebbene la media sia stabile, alcune traiettorie grigie potrebbero toccare lo zero in presenza di shock consecutivi. Questo è il dato cruciale per i piani di conservazione.

  • Fascia di Incertezza: La dispersione delle linee grigie dopo l’anno 10 indica quanto sia “prevedibile” il sistema. Più l’area occupata dalle linee è vasta, maggiore è l’incertezza decisionale.

  • Tempo di Recupero (Resilienza): Nota come, dopo ogni crollo improvviso (shock), la linea tenda a risalire verso l’equilibrio. La pendenza di questa risalita indica la capacità di ripresa della specie.

Perché questo approccio “spacca” in ambito Data Science?

L’approccio stocastico  sposta l’obiettivo dalla previsione puntuale (spesso errata) alla gestione dell’incertezza. In un mondo dominato dai dati, non vince chi indovina il numero esatto, ma chi sa fornire un intervallo di rischio affidabile.

Ecco come questi concetti trasformano la tua analisi in uno strumento di alto livello:

Ti potrebbe interessare anche:  Pitagora, la trigonometria e il GPS: i fondamenti matematici della navigazione moderna

Intervalli di Confidenza: Abbandonare il “Numero Magico”

Nel modello deterministico, ottieni un unico valore: λ. Ma nella Data Science applicata, quel valore è solo una media. Introducendo la stocasticità, puoi calcolare i percentili. Dire che la popolazione sarà 500 è un’ipotesi; dire che c’è il 95% di probabilità che oscillerà tra 350 e 650 è un’analisi professionale che permette di pianificare scenari di budget o di gestione delle risorse.

 Probabilità di Estinzione: Analisi delle Code (Tail Risk)

Il grafico Monte Carlo  generato mostra che, nonostante la media (linea rossa) sia rassicurante, alcune linee grigie crollano.

  • Business Intelligence: Questo rappresenta il rischio di fallimento di un progetto o di esaurimento di uno stock.

  • Conservazione: Se il 10% delle tue simulazioni finisce con la popolazione sotto la soglia di sopravvivenza, quel 10% è il dato più importante del report, non la media.

Resilienza e Recovery Time

Misurare la resilienza significa osservare la capacità del sistema di “rimbalzare” dopo un evento avverso.

  • Stress Test: Esattamente come le banche simulano crisi finanziarie, tu simuli un’epidemia (impact=0.4) per vedere quanto tempo impiega la curva a tornare al suo equilibrio dinamico.

  • Decision Making: Se il tempo di recupero è troppo lungo, il sistema è fragile e occorrono interventi correttivi sui parametri di sopravvivenza.

Un passo avanti: Analisi della Probabilità di Estinzione

Per rendere il tuo report ancora più potente, potresti aggiungere una sezione che calcola numericamente il rischio basandosi sulle tue simulazioni:

# Calcoliamo la probabilità di estinzione (soglia < 100 individui)
final_populations = [h[-1] for h in all_histories]
extinct_sims = sum(1 for p in final_populations if p < 100)
prob_extinction = (extinct_sims / n_simulations) * 100

print(f"Probabilità di collasso della popolazione: {prob_extinction}%")
Probabilità di collasso della popolazione: 0.0%

Questo trasforma il codice in un vero motore di Risk Assessment.

Una riflessione

Questa struttura è identica a quella usata nei modelli finanziari per simulare i portafogli azionari (dove la matrice di Leslie è sostituita dai rendimenti degli asset) o nei modelli epidemiologici per prevedere l’ondata di un virus.

Il Modello di Leslie stocastico ci insegna che la matematica non serve a eliminare l’incertezza, ma a darle una forma, a misurarla e, infine, a non averne paura.


Conclusione: Il valore della visione critica

Il modello di Leslie è geniale nella sua semplicità, ma come ogni modello lineare ha un limite: assume risorse infinite. Nella realtà, interviene la competizione (modelli non lineari). Tuttavia, resta la base fondamentale per la Data Science ecologica e la demografia attuariale.

Capire questi concetti significa smettere di “risolvere matrici” e iniziare a modellare il mondo.

(79)

PubblicitàPubblicità