Introduzione alla Teoria della Probabilità
In questi appunti riassumo la teoria che è alla base dei classificatori bayesiani e di una varietà di altri modelli probabilistici. Le nozioni sono utili per la comprensione degli appunti di Fondamenti relativi alle trasformazioni con riduzione di dimensionalità basate su modelli probabilistici generativi (e.g. LDA, pLSI).
La teoria della probabilità fornisce il framework matematico per modellare l'incertezza e ragionare in presenza di informazioni incomplete. Nel machine learning, questo framework è essenziale per sviluppare algoritmi robusti che possano fare predizioni affidabili anche quando i dati sono rumorosi o incompleti.
Concetti Fondamentali di Probabilità
Spazio Campionario e Eventi
Lo spazio campionario Ω rappresenta l'insieme di tutti i possibili risultati di un esperimento aleatorio. Formalmente, ogni elemento ω ∈ Ω rappresenta un possibile esito dell'esperimento.
Esempi pratici:
- Lancio di una moneta: Ω = {Testa, Croce}
- Lancio di un dado: Ω = {1, 2, 3, 4, 5, 6}
- Classificazione di email: Ω = {spam, non-spam}
- Riconoscimento di cifre: Ω = {0, 1, 2, ..., 9}
Un evento A è un sottoinsieme dello spazio campionario (A ⊆ Ω). Gli eventi possono essere:
- Elementari: contengono un solo esito
- Composti: contengono più esiti
- Certi: A = Ω (probabilità = 1)
- Impossibili: A = ∅ (probabilità = 0)
Assiomi della Probabilità
La probabilità è una funzione P: 2^Ω → [0,1] che soddisfa tre assiomi fondamentali di Kolmogorov:
- Non-negatività: P(A) ≥ 0 per ogni evento A
- Normalizzazione: P(Ω) = 1
- Additività numerabile: Per eventi disgiunti A₁, A₂, ...: P(⋃ᵢ Aᵢ) = Σᵢ P(Aᵢ)
Da questi assiomi derivano proprietà importanti come:
- P(Aᶜ) = 1 - P(A) (probabilità del complemento)
- P(∅) = 0 (probabilità dell'evento impossibile)
- Se A ⊆ B, allora P(A) ≤ P(B) (monotonia)
Variabili Aleatorie e Distribuzioni
Una variabile aleatoria X è una funzione X: Ω → ℝ che associa a ogni esito dell'esperimento un numero reale. Le variabili aleatorie si dividono in:
Variabili Aleatorie Discrete
Assumono valori in un insieme numerabile. Esempi: numero di email spam ricevute in un giorno, numero di errori in un dataset.
Variabili Aleatorie Continue
Assumono valori in un intervallo continuo. Esempi: peso di una persona, tempo di risposta di un algoritmo.
Funzioni di Probabilità
Funzione di Massa di Probabilità (PMF)
Per variabili aleatorie discrete, la PMF è definita come:
Proprietà della PMF:
- P_X(x) ≥ 0 per ogni x
- Σₓ P_X(x) = 1 (somma su tutti i valori possibili)
- P(X ∈ A) = Σₓ∈A P_X(x) per qualsiasi insieme A
Esempio: Lancio di un dado equo
Funzione di Densità di Probabilità (PDF)
Per variabili aleatorie continue, la PDF f_X(x) ha le proprietà:
- f_X(x) ≥ 0 per ogni x
- ∫₋∞^∞ f_X(x) dx = 1
- P(a ≤ X ≤ b) = ∫ₐᵇ f_X(x) dx
Nota importante: Per variabili continue, P(X = x) = 0 per qualsiasi valore specifico x. La probabilità è definita solo su intervalli.
Funzione di Ripartizione (CDF)
La CDF F_X(x) = P(X ≤ x) è definita sia per variabili discrete che continue e ha le proprietà:
- È monotona non-decrescente
- limₓ→₋∞ F_X(x) = 0 e limₓ→∞ F_X(x) = 1
- È continua a destra
Per variabili discrete:
Per variabili continue:
Probabilità Condizionale
La probabilità condizionale di A dato B (con P(B) > 0) è:
Interpretazione: P(A|B) rappresenta quanto siamo certi che A sia vero sapendo che B è vero.
Esempio pratico: In un dataset di email
- A = {email è spam}
- B = {email contiene la parola "offerta"}
- P(A|B) = probabilità che un'email sia spam dato che contiene "offerta"
Indipendenza
Due eventi A e B sono indipendenti se:
Equivalentemente: P(A|B) = P(A) (se P(B) > 0)
Per variabili aleatorie, X e Y sono indipendenti se:
per tutti i valori x, y.
Probabilità Composta e Totale
Probabilità Composta (Regola della Catena)
Per eventi A₁, A₂, ..., Aₙ:
Applicazione nel ML: Modellare sequenze di osservazioni dove ogni osservazione dipende dalle precedenti.
Probabilità Totale
Se {B₁, B₂, ..., Bₙ} è una partizione dello spazio campionario (eventi disgiunti la cui unione è Ω):
Interpretazione: La probabilità totale di A si ottiene "pesando" le probabilità condizionali di A dato ogni Bᵢ con le probabilità a priori dei Bᵢ.
Inferenza Bayesiana
Teorema di Bayes: Fondamento dell'Inferenza
Il teorema di Bayes è il pilastro dell'inferenza probabilistica:
Componenti del teorema:
- P(H|E): probabilità a posteriori - quanto siamo certi dell'ipotesi H dopo aver osservato l'evidenza E
- P(E|H): verosimiglianza - quanto è probabile osservare E se H fosse vera
- P(H): probabilità a priori - quanto siamo certi di H prima di osservare E
- P(E): evidenza marginale - probabilità totale di osservare E
Interpretazione Filosofica
Il teorema di Bayes formalizza il processo di aggiornamento delle credenze:
- Prior: Iniziamo con una credenza iniziale P(H)
- Likelihood: Osserviamo dati che ci dicono quanto sono compatibili con H
- Posterior: Aggiorniamo la nostra credenza ottenendo P(H|E)
Esempio medico:
- H = {paziente ha la malattia}
- E = {test risulta positivo}
- P(H) = prevalenza della malattia nella popolazione
- P(E|H) = sensibilità del test
- P(H|E) = probabilità che il paziente abbia la malattia dato il test positivo
Calcolo dell'Evidenza Marginale
L'evidenza marginale si calcola usando la probabilità totale:
dove {H₁, H₂, ..., Hₙ} rappresenta tutte le possibili ipotesi.
Ruolo di normalizzazione: P(E) assicura che le probabilità a posteriori sommino a 1.
Classificatori Bayesiani
Naive Bayes: Assunzione di Indipendenza
Il classificatore Naive Bayes assume che le features siano condizionalmente indipendenti data la classe:
Perché "Naive"? L'assunzione di indipendenza condizionale è spesso irrealistica ma rende il modello:
- Computazionalmente efficiente
- Robusto con pochi dati
- Sorprendentemente efficace in pratica
Classificazione: Dato un nuovo esempio x, si sceglie la classe che massimizza P(C|x):
Varianti di Naive Bayes:
- Gaussiano: per features continue con distribuzione normale
- Multinomiale: per dati di conteggio (es. frequenza parole)
- Bernoulli: for features binarie
Analisi Discriminante
L'analisi discriminante cerca funzioni che separino ottimalmente le classi nello spazio delle features.
Linear Discriminant Analysis (LDA):
- Assume che le classi abbiano la stessa matrice di covarianza
- Trova direzioni che massimizzano la separazione tra classi
- Produce confini di decisione lineari
Quadratic Discriminant Analysis (QDA):
- Permette matrici di covarianza diverse per classe
- Produce confini di decisione quadratici
- Più flessibile ma richiede più dati
Funzione discriminante: gᵢ(x) = log P(Cᵢ|x) + costante La classificazione sceglie la classe con gᵢ(x) massimo.
Distribuzioni Probabilistiche
Distribuzione Binomiale
Modella il numero di successi in n prove indipendenti con probabilità p di successo:
Parametri:
- n: numero di prove
- p: probabilità di successo in ogni prova
- k ∈ {0, 1, 2, ..., n}
Proprietà:
- Media: E[X] = np
- Varianza: Var(X) = np(1-p)
- Per n grande e p non troppo vicino a 0 o 1: X ≈ N(np, np(1-p))
Applicazioni nel ML:
- Modellare click-through rates
- Validazione incrociata (successi/fallimenti)
- A/B testing
Esempio: Numero di email spam in 100 email, se ogni email ha probabilità 0.3 di essere spam.
Distribuzione Multinomiale
Generalizzazione della binomiale per k > 2 esiti possibili:
dove Σᵢ₌₁ᵏ nᵢ = n e Σᵢ₌₁ᵏ pᵢ = 1.
Proprietà:
- Media: E[Xᵢ] = npᵢ
- Varianza: Var(Xᵢ) = npᵢ(1-pᵢ)
- Covarianza: Cov(Xᵢ, Xⱼ) = -npᵢpⱼ per i ≠ j
Applicazioni nel ML:
- Modellare frequenze di parole in documenti
- Classificazione multi-classe
- Topic modeling
Distribuzione Beta
Distribuzione continua su [0,1], spesso usata come prior per parametri di probabilità:
dove B(α,β) è la funzione Beta di Eulero:
Parametri e loro effetti:
- α, β > 0: parametri di forma
- α > 1, β > 1: distribuzione unimodale
- α = β = 1: distribuzione uniforme su [0,1]
- α < 1 o β < 1: distribuzione U-shaped
Proprietà:
- Media: E[X] = α/(α+β)
- Varianza: Var(X) = αβ/[(α+β)²(α+β+1)]
- Moda (se α,β > 1): (α-1)/(α+β-2)
Coniugazione con Binomiale: Se X|θ ~ Binomial(n,θ) e θ ~ Beta(α,β), allora: θ|X ~ Beta(α + X, β + n - X)
Applicazioni:
- Prior per probabilità di successo
- Modellare proporzioni
- Bayesian A/B testing
Distribuzione di Dirichlet
Generalizzazione multivariata della Beta, definita sul simplesso (k-1)-dimensionale:
soggetta ai vincoli: xᵢ ≥ 0 per tutti i, e Σᵢ₌₁ᵏ xᵢ = 1.
Proprietà:
- Media: E[Xᵢ] = αᵢ/α₀ dove α₀ = Σⱼ αⱼ
- Varianza: Var(Xᵢ) = αᵢ(α₀-αᵢ)/[α₀²(α₀+1)]
- Covarianza: Cov(Xᵢ,Xⱼ) = -αᵢαⱼ/[α₀²(α₀+1)] per i≠j
Coniugazione con Multinomiale: Se X|θ ~ Multinomial(n,θ) e θ ~ Dirichlet(α), allora: θ|X ~ Dirichlet(α + X)
Applicazioni fondamentali:
- Prior per distribuzioni di probabilità discrete
- Topic modeling (LDA)
- Modellare proporzioni multi-categoriali
Il Simplesso: Spazio delle Probabilità
Definizione Geometrica
Il simplesso (k-1)-dimensionale è lo spazio di tutti i vettori di probabilità k-dimensionali:
Esempi:
- k=2: Simplesso 1D = segmento [0,1] (dopo normalizzazione)
- k=3: Simplesso 2D = triangolo equilatero
- k=4: Simplesso 3D = tetraedro
Proprietà Geometriche
Vertici: I k vertici del simplesso sono i vettori unitari eᵢ = (0,...,0,1,0,...,0).
Centro: Il centro del simplesso è (1/k, 1/k, ..., 1/k).
Distanze: La distanza euclidea tra due punti x, y sul simplesso è:
Importanza nel Machine Learning
Il simplesso è fondamentale perché:
- Distribuzioni discrete vivono naturalmente sul simplesso
- Output di softmax sono punti sul simplesso
- Mixture models hanno pesi che vivono sul simplesso
- Topic models rappresentano distribuzioni di topic sul simplesso
Operazioni sul Simplesso
Proiezione su simplesso: Data un vettore v ∈ ℝᵏ, la proiezione sul simplesso si ottiene risolvendo:
Distanza di Bregman: Spesso si usano divergenze invece della distanza euclidea:
- Divergenza KL: D_KL(x||y) = Σᵢ xᵢ log(xᵢ/yᵢ)
- Divergenza di Hellinger: D_H(x,y) = Σᵢ (√xᵢ - √yᵢ)²
Applicazioni nei Modelli Generativi
Latent Dirichlet Allocation (LDA)
LDA è un modello probabilistico generativo per collezioni di documenti che assume:
Processo generativo:
- Per ogni documento d:
- Campiona una distribuzione di topic θ_d ~ Dirichlet(α)
- Per ogni topic k:
- Campiona una distribuzione di parole φ_k ~ Dirichlet(β)
- Per ogni parola w in documento d:
- Campiona un topic z ~ Multinomial(θ_d)
- Campiona una parola w ~ Multinomial(φ_z)
Inferenza: L'obiettivo è stimare θ e φ dati i documenti osservati.
Algoritmi di inferenza:
- Variational Bayes: Approssima la posterior con una distribuzione più semplice
- Gibbs Sampling: Campiona dalla posterior usando MCMC
- Collapsed Gibbs: Integra analyticamente alcuni parametri
Applicazioni:
- Topic modeling
- Raccomandazione di contenuti
- Analisi di sentiment
- Dimensionality reduction
Probabilistic Latent Semantic Indexing (pLSI)
pLSI è un predecessore di LDA che modella:
Differenze con LDA:
- Non ha prior sui parametri (non è completamente Bayesiano)
- Più semplice ma meno robusto all'overfitting
- Non può generare nuovi documenti facilmente
Hidden Markov Models (HMM)
Gli HMM sono utili per sequenze temporali:
Componenti:
- Stati nascosti: S = {s₁, s₂, ..., sₙ}
- Osservazioni: O = {o₁, o₂, ..., oₘ}
- Matrice di transizione: A = {aᵢⱼ} dove aᵢⱼ = P(sⱼ at t+1 | sᵢ at t)
- Matrice di emissione: B = {bᵢₖ} dove bᵢₖ = P(oₖ | sᵢ)
- Distribuzione iniziale: π = {πᵢ} dove πᵢ = P(s₁ = sᵢ)
Problemi fondamentali:
- Evaluation: P(O|λ) - probabilità della sequenza osservata
- Decoding: Sequenza di stati più probabile data l'osservazione
- Learning: Stimare i parametri λ = (A, B, π)
Metodi di Stima dei Parametri
Maximum Likelihood Estimation (MLE)
L'MLE trova i parametri che massimizzano la verosimiglianza dei dati osservati:
Spesso si lavora con la log-verosimiglianza:
Proprietà dell'MLE:
- Consistenza: Converge al valore vero per n → ∞
- Invarianza: Se θ̂ è MLE di θ, allora g(θ̂) è MLE di g(θ)
- Efficienza asintotica: Ha la minima varianza asintotica
Esempi:
- Binomiale: θ̂ = Σxᵢ/n (frequenza relativa)
- Normale: μ̂ = Σxᵢ/n, σ̂² = Σ(xᵢ-μ̂)²/n
- Multinomiale: θ̂ⱼ = Σᵢ xᵢⱼ/(n·k)
Maximum A Posteriori (MAP)
Il MAP trova i parametri che massimizzano la probabilità a posteriori:
Relazione con MLE: MAP = MLE + regolarizzazione (dal prior)
Vantaggi del MAP:
- Incorpora conoscenza a priori
- Può prevenire overfitting
- Funziona meglio con dati limitati
Esempi:
- Con prior Beta per Binomiale: Aggiunge "pseudo-count" α-1 e β-1
- Con prior Gaussiano per regressione: Equivale a ridge regression
- Con prior Laplace: Equivale a LASSO
Stima Bayesiana Completa
Invece di stimare un singolo valore, si considera l'intera distribuzione a posteriori:
Predizione: Per un nuovo dato x*:
Vantaggi:
- Quantifica completamente l'incertezza
- Predizioni più robuste (averaging)
- Principled way per model selection
Sfide computazionali:
- Calcolo dell'integrale spesso intrattabile
- Necessità di metodi approssimati (MCMC, Variational Inference)
Problemi e Soluzioni Pratiche
Overfitting nei Modelli Probabilistici
Cause:
- Troppi parametri rispetto ai dati
- Modello troppo complesso
- Lack of regularization
Soluzioni Bayesiane:
- Prior informativi: Incorporano conoscenza del dominio
- Hierarchical models: Prior che dipendono da iperparametri
- Model averaging: Media su diversi modelli possibili
Curse of Dimensionality
Problema: In alta dimensionalità, i dati diventano sparsi e la stima diventa difficile.
Effetti specifici:
- Naive Bayes: Molte features possono violare l'assunzione di indipendenza
- Density estimation: Servono esponenzialmente più dati
- Nearest neighbors: Tutti i punti diventano equidistanti
Soluzioni:
- Feature selection: Scegliere subset rilevanti di features
- Dimensionality reduction: PCA, t-SNE, autoencoders
- Regularization: L1, L2, elastic net
- Bayesian methods: Prior che favoriscono sparsità
Problemi di Smoothing
Problema delle probabilità zero: P(xᵢ|C) = 0 può causare problemi in Naive Bayes.
Tecniche di smoothing:
Laplace Smoothing (Add-one):
dove V è la dimensione del vocabolario.
Add-k Smoothing:
Good-Turing Smoothing: Redistribuisce massa di probabilità basandosi su frequenze di frequenze.
Kneser-Ney Smoothing: Usa contesto per smoothing più sofisticato.
Computational Issues
Underflow numerico: Prodotti di molte probabilità piccole possono causare underflow. Soluzione: Lavorare in log-space: log(ab) = log(a) + log(b)
Normalizzazione instabile: In softmax: exp(xᵢ) può essere molto grande. Soluzione: Log-sum-exp trick: log(Σᵢ exp(xᵢ)) = max(x) + log(Σᵢ exp(xᵢ - max(x)))
Applicazioni Avanzate
Bayesian Networks
Definizione: Modelli grafici che rappresentano dipendenze condizionali tra variabili.
Componenti:
- DAG (Directed Acyclic Graph): Nodi = variabili, archi = dipendenze
- CPT (Conditional Probability Tables): P(Xᵢ|Parents(Xᵢ))
Factorization: La joint distribution si fattorizza come:
Inferenza: Calcolare P(Query|Evidence) usando:
- Variable elimination
- Message passing
- Sampling methods
Variational Inference
Idea: Approssimare distribuzioni intrattabili con distribuzioni più semplici.
Mean Field Approximation: Assumere che le variabili siano indipendenti:
ELBO (Evidence Lower BOund):
Algoritmo: Massimizzare ELBO alternando tra aggiornamenti di qᵢ.
Markov Chain Monte Carlo (MCMC)
Obiettivo: Campionare da distribuzioni complesse quando il campionamento diretto è impossibile.
Metropolis-Hastings:
- Proponi nuovo stato x' da distribuzione q(x'|x)
- Calcola acceptance probability: α = min(1, P(x')q(x|x')/[P(x)q(x'|x)])
- Accetta con probabilità α
Gibbs Sampling: Caso speciale dove si campiona da distribuzioni condizionali complete.
Hamiltonian Monte Carlo: Usa gradienti per proposte più efficienti.
Esercizi e Applicazioni Pratiche
Esercizi Teorici
Esercizio 1 - Teorema di Bayes Un test medico per una malattia rara ha sensibilità 99% (P(T+|M+) = 0.99) e specificità 95% (P(T-|M-) = 0.95). La prevalenza della malattia è 0.1% (P(M+) = 0.001). Se una persona risulta positiva al test, qual è la probabilità che abbia effettivamente la malattia?
Soluzione:
Nonostante l'alta accuratezza del test, la probabilità è solo del 1.94% a causa della bassa prevalenza.
Esercizio 2 - Naive Bayes Dato un dataset di email con features:
- Contiene "gratis": P(gratis|spam) = 0.8, P(gratis|ham) = 0.1
- Contiene "!": P(!|spam) = 0.7, P(!|ham) = 0.2
- P(spam) = 0.3, P(ham) = 0.7
Classificare un'email che contiene sia "gratis" che "!".
Soluzione:
Classificazione: spam (0.168 > 0.014)
Implementazioni Python
Implementazione Naive Bayes da Zero:
import numpy as np
from collections import defaultdict
class NaiveBayes:
def __init__(self, smoothing=1.0):
self.smoothing = smoothing
self.class_priors = {}
self.feature_probs = defaultdict(dict)
self.classes = []
def fit(self, X, y):
self.classes = np.unique(y)
n_samples = len(y)
# Calcola probabilità a priori delle classi
for c in self.classes:
self.class_priors[c] = np.sum(y == c) / n_samples
# Calcola probabilità condizionali delle features
for feature_idx in range(X.shape[1]):
feature_values = np.unique(X[:, feature_idx])
for c in self.classes:
class_mask = (y == c)
class_feature_counts = X[class_mask, feature_idx]
for value in feature_values:
count = np.sum(class_feature_counts == value)
total = np.sum(class_mask)
# Laplace smoothing
prob = (count + self.smoothing) / (total + self.smoothing * len(feature_values))
self.feature_probs[feature_idx][(c, value)] = prob
def predict_proba(self, X):
predictions = []
for sample in X:
class_scores = {}
for c in self.classes:
score = np.log(self.class_priors[c])
for feature_idx, value in enumerate(sample):
if (c, value) in self.feature_probs[feature_idx]:
score += np.log(self.feature_probs[feature_idx][(c, value)])
else:
# Smoothing per valori non visti
score += np.log(self.smoothing / (np.sum([y == c]) + self.smoothing * 10))
class_scores[c] = score
# Normalizzazione
max_score = max(class_scores.values())
exp_scores = {c: np.exp(score - max_score) for c, score in class_scores.items()}
total = sum(exp_scores.values())
probabilities = {c: score/total for c, score in exp_scores.items()}
predictions.append(probabilities)
return predictions
def predict(self, X):
probas = self.predict_proba(X)
return [max(proba.keys(), key=lambda k: proba[k]) for proba in probas]
Implementazione Distribuzione Dirichlet:
import numpy as np
from scipy.special import gammaln
class DirichletDistribution:
def __init__(self, alpha):
self.alpha = np.array(alpha)
self.k = len(alpha)
def pdf(self, x):
"""Calcola la densità di probabilità"""
x = np.array(x)
# Verifica vincoli del simplesso
if not (np.all(x >= 0) and np.abs(np.sum(x) - 1) < 1e-10):
return 0.0
# Log-densità per stabilità numerica
log_pdf = (gammaln(np.sum(self.alpha)) -
np.sum(gammaln(self.alpha)) +
np.sum((self.alpha - 1) * np.log(x + 1e-10)))
return np.exp(log_pdf)
def sample(self, n_samples=1):
"""Campiona dalla distribuzione"""
samples = np.random.gamma(self.alpha, 1, (n_samples, self.k))
return samples / np.sum(samples, axis=1, keepdims=True)
def mean(self):
"""Media della distribuzione"""
return self.alpha / np.sum(self.alpha)
def variance(self):
"""Varianza della distribuzione"""
alpha0 = np.sum(self.alpha)
return (self.alpha * (alpha0 - self.alpha)) / (alpha0**2 * (alpha0 + 1))
def concentration(self):
"""Parametro di concentrazione"""
return np.sum(self.alpha)
# Esempio d'uso
if __name__ == "__main__":
# Distribuzione simmetrica
dir_sym = DirichletDistribution([1, 1, 1])
samples_sym = dir_sym.sample(1000)
# Distribuzione concentrata
dir_conc = DirichletDistribution([10, 2, 1])
samples_conc = dir_conc.sample(1000)
print("Media distribuzione simmetrica:", dir_sym.mean())
print("Media distribuzione concentrata:", dir_conc.mean())
Caso di Studio: Sistema di Raccomandazione Probabilistico
Problema: Sviluppare un sistema di raccomandazione per articoli di news che incorpori incertezza nelle preferenze utente.
Approccio Bayesiano:
class BayesianRecommendationSystem:
def __init__(self, n_topics=10, alpha=0.1, beta=0.01):
self.n_topics = n_topics
self.alpha = alpha # Prior per distribuzione topic-utente
self.beta = beta # Prior per distribuzione parola-topic
# Parametri del modello
self.user_topic_dist = {} # θ: distribuzione topic per utente
self.topic_word_dist = {} # φ: distribuzione parole per topic
def fit(self, user_item_matrix, content_features):
"""
Addestra il modello usando Variational Bayes
Args:
user_item_matrix: matrice utenti x articoli (ratings)
content_features: features di contenuto degli articoli
"""
n_users, n_items = user_item_matrix.shape
n_words = content_features.shape[1]
# Inizializza parametri variational
gamma = np.random.gamma(1, 1, (n_users, self.n_topics)) # q(θ)
lambda_param = np.random.gamma(1, 1, (self.n_topics, n_words)) # q(φ)
# EM algorithm con Variational Bayes
for iteration in range(100):
# E-step: aggiorna distribuzioni a posteriori approssimate
# Aggiorna γ (parametri per θ)
for u in range(n_users):
for k in range(self.n_topics):
gamma[u, k] = self.alpha + np.sum([
self._compute_topic_assignment_prob(u, i, k, gamma, lambda_param)
* user_item_matrix[u, i]
for i in range(n_items) if user_item_matrix[u, i] > 0
])
# Aggiorna λ (parametri per φ)
for k in range(self.n_topics):
for w in range(n_words):
lambda_param[k, w] = self.beta + np.sum([
self._compute_word_topic_prob(i, w, k, gamma, lambda_param)
* content_features[i, w]
for i in range(n_items)
])
# Verifica convergenza
if iteration > 0 and self._check_convergence(gamma, lambda_param):
break
# Salva parametri finali
self._save_parameters(gamma, lambda_param)
def _compute_topic_assignment_prob(self, user, item, topic, gamma, lambda_param):
"""Calcola probabilità di assegnamento topic"""
# Implementazione semplificata
user_topic_score = gamma[user, topic] / np.sum(gamma[user, :])
item_topic_score = np.sum(lambda_param[topic, :] * self.content_features[item, :])
return user_topic_score * item_topic_score
def predict_rating(self, user_id, item_id, n_samples=100):
"""
Predice rating con quantificazione dell'incertezza
Returns:
mean_rating: rating medio predetto
std_rating: deviazione standard della predizione
"""
if user_id not in self.user_topic_dist:
return 0.0, 1.0 # Utente nuovo: alta incertezza
# Campiona dalle distribuzioni a posteriori
ratings = []
for _ in range(n_samples):
# Campiona distribuzione topic per utente
theta = np.random.dirichlet(self.user_topic_dist[user_id])
# Calcola rating basato su similarity topic-based
item_topics = self._get_item_topic_distribution(item_id)
predicted_rating = np.dot(theta, item_topics) * 5 # Scala 1-5
ratings.append(predicted_rating)
return np.mean(ratings), np.std(ratings)
def recommend_items(self, user_id, n_recommendations=10, uncertainty_threshold=0.5):
"""
Raccomanda items considerando sia rating che incertezza
"""
candidate_items = self._get_candidate_items(user_id)
recommendations = []
for item_id in candidate_items:
mean_rating, std_rating = self.predict_rating(user_id, item_id)
# Scarta items con alta incertezza
if std_rating > uncertainty_threshold:
continue
# UCB-style ranking: bilancia exploitation vs exploration
ucb_score = mean_rating + 0.1 * std_rating
recommendations.append({
'item_id': item_id,
'predicted_rating': mean_rating,
'uncertainty': std_rating,
'ucb_score': ucb_score
})
# Ordina per UCB score
recommendations.sort(key=lambda x: x['ucb_score'], reverse=True)
return recommendations[:n_recommendations]
Frontiere della Ricerca
Probabilistic Programming
I linguaggi di programmazione probabilistica permettono di specificare modelli complessi in modo dichiarativo:
Esempio in PyMC3:
import pymc3 as pm
import theano.tensor as tt
def hierarchical_regression_model(X, y, groups):
"""
Modello di regressione gerarchica Bayesiana
"""
with pm.Model() as model:
# Hyperpriors
mu_alpha = pm.Normal('mu_alpha', mu=0, sd=1)
sigma_alpha = pm.HalfNormal('sigma_alpha', sd=1)
mu_beta = pm.Normal('mu_beta', mu=0, sd=1)
sigma_beta = pm.HalfNormal('sigma_beta', sd=1)
# Priors per group-level parameters
alpha = pm.Normal('alpha', mu=mu_alpha, sd=sigma_alpha, shape=len(np.unique(groups)))
beta = pm.Normal('beta', mu=mu_beta, sd=sigma_beta, shape=len(np.unique(groups)))
# Likelihood
mu = alpha[groups] + beta[groups] * X
sigma = pm.HalfNormal('sigma', sd=1)
y_obs = pm.Normal('y_obs', mu=mu, sd=sigma, observed=y)
# Sampling
trace = pm.sample(2000, tune=1000, cores=4)
return model, trace
# Inferenza predittiva
def posterior_predictive_check(model, trace, X_new, groups_new):
with model:
# Predizioni out-of-sample
pm.set_data({'X': X_new, 'groups': groups_new})
posterior_pred = pm.sample_posterior_predictive(trace, samples=1000)
return posterior_pred
Causal Inference
Andare oltre le correlazioni per scoprire relazioni causali:
Pearl's Causal Hierarchy:
- Association (P(Y|X)): correlazioni statistiche
- Intervention (P(Y|do(X))): effetti di interventi
- Counterfactuals (P(Y_x|X',Y')): reasoning controfattuale
Esempio - Causal Effect Estimation:
class CausalInferenceFramework:
def __init__(self, confounders, treatment, outcome):
self.confounders = confounders
self.treatment = treatment
self.outcome = outcome
def estimate_ate(self, data, method='ipw'):
"""
Stima Average Treatment Effect usando diversi metodi
Args:
data: dataframe con confounders, treatment, outcome
method: 'ipw' (Inverse Propensity Weighting), 'doubly_robust', etc.
"""
if method == 'ipw':
return self._inverse_propensity_weighting(data)
elif method == 'doubly_robust':
return self._doubly_robust_estimation(data)
else:
raise ValueError(f"Unknown method: {method}")
def _inverse_propensity_weighting(self, data):
"""Inverse Propensity Weighting"""
# Stima propensity scores
propensity_model = LogisticRegression()
propensity_model.fit(data[self.confounders], data[self.treatment])
propensity_scores = propensity_model.predict_proba(data[self.confounders])[:, 1]
# Calcola pesi IPW
weights = np.where(data[self.treatment] == 1,
1/propensity_scores,
1/(1-propensity_scores))
# Stima ATE
treated_outcome = np.average(data[data[self.treatment] == 1][self.outcome],
weights=weights[data[self.treatment] == 1])
control_outcome = np.average(data[data[self.treatment] == 0][self.outcome],
weights=weights[data[self.treatment] == 0])
ate = treated_outcome - control_outcome
# Bootstrap per uncertainty quantification
bootstrap_ates = []
for _ in range(1000):
boot_indices = np.random.choice(len(data), len(data), replace=True)
boot_data = data.iloc[boot_indices]
boot_ate = self._inverse_propensity_weighting(boot_data)
bootstrap_ates.append(boot_ate)
std_error = np.std(bootstrap_ates)
return {
'ate': ate,
'std_error': std_error,
'confidence_interval': np.percentile(bootstrap_ates, [2.5, 97.5])
}
Scalable Bayesian Methods
Stochastic Variational Inference:
class StochasticVariationalInference:
def __init__(self, model, batch_size=100, learning_rate=0.01):
self.model = model
self.batch_size = batch_size
self.learning_rate = learning_rate
def fit(self, data, n_epochs=100):
"""
Addestra usando mini-batch gradient ascent su ELBO
"""
n_samples = len(data)
variational_params = self._initialize_variational_params()
for epoch in range(n_epochs):
# Shuffle data
shuffled_data = data.sample(frac=1).reset_index(drop=True)
epoch_elbo = 0
for i in range(0, n_samples, self.batch_size):
batch = shuffled_data[i:i+self.batch_size]
# Calcola stochastic gradient dell'ELBO
elbo, grad = self._compute_stochastic_elbo_gradient(
batch, variational_params, n_samples
)
# Update variational parameters
variational_params = self._update_parameters(
variational_params, grad, self.learning_rate
)
epoch_elbo += elbo
if epoch % 10 == 0:
print(f"Epoch {epoch}, ELBO: {epoch_elbo/n_samples:.4f}")
return variational_params
def _compute_stochastic_elbo_gradient(self, batch, var_params, total_samples):
"""
Calcola gradiente stocastico dell'ELBO
"""
batch_size = len(batch)
scaling_factor = total_samples / batch_size
# Monte Carlo estimate del gradiente
mc_samples = 10
grad_estimates = []
for _ in range(mc_samples):
# Campiona da distribuzione variational
z_sample = self._sample_from_variational(var_params)
# Calcola gradiente per questo sample
log_likelihood = self.model.log_likelihood(batch, z_sample)
log_prior = self.model.log_prior(z_sample)
log_variational = self._log_variational_density(z_sample, var_params)
# ELBO sample
elbo_sample = scaling_factor * log_likelihood + log_prior - log_variational
# Gradient usando score function estimator
grad = self._score_function_gradient(z_sample, var_params, elbo_sample)
grad_estimates.append(grad)
# Media dei gradienti
final_grad = np.mean(grad_estimates, axis=0)
final_elbo = np.mean([est.elbo for est in grad_estimates])
return final_elbo, final_grad
Considerazioni Etiche e Filosofiche
Interpretabilità vs Prestazioni
I modelli probabilistici offrono spesso maggiore interpretabilità rispetto ai metodi black-box, ma questo può venire a scapito delle prestazioni:
Vantaggi dell'interpretabilità:
- Fiducia nelle decisioni automatiche
- Debugging e miglioramento del modello
- Compliance con regulazioni (GDPR, etc.)
- Scoperta di bias nascosti
Trade-offs:
- Modelli più semplici potrebbero avere prestazioni inferiori
- L'interpretabilità ha costi computazionali
- Diverse stakeholder richiedono diversi tipi di spiegazioni
Bias e Fairness
I modelli probabilistici possono perpetuare o amplificare bias presenti nei dati:
Tipi di bias:
- Selection bias: campioni non rappresentativi
- Confirmation bias: prior informativi incorretti
- Algorithmic bias: assunzioni del modello inappropriate
Mitigazione:
- Auditing regolare dei modelli
- Fairness constraints nell'ottimizzazione
- Diversità nei team di sviluppo
- Testing su popolazioni diverse
Privacy e Sicurezza
Differential Privacy: Garantire che le predizioni non rivelino informazioni su individui specifici:
def add_laplace_noise(value, sensitivity, epsilon):
"""
Aggiunge rumore Laplaciano per differential privacy
Args:
value: valore originale
sensitivity: sensibilità della query
epsilon: privacy budget
"""
scale = sensitivity / epsilon
noise = np.random.laplace(0, scale)
return value + noise
class PrivacyPreservingBayesianModel:
def __init__(self, epsilon=1.0):
self.epsilon = epsilon # Privacy budget
def private_posterior_sampling(self, data, n_samples=1000):
"""
Campiona dalla posterior aggiungendo rumore per privacy
"""
# Calcola sufficient statistics
sufficient_stats = self._compute_sufficient_statistics(data)
# Aggiungi rumore differentially private
noisy_stats = [
add_laplace_noise(stat, self._compute_sensitivity(stat), self.epsilon)
for stat in sufficient_stats
]
# Campiona da posterior usando noisy statistics
posterior_samples = self._sample_posterior(noisy_stats, n_samples)
return posterior_samples
Riferimenti e Approfondimenti
Testi Fondamentali
"Pattern Recognition and Machine Learning" - Christopher Bishop
- Trattazione completa di metodi probabilistici nel ML
- Excellent balance tra teoria e pratica
"The Elements of Statistical Learning" - Hastie, Tibshirani, Friedman
- Fondamenti statistici del machine learning
- Approfondimenti su bias-variance trade-off
"Probabilistic Graphical Models" - Daphne Koller & Nir Friedman
- Guida definitiva ai modelli grafici
- Teoria e algoritmi per inference
"Bayesian Data Analysis" - Gelman, Carlin, Stern, Rubin
- Approccio pratico all'analisi Bayesiana
- Molti esempi reali e case studies
Risorse Online
- Distill.pub: Visualizzazioni interattive di concetti ML
- Towards Data Science: Articoli pratici e tutorial
- NIPS/ICML Proceedings: Conference proceedings di alta qualità
Software e Librerie
Python:
- PyMC3/PyMC4: Probabilistic programming
- Stan (PyStan): Bayesian inference platform
- Scikit-learn: Implementazioni standard
- TensorFlow Probability: Deep probabilistic models
R:
- BUGS/JAGS: Bayesian inference usando Gibbs sampling
- rstanarm: Interface R per Stan
- MCMCpack: MCMC algorithms
Specialized:
- Church/WebPPL: Probabilistic programming languages
- Edward/TensorFlow Probability: Deep probabilistic models
- Pyro: Deep universal probabilistic programming
Conclusioni Finali
La teoria della probabilità rappresenta il linguaggio matematico fondamentale per modellare l'incertezza nel machine learning e nell'intelligenza artificiale. I concetti esplorati in questi appunti - dall'inferenza Bayesiana ai modelli generativi, dalle distribuzioni classiche alle applicazioni moderne - forniscono gli strumenti concettuali necessari per sviluppare sistemi intelligenti robusti e affidabili.
Punti chiave da ricordare:
Principi Fondamentali: Gli assiomi della probabilità e il teorema di Bayes sono alla base di tutto il reasoning probabilistico
Modeling: La scelta della distribuzione e dei prior è cruciale per il successo del modello
Computation: L'implementazione efficiente richiede attenzione ai problemi numerici e alla scalabilità
Validation: La valutazione deve includere non solo accuracy ma anche calibration e robustezza
Ethics: Considerazioni su bias, fairness e privacy sono essenziali per applicazioni responsabili
Il futuro del machine learning probabilistico è ricco di opportunità, dall'integrazione con deep learning alla scalabilità per big data, dalla causal inference alle applicazioni in domini critici come medicina e finanza. La padronanza di questi concetti fondamentali è essenziale per contribuire a questo campo in rapida evoluzione e per sviluppare la prossima generazione di sistemi intelligenti.