Un test diagnostico risulta positivo: quanto è probabile che tu sia davvero malato? E quando dici che pescando una carta da un mazzo di 52 hai «una probabilità su quattro» di prendere un cuori, che cosa stai assegnando, e a che cosa? La probabilità è nata per rispondere a domande così, ma per rispondere in modo coerente serve un piccolo insieme di regole fissate una volta per tutte.
La risposta di questo articolo è che bastano tre assiomi, formulati da Andrej Kolmogorov nel 1933 nei Grundbegriffe der Wahrscheinlichkeitsrechnung (Springer, Berlino), e che tutto il resto, dalla formula di Bayes all'indipendenza, è un teorema. Per seguirlo ti bastano insiemi, serie numeriche e qualche calcolo con le frazioni; la teoria della misura non è richiesta, e dove servirebbe lo dico. Ogni risultato qui sotto è calcolato in due modi, con le frazioni esatte e con una simulazione a seme fisso, e le due cose coincidono entro l'errore che dichiaro.
Che cos'è uno spazio di probabilità
Un esperimento casuale si descrive con tre oggetti, che insieme formano la terna (Ω, F, P). Ω è l'insieme degli esiti possibili: per una carta pescata ha 52 elementi, per il lancio di due monete ne ha quattro (HH, HT, TH, TT). Un evento è un sottoinsieme di Ω: «esce un cuori» è l'insieme delle 13 carte di cuori. F è la famiglia degli eventi ai quali vuoi poter assegnare una probabilità, e P è la funzione che li misura, con valori fra 0 e 1.
Perché non dire semplicemente che ogni sottoinsieme è un evento? Quando Ω è finito si può, ed è quello che fai con il mazzo. Ma Ω può essere un intervallo come [0, 1], e lì la teoria della misura dimostra che esistono sottoinsiemi a cui nessuna assegnazione coerente di «lunghezza» può dare un valore (il risultato di Vitali; la dimostrazione richiede l'assioma di scelta e sta fuori da questo articolo).
Per questo F deve essere una σ-algebra: una famiglia di sottoinsiemi che contiene Ω, contiene il complemento di ogni suo elemento e contiene l'unione di ogni famiglia numerabile di suoi elementi. In parole povere, se sai valutare «A» sai valutare «non A», e se sai valutare ciascun evento di una lista (anche infinita ma numerabile) sai valutare «accade almeno uno di loro».
Una σ-algebra è anche un modo di dire quanta informazione hai. Con due monete, la famiglia {∅, {HH, HT}, {TH, TT}, Ω} contiene solo gli eventi che dipendono dalla prima moneta: sa dire «la prima è testa», non sa dire «la seconda è testa». Il programma seguente prende la definizione alla lettera e la verifica per esaurimento: su un insieme di n punti elenca tutte le 22n famiglie di sottoinsiemi (256 per n = 3, 65.536 per n = 4), tiene quelle che contengono Ω e sono chiuse per complemento e unione (su un insieme finito le unioni numerabili si riducono a quelle finite), e le conta. Poi calcola la σ-algebra generata da una partizione, cioè la più piccola che contiene gli insiemi dati, chiudendoli ripetutamente.
# Quante sigma-algebre esistono su un insieme finito? Controllo per esaurimento.
from itertools import combinations
def sigma_algebre(n):
"""Tutte le famiglie F di sottoinsiemi di {0..n-1} (come maschere di bit)
che contengono Omega, sono chiuse per complemento e per unione."""
tutti = (1 << n) - 1 # Omega come maschera
trovate = []
for famiglia in range(1 << (1 << n)): # ogni famiglia = un sottoinsieme dei 2^n insiemi
membri = [s for s in range(1 << n) if famiglia >> s & 1]
if tutti not in membri:
continue
insieme = set(membri)
if any((tutti ^ s) not in insieme for s in membri):
continue
if any((a | b) not in insieme for a, b in combinations(membri, 2)):
continue
trovate.append(membri)
return trovate
for n in (3, 4):
print(f"n={n}: {len(sigma_algebre(n))} sigma-algebre (su {2**(2**n)} famiglie candidate)")
def generata(n, generatori):
"""Chiusura per complemento e unione dei generatori (e di Omega)."""
tutti = (1 << n) - 1
f = {tutti, 0} | set(generatori)
cambiato = True
while cambiato:
cambiato = False
for s in list(f):
if (tutti ^ s) not in f:
f.add(tutti ^ s); cambiato = True
for a, b in combinations(list(f), 2):
if (a | b) not in f:
f.add(a | b); cambiato = True
return f
def maschera(elementi):
return sum(1 << (e - 1) for e in elementi)
C = [maschera({1, 2}), maschera({3, 4, 5}), maschera({6, 7, 8})]
print("sigma generata da {1,2},{3,4,5},{6,7,8} su 8 punti:", len(generata(8, C)), "elementi")
prima_moneta = [maschera({1, 2})] # esiti 1=HH, 2=HT, 3=TH, 4=TT: 'prima testa'
print("sigma generata da 'prima moneta testa' su 4 esiti:", len(generata(4, [0b0011])), "elementi")
# Le sigma-algebre su n punti sono tante quante le partizioni di n punti (numeri di Bell)
def bell(n):
riga = [1]
for _ in range(n - 1):
nuova = [riga[-1]]
for x in riga:
nuova.append(nuova[-1] + x)
riga = nuova
return riga[-1]
print("numeri di Bell B(1..6):", [bell(k) for k in range(1, 7)])
# Output:
# n=3: 5 sigma-algebre (su 256 famiglie candidate)
# n=4: 15 sigma-algebre (su 65536 famiglie candidate)
# sigma generata da {1,2},{3,4,5},{6,7,8} su 8 punti: 8 elementi
# sigma generata da 'prima moneta testa' su 4 esiti: 4 elementi
# numeri di Bell B(1..6): [1, 2, 5, 15, 52, 203]
Su tre punti le σ-algebre sono 5, su quattro sono 15, e la riga dei numeri di Bell conferma lo schema: sono tante quante le partizioni dell'insieme in blocchi, perché una σ-algebra finita è determinata dai suoi «atomi», gli eventi minimi che non si possono spezzare.
Lo vedi anche nelle ultime due righe: la partizione {1,2}, {3,4,5}, {6,7,8} genera 8 = 23 eventi, uno per ogni modo di scegliere quali blocchi unire, e la sola prima moneta ne genera 4. Il conto è esatto solo perché Ω è finito; su un insieme infinito non esiste un'enumerazione di questo tipo, ed è il motivo per cui lì si lavora con la σ-algebra di Borel, generata dagli intervalli, senza mai scriverla per esteso.
I tre assiomi e ciò che ne discende
Una funzione P definita sugli eventi di F è una misura di probabilità se rispetta tre condizioni, e nient'altro:
- Non negatività: P(A) ≥ 0 per ogni evento A.
- Normalizzazione: P(Ω) = 1.
- σ-additività: se A1, A2, … sono eventi a due a due disgiunti, P(A1 ∪ A2 ∪ …) = P(A1) + P(A2) + …
Le prime due fissano la scala (nessuna probabilità negativa, l'evento certo vale 1); la terza è la sola regola di calcolo, e dice che la probabilità di «uno fra tanti casi che si escludono a vicenda» è la somma. L'ordine qui non è intercambiabile: la terza usa la parola «probabilità» e ha senso solo dopo che le prime due hanno stabilito che cosa è una probabilità. Tutto il resto si deriva.
Per esempio P(∅) = 0: applicando la terza alla successione di infiniti insiemi vuoti (disgiunti perché vuoti) si ottiene P(∅) = P(∅) + P(∅) + …, e un numero non negativo che è uguale alla somma di infinite copie di sé stesso può essere solo zero.
Da P(A) + P(Ac) = P(Ω) = 1 segue P(Ac) = 1 − P(A), dove Ac è il complementare; se A ⊂ B segue P(A) ≤ P(B), perché B si spezza in A e B − A, disgiunti.
Con due eventi qualsiasi vale l'inclusione-esclusione: P(A ∪ B) = P(A) + P(B) − P(A ∩ B), perché sommando P(A) e P(B) conti due volte la parte comune.
Un esempio con numeri veri: peschi una carta da un mazzo di 52. Sia A «cuori» (13 carte) e B «figura», cioè J, Q o K (12 carte). Tre carte stanno in entrambi gli insiemi: J, Q e K di cuori. Con la misura uniforme, in cui ogni carta vale 1/52, P(A ∪ B) = 13/52 + 12/52 − 3/52 = 22/52.
Il programma costruisce il mazzo, conta le carte dell'unione direttamente con le frazioni esatte, confronta con la formula, e poi ripete la prova un milione di volte con un generatore a seme fisso. Il criterio di accettazione è dichiarato: la frequenza osservata deve cadere entro tre errori standard, 3√(p(1 − p)/N), dal valore esatto.
from fractions import Fraction
from itertools import product
import numpy as np
semi = range(4) # 0 = cuori
valori = range(13) # 0=asso, 1..9 = 2..10, 10=J, 11=Q, 12=K
mazzo = list(product(semi, valori))
cuori = {c for c in mazzo if c[0] == 0}
figure = {c for c in mazzo if c[1] >= 10} # J, Q, K: 12 carte in tutto
P = lambda E: Fraction(len(E), len(mazzo)) # misura uniforme
esatto = P(cuori | figure)
incl_escl = P(cuori) + P(figure) - P(cuori & figure)
print("|cuori|, |figure|, |cuori e figure| =", len(cuori), len(figure), len(cuori & figure))
print("P(A o B) esatto =", esatto, "=", float(esatto))
print("incl.-escl. =", incl_escl, "uguale:", esatto == incl_escl)
N = 10**6
rng = np.random.default_rng(42)
pesca = rng.integers(0, 52, size=N)
seme, valore = pesca // 13, pesca % 13
freq = np.mean((seme == 0) | (valore >= 10))
p = float(esatto)
tol = 3 * (p * (1 - p) / N) ** 0.5
print(f"Monte Carlo N={N}: {freq:.5f}; errore atteso (3 sigma) {tol:.5f}; scarto {abs(freq-p):.5f}")
assert abs(freq - p) < tol
# Output:
# |cuori|, |figure|, |cuori e figure| = 13 12 3
# P(A o B) esatto = 11/26 = 0.4230769230769231
# incl.-escl. = 11/26 uguale: True
# Monte Carlo N=1000000: 0.42294; errore atteso (3 sigma) 0.00148; scarto 0.00014
Il valore esatto è 11/26, circa 0,4231, e la formula dà esattamente lo stesso conteggio. La simulazione scarta di 0,00014 a fronte di una tolleranza di 0,00148: nel caso tipico lo scarto è di circa un errore standard, quindi un valore così piccolo è normale e non va letto come una prova più forte. Quello che la simulazione non può dire è perché l'inclusione-esclusione sia vera: lo dicono gli assiomi.
Con n eventi la formula completa ha 2n − 1 intersezioni da calcolare, e già con n = 20 sono più di un milione; per questo nella pratica si usa spesso solo la maggiorazione di Boole, P(A1 ∪ … ∪ An) ≤ P(A1) + … + P(An), che discende dalla stessa additività ed è sempre vera anche quando gli eventi si sovrappongono.
Probabilità condizionata e formula di Bayes
Se sai che è accaduto B, lo spazio degli esiti possibili si restringe a B, e le probabilità vanno riscalate perché sommino ancora a 1. Questa è la probabilità condizionata: P(A | B) = P(A ∩ B) / P(B), definita solo se P(B) > 0. Riscrivendola come P(A ∩ B) = P(A | B) P(B) ottieni la regola del prodotto, che iterata dà la regola della catena su più eventi.
Se gli eventi B1, …, Bm formano una partizione di Ω (si escludono a vicenda e coprono tutto), la formula delle probabilità totali scompone P(A) = Σj P(A | Bj) P(Bj).
Scrivendo in due modi P(A ∩ Bi) e dividendo per P(A) si arriva alla formula di Bayes: P(Bi | A) = P(A | Bi) P(Bi) / Σj P(A | Bj) P(Bj). Le due direzioni, P(A | B) e P(B | A), sono numeri diversi, e scambiarli è l'errore più comune di tutta la materia.
Esercizio svolto. Un test per una malattia ha sensibilità 99% (se sei malato, risulta positivo nel 99% dei casi) e specificità 95% (se sei sano, risulta negativo nel 95% dei casi, cioè dà un falso positivo nel 5%). La malattia ha prevalenza 1%, cioè colpisce una persona su cento.
Il tuo test è positivo: qual è la probabilità di essere malato? Per rispondere si calcola il valore predittivo positivo con la formula di Bayes, lo si riscrive in frequenze naturali (su 10.000 persone, quante sono nei due gruppi) perché è il modo in cui la mente lo afferra, si fa variare la prevalenza, e si simula una popolazione di un milione di persone contando, tra i positivi, quanti sono davvero malati.
from fractions import Fraction as F
import numpy as np
def ppv(sens, spec, prev):
return sens * prev / (sens * prev + (1 - spec) * (1 - prev))
sens, spec, prev = F(99, 100), F(95, 100), F(1, 100)
print("PPV esatto =", ppv(sens, spec, prev), "=", round(float(ppv(sens, spec, prev)), 4))
# Le stesse cifre in frequenze naturali, su 10000 persone
malati = 100; veri_pos = 99; sani = 9900; falsi_pos = 495
print("frequenze naturali:", veri_pos, "veri positivi su", veri_pos + falsi_pos, "positivi =", F(veri_pos, veri_pos + falsi_pos))
for p in (F(1, 1000), F(1, 100), F(1, 10), F(1, 2)):
print(f"prevalenza {float(p):5.3f}: PPV = {float(ppv(sens, spec, p)):.4f}")
N = 10**6
rng = np.random.default_rng(7)
malato = rng.random(N) < 0.01
u = rng.random(N)
positivo = np.where(malato, u < 0.99, u < 0.05) # malati: 99% positivi; sani: 5% positivi
n_pos = int(positivo.sum())
freq = malato[positivo].mean()
p = float(ppv(sens, spec, prev))
tol = 3 * (p * (1 - p) / n_pos) ** 0.5
print(f"Monte Carlo: {n_pos} positivi, quota di malati {freq:.4f}; atteso {p:.4f} +/- {tol:.4f}")
assert abs(freq - p) < tol
# Output:
# PPV esatto = 1/6 = 0.1667
# frequenze naturali: 99 veri positivi su 594 positivi = 1/6
# prevalenza 0.001: PPV = 0.0194
# prevalenza 0.010: PPV = 0.1667
# prevalenza 0.100: PPV = 0.6875
# prevalenza 0.500: PPV = 0.9519
# Monte Carlo: 59337 positivi, quota di malati 0.1660; atteso 0.1667 +/- 0.0046
La risposta è 1/6, circa 16,7%, e non il 99% che il numero della sensibilità suggerisce. Le frequenze naturali mostrano il motivo: su 10.000 persone i malati sono 100 e ne risultano positivi 99, ma i sani sono 9.900 e il 5% di loro, cioè 495, risulta positivo per errore; i falsi positivi superano i veri di cinque volte. La tabella delle prevalenze è la parte più istruttiva: con una malattia rara (una su mille) lo stesso test, di qualità identica, dà un valore predittivo del 1,9%, mentre con prevalenza al 50% sale al 95%.
Nessuna delle due caratteristiche del test basta da sola; conta anche la popolazione a cui lo applichi. La simulazione trova 59.337 positivi, di cui il 16,60% malati, a fronte di un atteso del 16,67% con tolleranza di 0,46 punti percentuali: la tolleranza è più larga di quella delle carte perché i positivi sono meno del campione intero. Questa è l'aritmetica, non un consiglio medico: nessun risultato di un test si interpreta senza un professionista sanitario.
Indipendenza: a coppie non basta
Due eventi sono indipendenti se P(A ∩ B) = P(A) P(B); se P(B) > 0 è come dire che P(A | B) = P(A), cioè sapere B non cambia la probabilità di A. È una condizione algebrica sulla P scelta, non un'impressione sulla «vita reale»: due eventi possono essere indipendenti per una misura e dipendenti per un'altra.
Per più eventi non basta controllare le coppie: serve l'indipendenza mutua, cioè la regola del prodotto per ogni sottofamiglia di almeno due eventi, che sono 2n − n − 1 uguaglianze. Con tre eventi sono quattro: le tre coppie e la tripla. Questa definizione è la 4.2 del capitolo 4 di Grinstead e Snell, che porta lo stesso tipo di controesempio come esercizio.
Il controesempio è costruibile con due monete eque. Sia A «la prima è testa», B «la seconda è testa», C «esce esattamente una testa». Ognuno ha probabilità 1/2, e ogni coppia ha probabilità 1/4 = 1/2 · 1/2: le coppie sono indipendenti. Ma se escono due teste non può uscire «esattamente una testa», quindi A ∩ B ∩ C è vuoto. Il programma lo calcola con le frazioni sull'insieme dei quattro esiti, e controlla anche un errore diffuso: due eventi disgiunti non sono indipendenti, salvo che uno dei due abbia probabilità zero.
from fractions import Fraction as F
from itertools import product, combinations
omega = list(product((0, 1), repeat=2)) # (prima, seconda); 1 = testa
P = lambda E: F(len(E), len(omega))
A = {w for w in omega if w[0] == 1} # prima testa
B = {w for w in omega if w[1] == 1} # seconda testa
C = {w for w in omega if w[0] != w[1]} # esattamente una testa
for (na, X), (nb, Y) in combinations([("A", A), ("B", B), ("C", C)], 2):
print(f"P({na} e {nb}) = {P(X & Y)} prodotto = {P(X) * P(Y)} indipendenti: {P(X & Y) == P(X) * P(Y)}")
print("P(A e B e C) =", P(A & B & C), " prodotto =", P(A) * P(B) * P(C))
# Disgiunti non e' indipendenti: A = 'prima testa', D = 'prima croce'
D = {w for w in omega if w[0] == 0}
print("A e D disgiunti:", A & D == set(), "| P(A e D) =", P(A & D), "contro P(A)P(D) =", P(A) * P(D))
# Output:
# P(A e B) = 1/4 prodotto = 1/4 indipendenti: True
# P(A e C) = 1/4 prodotto = 1/4 indipendenti: True
# P(B e C) = 1/4 prodotto = 1/4 indipendenti: True
# P(A e B e C) = 0 prodotto = 1/8
# A e D disgiunti: True | P(A e D) = 0 contro P(A)P(D) = 1/4
Le tre coppie sono indipendenti, la tripla no: P(A ∩ B ∩ C) = 0, mentre il prodotto delle tre probabilità sarebbe 1/8. Conseguenza pratica: sapere che A e B sono accaduti ti dice tutto su C (non è accaduto), anche se nessuna delle due notizie da sola te ne dice qualcosa.
L'ultima riga corregge l'abitudine di usare «disgiunto» e «indipendente» come sinonimi: «prima testa» e «prima croce» si escludono, quindi la loro intersezione ha probabilità 0, mentre il prodotto vale 1/4. Se due eventi non possono accadere insieme, sapere che uno è accaduto ti dà informazione massima sull'altro, il contrario dell'indipendenza.
I lemmi di Borel-Cantelli: accade infinite volte?
Data una successione di eventi A1, A2, …, l'evento «An accade infinitamente spesso» si scrive come intersezione su n delle unioni da n in poi: nessuna coda della successione è priva di eventi. Il primo lemma di Borel-Cantelli dice che se la somma delle probabilità converge, Σn P(An) < ∞, allora quasi certamente solo un numero finito di eventi accade.
La dimostrazione è una riga: la probabilità che accada almeno un evento da n in poi è al più la coda della serie, Σk ≥ n P(Ak), che tende a 0. Il secondo lemma richiede l'indipendenza: se gli eventi sono indipendenti e la somma diverge, quasi certamente ne accadono infiniti. Senza indipendenza il secondo lemma è falso: basta prendere An = A per ogni n, con P(A) = 1/2.
Una simulazione non può mostrare «infinitamente» perché gira per un tempo finito, e conviene dirlo prima di leggerne l'uscita. Quello che si può osservare sono le quantità che il ragionamento usa, calcolabili esattamente. Il programma genera 20.000 successioni indipendenti, con P(An) = 1/n2 (serie convergente) oppure 1/n (serie divergente), e conta quanti eventi accadono per n da 21 a 2000, la «coda» dopo i primi venti.
Confronta la media con la somma esatta delle probabilità e la frazione di successioni senza alcun evento nella coda con il prodotto esatto dei complementari, che per l'indipendenza è la probabilità di non vederne nessuno.
import numpy as np
from fractions import Fraction
R, N, SOGLIA = 20000, 2000, 20 # replicati, orizzonte, "coda" = eventi con n > SOGLIA
n = np.arange(1, N + 1)
rng = np.random.default_rng(2024)
risultati = {}
for nome, p in (("1/n^2", 1 / n**2), ("1/n", 1 / n)):
nella_coda = np.zeros(R, dtype=int)
for inizio in range(0, R, 500): # a blocchi, per non occupare memoria
occ = rng.random((500, N)) < p # occ[r, k] = A_{k+1} accade nel replicato r
nella_coda[inizio:inizio + 500] = occ[:, SOGLIA:].sum(axis=1)
risultati[nome] = nella_coda
coda = n[SOGLIA:]
for nome, p in (("1/n^2", 1 / coda**2), ("1/n", 1 / coda)):
atteso = p.sum() # valore atteso del numero di eventi nella coda
prob_nessuno = np.prod(1 - p) # indipendenza: prodotto
r = risultati[nome]
print(f"P(A_n)={nome:6}: eventi con n in ({SOGLIA},{N}]: media {r.mean():.3f} (esatta {atteso:.3f}); "
f"P(nessuno) simulata {np.mean(r == 0):.4f} (esatta {prob_nessuno:.4f})")
sd = (p * (1 - p)).sum() ** 0.5 # deviazione standard del conteggio
assert abs(r.mean() - atteso) < 4 * sd / R ** 0.5, nome
print("medie entro 4 errori standard dal valore esatto")
# Output:
# P(A_n)=1/n^2 : eventi con n in (20,2000]: media 0.049 (esatta 0.048); P(nessuno) simulata 0.9522 (esatta 0.9529)
# P(A_n)=1/n : eventi con n in (20,2000]: media 4.603 (esatta 4.581); P(nessuno) simulata 0.0092 (esatta 0.0100)
# medie entro 4 errori standard dal valore esatto
Nel caso convergente la coda contiene in media 0,049 eventi e il 95% delle successioni non ne ha nessuno: dopo i primi venti, quasi niente accade più, ed è ciò che il primo lemma prevede (la somma della coda, 0,048, è anche una maggiorazione della probabilità di vederne almeno uno).
Nel caso divergente la coda ne contiene in media 4,6, e la probabilità di non vederne nessuno fino a 2000 è l'1%: allungando l'orizzonte il conteggio medio cresce come il logaritmo di N senza fermarsi, ed è il comportamento che il secondo lemma porta al limite. Le due medie sono entro quattro errori standard del valore esatto, come il programma verifica con un'asserzione. Ricorda che queste sono prove di coerenza su un orizzonte finito, non una dimostrazione dei lemmi: la dimostrazione è il paragrafo precedente.
Che cosa resta fuori
Tre cose vanno oltre quanto qui è stato dimostrato, e conviene sapere dove cominciano. Condizionare su un evento di probabilità zero, come «X = 3» per una variabile continua, non è coperto dalla definizione sopra e richiede la probabilità condizionata regolare. L'estensione di una probabilità da una famiglia semplice di eventi a tutta la σ-algebra generata (il teorema di Carathéodory) è ciò che permette di costruire la misura di Lebesgue e i processi stocastici infiniti.
Il valore atteso condizionato rispetto a una σ-algebra generalizza le probabilità totali. Per queste, e per le dimostrazioni complete, il riferimento classico è un testo di probabilità fondata sulla teoria della misura, come quelli di Billingsley o di Kallenberg; non li ho aperti per questo articolo, e li nomino solo per indicare dove proseguire.
Prova da solo: sigma-algebre su cinque punti
Quante σ-algebre esistono su un insieme di cinque punti? Ragiona sulle partizioni in atomi e confronta con la riga dei numeri di Bell stampata dal programma. Soluzione: 52, il numero di partizioni di un insieme di cinque elementi; una volta scelta la partizione, la σ-algebra è l'insieme di tutte le unioni di blocchi, che per k blocchi sono 2k.
Domande frequenti
Perché Kolmogorov usa la teoria della misura?
Perché permette di trattare insieme casi discreti e continui con le stesse regole, e di costruire probabilità su spazi infiniti, come le traiettorie di un processo. Gli assiomi sono quelli di una misura positiva di massa totale 1, e questo collega la probabilità a un apparato già sviluppato per le lunghezze e i volumi.
Un evento di probabilità zero è impossibile?
No. Se scegli un numero a caso in [0, 1] con distribuzione uniforme, ogni singolo valore ha probabilità zero, eppure uno di essi uscirà. Zero significa «quasi certamente non accade», non «non può accadere»; l'evento impossibile è solo l'insieme vuoto.
Perché il test positivo non significa che sono malato al 99%?
Perché il 99% è la probabilità di un risultato positivo se si è malati, non la probabilità di essere malati se il risultato è positivo. Le due probabilità sono legate dalla formula di Bayes tramite la prevalenza: con prevalenza all'1% e specificità del 95% il valore predittivo è 1/6.
Che cosa sai fare adesso
Sai definire uno spazio di probabilità e controllare se una famiglia di eventi è una σ-algebra, derivare dalle tre regole le proprietà che userai ogni giorno, e calcolare una probabilità condizionata sia con la formula sia con le frequenze naturali. Sai distinguere l'indipendenza a coppie da quella mutua e l'indipendenza dall'incompatibilità, e sai leggere i lemmi di Borel-Cantelli come una dichiarazione su code di serie.
Il passo successivo è dare un numero a ogni esito: le variabili aleatorie discrete, che usano la formula delle probabilità totali per scomporre un conteggio in prove indipendenti. Con la variabile che può assumere qualsiasi valore in un intervallo cambia il modo di assegnare le probabilità, che diventano aree: lo vedi nelle variabili continue. Più avanti, le distribuzioni multivariate riprendono la probabilità condizionata per più grandezze insieme, e il teorema centrale del limite usa l'indipendenza introdotta qui. L'indice dell'intera serie è alla pagina Probabilità e Statistica.
Nella stessa serie trovi anche Analisi dati esplorativa (EDA) con Python.
Fonti
- Grinstead e Snell, Introduction to Probability (versione libera del progetto CHANCE) - capitolo 4, §4.1: probabilità condizionata, probabilità di Bayes, definizioni 4.1 e 4.2 di indipendenza, esercizio sull'indipendenza a coppie senza indipendenza mutua; indice e passaggi letti nel PDF, consultata il 2026-11-13
- MIT OpenCourseWare 6.041SC, Probabilistic Systems Analysis and Applied Probability (Tsitsiklis, 2013) - l'ordine degli argomenti del corso (modelli di probabilità e variabili discrete, poi variabili generali, poi leggi dei grandi numeri) a cui la serie si allinea; letta la pagina del corso, non le singole lezioni, consultata il 2026-11-13
- A. N. Kolmogorov, Grundbegriffe der Wahrscheinlichkeitsrechnung, Springer, Berlino, 1933 - l'assiomatizzazione attribuita nel testo; volume a stampa non consultato, la data e l'editore sono quelli del riferimento bibliografico standard
Programmi eseguiti con Python 3.14.4 (python3 -I), NumPy 2.3.5, due volte ciascuno con uscita identica. I semi dei generatori sono 42 (carte), 7 (test diagnostico) e 2024 (Borel-Cantelli).
Commenti
Caricamento commenti...
Accedi per commentare