Modello di Leslie in Python: Guida ed Esercizi per l’Analisi delle Popolazioni

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Modello di Leslie Python

Prevedere come cambierà una popolazione non è un esercizio di stile per accademici, ma una necessità pratica. Che si tratti di gestire un allevamento, proteggere una specie in via d’estinzione o pianificare le risorse di un ecosistema, i numeri devono parlare. Il Modello di Leslie è lo strumento che trasforma i dati biologici — chi nasce e chi sopravvive — in una traiettoria futura. In queste righe non ci limiteremo a far girare un algoritmo: vedremo come poche righe di codice in Python possano svelare se un sistema è destinato a prosperare o a spegnersi lentamente.

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

Esercizio 1 (Facile): Analisi di una Popolazione Semplice

Testo:
Un allevamento di conigli ha la seguente struttura per classi di età (in mesi):

  • Classe 0-3: 100 conigli

  • Classe 3-6: 50 conigli

  • Classe 6-9: 30 conigli

Le femmine di classe 0-3 non si riproducono, quelle di classe 3-6 generano 4 nuovi conigli ogni 3 mesi (in media 1.33 per femmina), quelle di classe 6-9 generano 2 nuovi conigli ogni 3 mesi (in media 0.67 per femmina). Assumendo che:

  1. il 60% dei conigli di classe 0-3 sopravviva e passi alla classe 3-6

  2. il 40% di quelli di classe 3-6 sopravviva e passi alla classe 6-9

  3. i conigli di classe 6-9 muoiano tutti dopo il periodo

Calcola la popolazione dopo un periodo di 3 mesi usando il modello di Leslie, assumendo che metà dei conigli siano femmine.

Risoluzione:

import numpy as np

# 1. Definizione del vettore popolazione iniziale
# [classe 0-3, classe 3-6, classe 6-9]
n0 = np.array([100, 50, 30])  # popolazione totale
femmine = n0 * 0.5  # metà sono femmine

print("Popolazione iniziale (totale):", n0)
print("Femmine iniziali:", femmine)

# 2. Costruzione della matrice di Leslie
# La matrice L ha:
# - Prima riga: tassi di natalità per classe
# - Sottodiagonale: tassi di sopravvivenza tra classi
# - Altri elementi: zero

L = np.zeros((3, 3))

# Tassi di fecondità (per femmina, per periodo di 3 mesi)
# Solo le femmine si riproducono
# Classe 0-3: 0 figli
# Classe 3-6: 1.33 figli (4/3) PER FEMMINA
# Classe 6-9: 0.67 figli (2/3) PER FEMMINA
# Ma nella matrice mettiamo il contributo per individuo TOTALE
# Quindi dividiamo per 2 (solo metà sono femmine)
L[0, 1] = 1.33 * 0.5  # 4/3 * 0.5 = 0.667
L[0, 2] = 0.67 * 0.5  # 2/3 * 0.5 = 0.333

# Tassi di sopravvivenza
L[1, 0] = 0.60  # da 0-3 a 3-6
L[2, 1] = 0.40  # da 3-6 a 6-9

print("\nMatrice di Leslie L:")
print(L)

# 3. Calcolo della popolazione dopo un periodo
n1 = L @ n0  # Moltiplicazione matrice-vettore

print("\nPopolazione dopo 3 mesi:", n1)
print("Popolazione totale dopo 3 mesi:", np.sum(n1))
Popolazione iniziale (totale): [100  50  30]
Femmine iniziali: [50. 25. 15.]

Matrice di Leslie L:
[[0.    0.665 0.335]
 [0.6   0.    0.   ]
 [0.    0.4   0.   ]]

Popolazione dopo 3 mesi: [43.3 60.  20. ]
Popolazione totale dopo 3 mesi: 123.3

Spiegazione:

  1. Definizione del vettore popolazione: Rappresentiamo la distribuzione per classi di età

  2. Costruzione matrice di Leslie:

    • Elementi L[0,j]: tassi di fecondità (numero di nuovi nati da individui di classe j)

    • Elementi L[i,i-1]: tassi di sopravvivenza da una classe alla successiva

  3. Evoluzione temporale: La popolazione al tempo t+1 si ottiene moltiplicando L per la popolazione al tempo t

Forse potrebbe interessarti anche:  Distribuzione Gamma: La Guida Pratica per Modellare Tempi e Valori Positivi (con Esempi e Codice Python)

