Salta al contenuto
Note per Studenti Esercizio - Probabilità dai dati - voti e meteo di Padova (laboratorio 5)

Esercizio - Probabilità dai dati - voti e meteo di Padova (laboratorio 5)

Testo (laboratorio 5, Probability and Bayesian networks, part A, corso di Intelligenza Artificiale, Ing. dell'Informazione UniPD). Due parti: un esempio sul calcolo di probabilità da una tabella e l'esercizio 11 del laboratorio.

Esempio (voti). La tabella elenca 1010 studenti con il voto finale (A, B o C) ottenuto al primo, secondo e terzo anno. Con tre variabili G1,G2,G3G_1,G_2,G_3 per i voti dei tre anni, come si calcolano probabilità come P(G1=A)P(G_1=A), P(G1=B,G2=C)P(G_1=B,G_2=C), P(G3=A∣G2=C)P(G_3=A\mid G_2=C)?

Studente G1G_1 G2G_2 G3G_3
John A A B
Sarah C C B
Eric A B B
Paul B C A
Susanne A A A
Beth B A B
Jack B C B
Rachel B A A
Tom B C C
Jenny B A B

Esercizio 11 (meteo di Padova). Il file (finto) padua_weather.csv contiene lo storico del tempo a Padova: per ogni giorno della settimana, per un anno intero (5252 settimane), il tempo è piovoso (11), nuvoloso (22) o soleggiato (33). Dopo aver formalizzato il problema (variabili aleatorie e formule necessarie), scrivere un programma Python che legge il dataset e calcola:

  • la probabilità che sia soleggiato nel fine settimana (uno o entrambi i giorni);
  • il tempo atteso per ogni giorno della settimana (un valore atteso di 2,52{,}5 si interpreta come "un misto di nuvoloso e soleggiato");
  • supponendo di non sapere che giorno è oggi (poco realistico), come indovinarlo solo dal tempo.

Parte 1: probabilità da una tabella

Si assume che la tabella rappresenti la vera distribuzione P(G1,G2,G3)P(G_1,G_2,G_3): una probabilità è una frequenza (Incertezza - probabilità, regola di Bayes e indipendenza condizionataUn agente con osservazioni parziali non può usare regole logiche rigide ("mal di denti implica carie" è falso): usa la probabilità come grado di credenza e, con la teoria dell'utilità, sceglie l'azione con utilità attesa massima. Strumenti: distribuzione congiunta completa (tabella di $2^n$ valori), marginalizzazione $P(Y\mid e)=\alpha\sum_h P(Y,e,h)$ con costante di normalizzazione $\alpha=1/P(e)$, regola del prodotto $P(a,b)=P(a\mid b)P(b)$, regola di Bayes $P(\text{causa}\mid\text{effetto})=\frac{P(\text{effetto}\mid\text{causa})P(\text{causa})}{P(\text{effetto})}$ e indipendenza condizionata $P(a,b\mid c)=P(a\mid c)P(b\mid c)$, che permette di scomporre la congiunta in tabelle più piccole. Un test con sensibilità 73% e falsi positivi 12% su una malattia con prior 1/700 dà una probabilità a posteriori di appena 0,9%.Incertezza - probabilità, regola di Bayes e indipendenza condizionata →). Più dati si hanno, meglio è, purché coprano bene la distribuzione.

  • P(G1=A)P(G_1=A): tre AA al primo anno (John, Eric, Susanne): 3/10=0,33/10=0{,}3.
  • P(G1=B,G2=C)P(G_1=B,G_2=C): tre casi (Paul, Jack, Tom): 3/10=0,33/10=0{,}3.
  • P(G3=A∣G2=C)P(G_3=A\mid G_2=C), per conteggio: quattro studenti con G2=CG_2=C (Sarah, Paul, Jack, Tom); tra questi solo Paul ha G3=AG_3=A: 1/4=0,251/4=0{,}25.
  • Dalla definizione P(a∣b)=P(a,b)/P(b)P(a\mid b)=P(a,b)/P(b): P(G2=C,G3=A)=1/10P(G_2=C,G_3=A)=1/10 (Paul), P(G2=C)=4/10P(G_2=C)=4/10, quindi 1/104/10=14=0,25\frac{1/10}{4/10}=\frac14=0{,}25. Stesso risultato: condizionare significa restringersi alle righe in cui la condizione è vera.
python
import numpy as np

voti = np.array([["A","A","B"],["C","C","B"],["A","B","B"],["B","C","A"],["A","A","A"],
                 ["B","A","B"],["B","C","B"],["B","A","A"],["B","C","C"],["B","A","B"]])
g1, g2, g3 = voti[:, 0], voti[:, 1], voti[:, 2]
print(np.mean(g1 == "A"))                                         # P(G1=A)
print(np.mean((g1 == "B") & (g2 == "C")))                         # P(G1=B, G2=C)
print(np.mean((g2 == "C") & (g3 == "A")) / np.mean(g2 == "C"))    # P(G3=A | G2=C)

Output: 0.3, 0.3, 0.25.

Parte 2: meteo di Padova

Formalizzazione. Due variabili: il tempo W∈{1,2,3}W\in\{1,2,3\} e il giorno D∈{lu,ma,me,gi,ve,sa,do}D\in\{\text{lu},\text{ma},\text{me},\text{gi},\text{ve},\text{sa},\text{do}\}. Ogni riga del file è una settimana, ogni colonna un giorno; dunque P(W=y∣D=d)P(W=y\mid D=d) è la frazione di settimane in cui, in quel giorno, il tempo è yy.

1. Sole nel fine settimana

La domanda è la probabilità dell'unione "sabato soleggiato o domenica soleggiato" (si conta ogni settimana una volta sola). Dalla soluzione del corso, 2323 settimane su 5252 hanno almeno un giorno soleggiato: P(W=3∣D=sa∨D=do)=2352≈0,4423.P(W=3\mid D=\text{sa}\lor D=\text{do})=\frac{23}{52}\approx0{,}4423. Con 1212 sabati e 1414 domeniche soleggiati (dai conteggi sotto), 12+14−23=312+14-23=3 weekend hanno entrambi i giorni soleggiati: sommare 12/52+14/5212/52+14/52 conterebbe due volte quelle settimane.

2. Tempo atteso per giorno

E(W∣D=d)=∑yy P(W=y∣D=d)E(W\mid D=d)=\sum_{y}y\,P(W=y\mid D=d). Per il lunedì: 1717 piovosi, 1414 nuvolosi, 2121 soleggiati su 5252: E(W∣D=lu)=1⋅1752+2⋅1452+3⋅2152=17+28+6352=10852≈2,077.E(W\mid D=\text{lu})=1\cdot\frac{17}{52}+2\cdot\frac{14}{52}+3\cdot\frac{21}{52}=\frac{17+28+63}{52}=\frac{108}{52}\approx2{,}077. È la media dei valori della colonna. Per i sette giorni: 2,077, 1,981, 2,038, 1,942, 1,962, 1,846, 1,7502{,}077,\ 1{,}981,\ 2{,}038,\ 1{,}942,\ 1{,}962,\ 1{,}846,\ 1{,}750. Il weekend è più "piovoso" (valori più bassi).

3. Indovinare il giorno dal tempo

Si usa la regola di Bayes: si cerca P(D∣W=w)\mathbf P(D\mid W=w) e si prende il giorno più probabile (massimo a posteriori). Poiché DD ha prior uniforme (1/71/7), P(d∣w)∝P(w∣d)P(d\mid w)\propto P(w\mid d), cioè basta contare quanti giorni di quel tipo ci sono per ogni giorno della settimana. Con tempo piovoso: tra i 137137 giorni piovosi, 1717 lunedì, 1919 martedì, 1616 mercoledì, 1919 giovedì, 1919 venerdì, 2020 sabato, 2727 domeniche: P(D∣W=1)=1137⟨17, 19, 16, 19, 19, 20, 27⟩≈⟨0,124; 0,139; 0,117; 0,139; 0,139; 0,146; 0,197⟩.\mathbf P(D\mid W=1)=\tfrac1{137}\langle17,\,19,\,16,\,19,\,19,\,20,\,27\rangle\approx\langle0{,}124;\ 0{,}139;\ 0{,}117;\ 0{,}139;\ 0{,}139;\ 0{,}146;\ \mathbf{0{,}197}\rangle. Se piove, il giorno più probabile è la domenica. Con le stesse tabelle: se è nuvoloso (totale 111111), il giorno più probabile è il sabato (20/111=0,18020/111=0{,}180); se c'è il sole (totale 116116), il lunedì (21/116=0,18121/116=0{,}181). La normalizzazione per 137137 non cambia quale giorno vince, ma serve per avere una probabilità.

Codice

python
import numpy as np

dati = np.loadtxt("padua_weather.csv", delimiter=",", skiprows=1, dtype=int)   # 52 settimane x 7 giorni
n_sett = dati.shape[0]

# 1) P(almeno uno tra sabato e domenica soleggiato)
p_weekend = np.mean((dati[:, 5] == 3) | (dati[:, 6] == 3))
print(p_weekend)

# 2) tempo atteso per giorno: E(W | D=d) = somma_y y P(W=y | D=d)
valori = np.array([1, 2, 3])
P_W_D = np.stack([(dati == y).mean(axis=0) for y in valori])   # riga y, colonna giorno
print(valori @ P_W_D)

# 3) indovinare il giorno dal tempo: P(D | W=w)
conteggi = np.stack([(dati == y).sum(axis=0) for y in valori])      # 3 x 7
P_D_w = conteggi / conteggi.sum(axis=1, keepdims=True)
print(P_D_w.round(3))
print(np.argmax(P_D_w, axis=1) + 1)    # giorno piu' probabile (lunedi = 1, ..., domenica = 7)

Output atteso (uguale a quello della soluzione del corso): 0.4423076923076923; [2.077 1.981 2.038 1.942 1.962 1.846 1.75 ]; le tre righe di P(D∣W=w)\mathbf P(D\mid W=w) (la prima è quella sopra) e [7 6 1].

Nota sulla verifica. Il file CSV originale non è fra i materiali: i conteggi (piovosi 17,19,16,19,19,20,2717,19,16,19,19,20,27; nuvolosi 14,15,18,17,16,20,1114,15,18,17,16,20,11; soleggiati 21,18,18,16,17,12,1421,18,18,16,17,12,14) sono stati ricavati dalle probabilità stampate nella soluzione del corso (sono coerenti: ogni giorno somma a 5252 e le righe a 137137, 111111, 116116). Il codice qui sopra è stato eseguito su un dataset ricostruito con questi conteggi e 2323 weekend con almeno un giorno soleggiato, e riproduce tutti gli output del corso. La soluzione del corso usa pandas e gdown; la versione qui è equivalente, con solo numpy.

Versione ripasso

  • Probabilità da una tabella = frequenze. P(G1=A)=3/10P(G_1=A)=3/10; P(G1=B,G2=C)=3/10P(G_1=B,G_2=C)=3/10; P(G3=A∣G2=C)=P(G2=C,G3=A)P(G2=C)=1/104/10=0,25P(G_3=A\mid G_2=C)=\frac{P(G_2=C,G_3=A)}{P(G_2=C)}=\frac{1/10}{4/10}=0{,}25 (condizionare = restringersi alle righe con la condizione vera).
  • Meteo: W∈{1,2,3}W\in\{1,2,3\}, DD = giorno. Sole nel weekend (unione, ogni settimana una volta): 23/52=0,442323/52=0{,}4423 (12+14−312+14-3).
  • Tempo atteso: E(W∣D=d)=∑yy P(W=y∣D=d)E(W\mid D=d)=\sum_y y\,P(W=y\mid D=d); lunedì 17+28+6352=2,077\frac{17+28+63}{52}=2{,}077; domenica 1,751{,}75 (la più piovosa).
  • Indovinare il giorno: P(D∣w)\mathbf P(D\mid w) per BayesP(d∣w)=P(w∣d)P(d)/P(w)P(d\mid w)=P(w\mid d)P(d)/P(w), con prior uniformeIncertezza - probabilità, regola di Bayes e indipendenza condizionata →, poi il massimo: pioggia →\to domenica (27/137=0,19727/137=0{,}197), nuvoloso →\to sabato, sole →\to lunedì.
  • Errori tipici: sommare P(sa)+P(do)P(\text{sa})+P(\text{do}) senza togliere l'intersezione; non normalizzare P(D∣w)\mathbf P(D\mid w) per il totale di quel tempo; confondere P(W∣D)P(W\mid D) con P(D∣W)P(D\mid W).
  • Conteggi del meteo (piovoso, nuvoloso, soleggiato per lu, ma, me, gi, ve, sa, do): piovoso 17,19,16,19,19,20,2717,19,16,19,19,20,27 (totale 137137); nuvoloso 14,15,18,17,16,20,1114,15,18,17,16,20,11 (111111); soleggiato 21,18,18,16,17,12,1421,18,18,16,17,12,14 (116116); ogni giorno somma a 5252.
  • Tempo atteso: 2,077; 1,981; 2,038; 1,942; 1,962; 1,846; 1,7502{,}077;\ 1{,}981;\ 2{,}038;\ 1{,}942;\ 1{,}962;\ 1{,}846;\ 1{,}750 (weekend più piovoso).
  • Sole nel weekend: 1212 sabati e 1414 domeniche soleggiati, 12+14−23=312+14-23=3 weekend con entrambi.
  • Giorno più probabile dato il tempo: piovoso →\to domenica (27/137=0,19727/137=0{,}197), nuvoloso →\to sabato (20/111=0,18020/111=0{,}180), soleggiato →\to lunedì (21/116=0,18121/116=0{,}181); in codice np.argmax(P_D_w, axis=1) + 1 dà [7 6 1].
  • Verifica: il CSV originale non è disponibile; il codice (solo numpy, np.loadtxt) riproduce gli output del corso su un dataset ricostruito con gli stessi conteggi.

Teoria collegata