Osservazioni:
💡 Attenzione ai tassi di fecondità:
Nella matrice di Leslie, gli elementi della prima riga rappresentano il contributo di CIASCUN individuo di una data classe all’anno successivo. Se solo le femmine si riproducono, dobbiamo considerare la proporzione di femmine nella popolazione.

Pubblicità

Domanda di riflessione:
Perché nella prima colonna della matrice di Leslie abbiamo tutti zeri nella riga 0? Cosa rappresenta questo biologicamente?

Esercizio 2 (Facile-Medio): Simulazione per Più Periodi

Testo:
Utilizzando i dati dell’esercizio 1, simula l’evoluzione della popolazione per 5 periodi (15 mesi). Calcola:

  1. La popolazione totale ad ogni periodo

  2. La distribuzione percentuale per classi di età ad ogni periodo

  3. Il tasso di crescita complessivo tra il primo e l’ultimo periodo

Risoluzione:

import numpy as np
import matplotlib.pyplot as plt

# Definizione iniziali e matrice di Leslie (stessa dell'esercizio 1)
n0 = np.array([100, 50, 30])
L = np.array([[0, 0.667, 0.333],
              [0.6, 0, 0],
              [0, 0.4, 0]])

# 1. Simulazione per 5 periodi
periodi = 5
popolazione = np.zeros((periodi + 1, 3))  # +1 per includere il tempo 0
popolazione[0] = n0

for t in range(periodi):
    popolazione[t+1] = L @ popolazione[t]

print("Evoluzione della popolazione (totale per classe):")
for t in range(periodi + 1):
    print(f"Periodo {t}: {popolazione[t]} (totale: {np.sum(popolazione[t]):.1f})")

# 2. Distribuzione percentuale
print("\nDistribuzione percentuale per classi:")
for t in range(periodi + 1):
    totale = np.sum(popolazione[t])
    percentuali = (popolazione[t] / totale) * 100
    print(f"Periodo {t}: Classe1={percentuali[0]:.1f}%, Classe2={percentuali[1]:.1f}%, Classe3={percentuali[2]:.1f}%")

# 3. Tasso di crescita
pop_finale = np.sum(popolazione[-1])
pop_iniziale = np.sum(popolazione[0])
tasso_crescita = (pop_finale / pop_iniziale) ** (1/periodi) - 1

print(f"\nTasso di crescita medio per periodo: {tasso_crescita*100:.2f}%")
print(f"Popolazione finale/popolazione iniziale: {pop_finale/pop_iniziale:.3f}")

# 4. Visualizzazione
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))

# Grafico popolazione totale
tempi = list(range(periodi + 1))
totali = [np.sum(popolazione[t]) for t in tempi]
ax1.plot(tempi, totali, 'o-', linewidth=2)
ax1.set_xlabel('Periodo (3 mesi)')
ax1.set_ylabel('Popolazione totale')
ax1.set_title('Crescita della popolazione totale')
ax1.grid(True, alpha=0.3)

# Grafico distribuzioni
classi = ['0-3 mesi', '3-6 mesi', '6-9 mesi']
for i in range(3):
    ax2.plot(tempi, popolazione[:, i], 'o-', label=classi[i], linewidth=2)
ax2.set_xlabel('Periodo (3 mesi)')
ax2.set_ylabel('Popolazione per classe')
ax2.set_title('Distribuzione per classi di età')
ax2.legend()
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

 

Evoluzione della popolazione (totale per classe):
Periodo 0: [100.  50.  30.] (totale: 180.0)
Periodo 1: [43.34 60.   20.  ] (totale: 123.3)
Periodo 2: [46.68  26.004 24.   ] (totale: 96.7)
Periodo 3: [25.336668 28.008    10.4016  ] (totale: 63.7)
Periodo 4: [22.1450688 15.2020008 11.2032   ] (totale: 48.6)
Periodo 5: [13.87040013 13.28704128  6.08080032] (totale: 33.2)

Distribuzione percentuale per classi:
Periodo 0: Classe1=55.6%, Classe2=27.8%, Classe3=16.7%
Periodo 1: Classe1=35.1%, Classe2=48.6%, Classe3=16.2%
Periodo 2: Classe1=48.3%, Classe2=26.9%, Classe3=24.8%
Periodo 3: Classe1=39.7%, Classe2=43.9%, Classe3=16.3%
Periodo 4: Classe1=45.6%, Classe2=31.3%, Classe3=23.1%
Periodo 5: Classe1=41.7%, Classe2=40.0%, Classe3=18.3%

Tasso di crescita medio per periodo: -28.67%
Popolazione finale/popolazione iniziale: 0.185

Spiegazione teorica:
Il modello di Leslie è un modello lineare discreto:

n(t+1) = L * n(t).

Questo implica che n(t) = L^t * n(0). La dinamica a lungo termine è determinata dall’autovalore dominante di L.

Forse potrebbe interessarti anche:  Parquet vs CSV con Python: 6 Esercizi Pratici per Ottimizzare i Tuoi Dataframe

Osservazioni:
💡 Stabilità della distribuzione:
Dopo alcuni periodi, la distribuzione percentuale tende a stabilizzarsi anche se la popolazione totale cresce o decresce. Questa distribuzione stabile è l’autovettore destro dell’autovalore dominante.

Domanda di riflessione:
Cosa noti riguardo alla distribuzione percentuale dopo diversi periodi? Perché pensi che accada questo?

Esercizio 3 (Medio): Analisi degli Autovalori e Distribuzione Stabile

Testo:
Data la matrice di Leslie dell’esercizio 1:

  1. Calcola gli autovalori e autovettori

  2. Identifica l’autovalore dominante (il più grande in modulo)

  3. Verifica che la distribuzione stabile (autovettore corrispondente) corrisponda alla distribuzione percentuale osservata nell’esercizio 2 dopo molti periodi

  4. Calcola il tasso di crescita a lungo termine

Risoluzione:

import numpy as np

# Matrice di Leslie dell'esercizio 1
L = np.array([[0, 0.667, 0.333],
              [0.6, 0, 0],
              [0, 0.4, 0]])

# 1. Calcolo autovalori e autovettori
autovalori, autovettori = np.linalg.eig(L)

print("Autovalori della matrice di Leslie:")
for i, val in enumerate(autovalori):
    print(f"λ{i+1} = {val:.4f} (modulo: {np.abs(val):.4f})")

# 2. Identificazione autovalore dominante
moduli = np.abs(autovalori)
idx_dominante = np.argmax(moduli)
lambda1 = autovalori[idx_dominante]
v1 = autovettori[:, idx_dominante]  # Autovettore destro

print(f"\nAutovalore dominante: λ = {lambda1:.4f}")
print(f"Modulo: |λ| = {np.abs(lambda1):.4f}")
print(f"Tasso di crescita a lungo termine per periodo: {(np.abs(lambda1)-1)*100:.2f}%")

# 3. Normalizzazione dell'autovettore (per avere somma 1)
v1_normalizzato = v1 / np.sum(v1)
print(f"\nDistribuzione stabile (autovettore normalizzato):")
print(f"Classe 0-3: {v1_normalizzato[0]*100:.2f}%")
print(f"Classe 3-6: {v1_normalizzato[1]*100:.2f}%")
print(f"Classe 6-9: {v1_normalizzato[2]*100:.2f}%")

# 4. Verifica sperimentale: simulazione per molti periodi
print("\nVerifica sperimentale con simulazione:")
n0 = np.array([100, 50, 30])
n = n0.copy()
for t in range(20):  # Molti periodi
    n = L @ n

# Distribuzione dopo molti periodi
distribuzione_sperimentale = n / np.sum(n)
print(f"\nDistribuzione dopo 20 periodi (sperimentale):")
print(f"Classe 0-3: {distribuzione_sperimentale[0]*100:.2f}%")
print(f"Classe 3-6: {distribuzione_sperimentale[1]*100:.2f}%")
print(f"Classe 6-9: {distribuzione_sperimentale[2]*100:.2f}%")

# Confronto
print("\nConfronto tra teoria e sperimentale:")
print(f"Differenza classe 0-3: {abs(v1_normalizzato[0]-distribuzione_sperimentale[0])*100:.4f}%")
print(f"Differenza classe 3-6: {abs(v1_normalizzato[1]-distribuzione_sperimentale[1])*100:.4f}%")
print(f"Differenza classe 6-9: {abs(v1_normalizzato[2]-distribuzione_sperimentale[2])*100:.4f}%")
Autovalori della matrice di Leslie:
λ1 = 0.7155 (modulo: 0.7155)
λ2 = -0.4853 (modulo: 0.4853)
λ3 = -0.2302 (modulo: 0.2302)

Autovalore dominante: λ = 0.7155
Modulo: |λ| = 0.7155
Tasso di crescita a lungo termine per periodo: -28.45%

Distribuzione stabile (autovettore normalizzato):
Classe 0-3: 43.34%
Classe 3-6: 36.34%
Classe 6-9: 20.32%

Verifica sperimentale con simulazione:

Distribuzione dopo 20 periodi (sperimentale):
Classe 0-3: 43.34%
Classe 3-6: 36.33%
Classe 6-9: 20.32%

Confronto tra teoria e sperimentale:
Differenza classe 0-3: 0.0047%
Differenza classe 3-6: 0.0107%
Differenza classe 6-9: 0.0061%

Teoria degli autovalori:

Per una matrice di Leslie [math]L[/math]:

  • L’equazione caratteristica è: [math]\displaystyle \begin{aligned} \lambda^n &= f_1\lambda^{n-1} + f_2s_1\lambda^{n-2} + \dots \ &{} \quad + f_ns_1s_2\dots s_{n-1} \end{aligned}[/math]
  • Esiste un unico autovalore positivo reale [math]\lambda_1[/math] (Teorema di Perron-Frobenius)
  • Per [math]t\to\infty[/math], [math]n(t) \approx c\cdot\lambda_1^t\cdot v_1[/math], dove [math]v_1[/math] è l’autovettore destro corrispondente

Osservazioni:
💡 Interpretazione dell’autovalore dominante:
Se [math]|\lambda_1| > 1[/math], la popolazione cresce; se [math]|\lambda_1| < 1[/math], si estingue; se [math]|\lambda_1| = 1[/math], la popolazione rimane costante in media. [math]\lambda_1[/math] rappresenta il fattore di crescita per periodo a lungo termine.

Domanda di riflessione:
Perché nella matrice di Leslie di dimensioni 3×3 ci aspettiamo di trovare 3 autovalori? Cosa rappresentano gli autovalori complessi in questo contesto biologico?

Risposte alle Domande di Riflessione

Pubblicità

Esercizio 1:

Risposta: Nella prima colonna della matrice di Leslie abbiamo tutti zeri nella riga 0 perché gli individui della classe più giovane (0-3 mesi) non si riproducono. Biologicamente, questo rappresenta il periodo di immaturità sessuale, comune in molte specie.

Forse potrebbe interessarti anche:  Distribuzione Multinomiale: Guida Pratica per Data Scientist (NLP e Python)

Esercizio 2:

Risposta: La distribuzione percentuale tende a stabilizzarsi dopo alcuni periodi. Questo accade perché, indipendentemente dalla distribuzione iniziale, la popolazione evolve verso la distribuzione stabile di età, che è l’autovettore destro dell’autovalore dominante. Questa è una proprietà fondamentale delle matrici di Leslie con autovalore dominante reale positivo.

Esercizio 3:

Risposta: Una matrice 3×3 ha 3 autovalori (contati con molteplicità). Gli autovalori complessi in questo contesto biologico rappresentano oscillazioni nella dinamica della popolazione. Quando ci sono autovalori complessi coniugati, la popolazione mostra fluttuazioni periodiche prima di stabilizzarsi nella distribuzione stabile.

Approfondimento Applicativo

Gli esercizi proposti non sono solo un test di programmazione, ma toccano tre punti nevralgici della modellistica professionale:

  1. Il Filtro della Natalità: Nell’esercizio 1, il fatto di dover “pesare” la natalità sulla popolazione totale (dividendo per 2 perché solo le femmine partoriscono) insegna a non prendere mai i dati grezzi come oro colato. In un contesto professionale (es. gestione ittica), sbagliare questo coefficiente significa sovrastimare la crescita del 100%, portando al collasso della risorsa.

  2. L’Inerzia Biologica: L’esercizio 2 mostra come una popolazione possa continuare a decrescere anche se ci sono nuovi nati. È il concetto di “momentum” demografico: la struttura per età iniziale influenza il destino dei primi periodi tanto quanto i tassi di sopravvivenza.

  3. La Profezia dell’Autovalore: L’esercizio 3 è il più “visionario”. Dimostra che il destino di un sistema è scritto nella sua struttura (la matrice). Se λ1 < 1, non importa quanto la popolazione sembri stabile inizialmente: l’estinzione è matematicamente certa a meno di non intervenire sui parametri di sopravvivenza.

Applicazioni reali: Questi script sono la base per i software usati dai biologi della fauna selvatica per decidere le quote di caccia sostenibile o per i demografi che studiano l’invecchiamento della popolazione in ambito assicurativo.

Pubblicità