Opportunità, sfide e rischi dell'IA: come si misurano, non come si temono
Corso Machine Learning Engineer · Modulo 00 · Mindset data-driven · Lezione 3
Obiettivo. Sostituire le opinioni ("l'IA è pericolosa", "l'IA risolve tutto") con misure. Il lettore impara a fare tre cose: scoprire che l'accuratezza può mentire, auditare un modello per gruppo, e capire perché certi obiettivi di equità non si possono soddisfare insieme (con dimostrazione).
Falso mito. "Se il modello è accurato, è anche equo." Nel codice di questa lezione il gruppo con l'accuratezza più alta è quello penalizzato.
Introduzione
Ogni tecnologia ha opportunità e rischi. Con l'IA il dibattito si perde subito nelle opinioni. Un ingegnere ha un vantaggio: può misurare. Questa lezione ti dà gli strumenti di misura essenziali e il quadro normativo europeo in cui si lavora.
Roadmap. (1) Le opportunità, in modo concreto. (2) Le sfide, in sette famiglie. (3) Prima misura: la matrice di confusione e l'accuratezza che mente. (4) Seconda misura: l'audit per gruppo. (5) Perché non si può avere tutto: la dimostrazione. (6) Il quadro normativo e di governo. (7) Cosa fare il lunedì mattina.
Cos'è, perché conta, quando NON fidarsi
Opportunità: dove l'IA aiuta davvero
Si possono ridurre a quattro verbi, ciascuno con la sua forma di compito:
| Verbo | Compito ML | Esempio |
|---|---|---|
| Prevedere | Regressione / classificazione | Stimare la domanda di un prodotto; marcare una transazione sospetta |
| Raggruppare | Clustering | Scoprire segmenti di utenti simili |
| Ordinare | Ranking / raccomandazione | Quali risultati mostrare per primi |
| Generare / riassumere | Modelli generativi | Bozze di testo, sintesi di documenti (modulo 10) |
Il filo comune è che l'IA fa bene i compiti ripetitivi, con molti esempi, in cui un errore occasionale è tollerabile, e li fa a una scala che l'attenzione umana non regge.
Sfide: sette famiglie
- Qualità dei dati: mancanti, duplicati, etichette sbagliate.
- Bias: il modello eredita le distorsioni del dato e dell'etichettatura.
- Privacy: i dati personali richiedono base giuridica e minimizzazione.
- Spiegabilità: "perché ha deciso così?" non sempre ha risposta.
- Robustezza e sicurezza: input avversari, prompt injection, cambio di distribuzione.
- Costi: calcolo, dati, persone, manutenzione continua.
- Responsabilità: chi risponde dell'errore?
Le sette voci non pesano uguale in ogni progetto, ma nessuna si può saltare: le prime due nascono dai dati, le ultime cinque dal modo in cui il modello viene usato. La sezione che segue traduce ciascuna in un controllo che puoi eseguire, perché un rischio che non sai misurare resta un'opinione.
Quando NON fidarsi di un numero di prestazione
Quando manca (a) la baseline, (b) la separazione tra training e test, (c) la scomposizione per sottogruppi, (d) il costo asimmetrico degli errori. Le due sezioni seguenti coprono (a) e (c).
Le sette sfide, e come si misura ciascuna
Un elenco di rischi non basta: per ciascuno serve un controllo concreto, che un ingegnere possa eseguire. Ecco la traduzione operativa.
- Qualità dei dati: si misura con conteggi semplici. Quante righe duplicate? Quale percentuale di valori mancanti per colonna? Quante etichette sono in disaccordo quando due persone etichettano lo stesso esempio? Un tasso di disaccordo alto tra etichettatori dice che il problema è mal definito prima ancora di cominciare.
- Bias: si misura confrontando le metriche per gruppo (è l'audit della sezione seguente). Non esiste un test unico: esiste una famiglia di criteri tra cui scegliere, e la scelta è una decisione, non un calcolo.
- Privacy: si misura con l'inventario: quali dati personali entrano nel modello, con quale base giuridica, per quanto tempo, e se ne servono davvero tutti (principio di minimizzazione). Un controllo pratico: togliere una colonna personale e verificare di quanto cala la prestazione; se il calo è trascurabile, la colonna non andava raccolta.
- Spiegabilità: si misura chiedendosi se, per una singola decisione, si riesce a dire quali caratteristiche l'hanno determinata e se un esperto del dominio considera quelle ragioni sensate.
- Robustezza: si misura perturbando gli ingressi (rumore, valori estremi, categorie mai viste) e osservando quanto cambia l'uscita; e confrontando la prestazione sui dati di oggi con quella sui dati di un anno fa (cambio di distribuzione).
- Costi: si misurano in modo esplicito, inclusi quelli che di solito si dimenticano: etichettatura, riaddestramento periodico, monitoraggio, revisione umana.
- Responsabilità: si misura con una domanda scritta nel documento di progetto: «Se questo modello sbaglia in modo grave, chi viene avvisato, chi decide di spegnerlo, chi risponde?» Se la risposta non c'è, il rischio non è gestito.
La regola trasversale: un rischio senza misura è un'opinione, e un'opinione non si monitora nel tempo. Nota che sei controlli su sette sono conteggi o confronti che si fanno in poche righe di codice o con un foglio di calcolo: la parte difficile non è calcolarli, è decidere in anticipo quale valore fa scattare un intervento, e scriverlo prima di vedere i risultati.
Preparazione
pip install numpy scikit-learn
Nessun dato esterno: tutti i dati sono simulati con generatori che dichiariamo. Tutti i numeri nel testo sono prodotti dal codice, con seed fissato.
Primo esempio: l'accuratezza che mente
Analogia: il guardiano che dorme
Immagina un guardiano notturno in un edificio dove entra un ladro ogni cinquanta notti. Se il guardiano dorme sempre e dichiara "nessun ladro", ha ragione quarantanove notti su cinquanta: il 98%. Il suo "tasso di successo" è altissimo e il suo valore è zero, perché non vede mai l'unico evento che conta.
Prima delle definizioni, un'immagine mentale. Ogni previsione di un classificatore binario è un verdetto su un caso: «allarme» o «tutto ok». Il verdetto può essere giusto o sbagliato in due modi diversi: un allarme su un caso innocuo (falso allarme) o un silenzio davanti a un caso vero (mancato rilevamento). Questi due errori hanno quasi sempre costi diversi (un filtro antispam che manda in spam una mail importante vs. una che lascia passare una pubblicità), e la matrice di confusione serve proprio a tenerli separati invece di fonderli in un solo numero.
Definizioni: la matrice di confusione
Per un problema con due classi (positivo = l'evento che cerchiamo, per esempio frode) ogni previsione cade in una di quattro caselle:
| Previsto positivo | Previsto negativo | |
|---|---|---|
| Davvero positivo | VP (vero positivo) | FN (falso negativo) |
| Davvero negativo | FP (falso positivo) | VN (vero negativo) |
Da qui, le misure fondamentali (le definisco tutte, nessuna è "ovvia"):
- Accuratezza =
(VP + VN) / (VP + VN + FP + FN): frazione di risposte giuste. - Richiamo / TPR =
VP / (VP + FN): tra i positivi veri, quanti ne ho trovati. - Tasso di falsi positivi / FPR =
FP / (FP + VN): tra i negativi veri, quanti ho scambiato per positivi. - Precisione / PPV =
VP / (VP + FP): tra quelli che ho segnalato, quanti lo erano davvero.
Le prime due righe guardano l'insieme delle risposte e i positivi veri, le ultime due guardano l'errore per classe. Il guardiano che dorme ha accuratezza 98% e richiamo 0%: nessuna delle quattro misure da sola basta, e sono il richiamo e la precisione quelle che denunciano il guardiano. Il FPR e il PPV sembrano parenti ma hanno denominatori diversi (i negativi veri contro i segnalati) e, come vedrai, si separano quando cambia il tasso base.
import numpy as np
from sklearn.metrics import confusion_matrix
rng = np.random.default_rng(7)
n = 10_000
y = (rng.random(n) < 0.02).astype(int) # circa il 2% di casi positivi
pred_pigra = np.zeros(n, dtype=int) # "non è mai frode"
tn, fp, fn, tp = confusion_matrix(y, pred_pigra).ravel()
print("accuratezza pigra:", (tn + tp) / n)
print("richiamo (recall):", tp / (tp + fn))
Come leggere il codice. y è la verità: un vettore di zeri e uni in cui circa il 2% dei valori è 1 (rng.random(n) < 0.02 produce vero con probabilità 0.02, e astype(int) lo trasforma in 1). pred_pigra è un modello che dice sempre 0. confusion_matrix(y, pred_pigra) restituisce la tabella 2×2 e .ravel() la appiattisce in quattro numeri nell'ordine tn, fp, fn, tp; poiché il modello non dice mai «positivo», tp e fp valgono zero e il richiamo tp/(tp+fn) è zero. L'accuratezza è semplicemente la frazione di zeri nel vettore y.
Output ottenuto: accuratezza 0.9784, richiamo 0.0. Un modello che non trova nulla, con quasi il 98% di accuratezza.
Un numero per capire quanto costa un errore. Se un mancato rilevamento costa 50 euro e un falso allarme 2 euro, un modello che segnala di più (richiamo alto, precisione bassa) può convenire anche se «sbaglia più spesso»: il costo atteso conta, non il numero di errori. Questa è la ragione per cui la soglia di decisione non si lascia al valore predefinito 0.5: si sceglie con i costi, come vedremo nella lezione 4.
Trade-off. Precisione e richiamo tirano in direzioni opposte: se segnali tutto, il richiamo sale a 1 e la precisione crolla; se segnali solo i casi certissimi, la precisione sale e il richiamo scende. Quale preferire dipende dal costo dei due errori (lezione 04): un esame di screening vuole alto richiamo (non perdere i malati), un filtro che blocca account vuole alta precisione (non bloccare gli innocenti).
Teoria: audit per gruppo e impossibilità di avere tutto
Perché la media nasconde
Un numero medio è una media pesata sui gruppi. Se un gruppo è piccolo, può stare male senza che la media se ne accorga. L'audit consiste nel calcolare le stesse metriche separatamente per ogni sottogruppo rilevante.
Tre criteri classici (nomi dalla letteratura):
- Parità demografica: il tasso di selezione
P(ŷ = 1)è uguale tra i gruppi. - Pari opportunità (Hardt, Price, Srebro 2016): il richiamo
P(ŷ = 1 | y = 1)è uguale tra i gruppi. Chi merita l'esito positivo ha la stessa probabilità di ottenerlo. - Parità predittiva: la precisione
P(y = 1 | ŷ = 1)è uguale tra i gruppi. "Un segnale vuol dire la stessa cosa in tutti i gruppi."
I tre criteri guardano punti diversi della matrice di confusione: il primo ignora la verità e conta solo chi viene selezionato, il secondo guarda chi merita, il terzo guarda chi è stato segnalato. Sono tutte richieste ragionevoli e ciascuna protegge una persona diversa; più avanti vedrai che non si possono soddisfare insieme quando i tassi base differiscono.
L'esperimento
Due gruppi, A e B. In B il fenomeno è più raro (tasso base 15% contro 40%) e lo strumento di misura è meno informativo (la separazione tra le classi è 0.8 contro 1.5). I dati sono simulati: servono a mostrare un meccanismo, non a descrivere un caso reale. Alleniamo un solo modello su tutti.
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
rng = np.random.default_rng(7)
def genera(n, gruppo, rng):
p = 0.40 if gruppo == "A" else 0.15 # tasso base
sep = 1.5 if gruppo == "A" else 0.8 # quanto il segnale distingue le classi
y = (rng.random(n) < p).astype(int)
x = rng.normal(0, 1, n) + sep * y
return x.reshape(-1, 1), y
XA, yA = genera(6000, "A", rng)
XB, yB = genera(2000, "B", rng)
X = np.vstack([XA, XB])
y = np.concatenate([yA, yB])
g = np.array(["A"] * len(yA) + ["B"] * len(yB))
modello = LogisticRegression().fit(X, y)
pred = modello.predict(X)
def metriche(y, p):
tn, fp, fn, tp = confusion_matrix(y, p, labels=[0, 1]).ravel()
return {
"accuratezza": (tp + tn) / len(y),
"tasso_selezione": (tp + fp) / len(y),
"TPR": tp / (tp + fn),
"FPR": fp / (fp + tn),
"PPV": tp / (tp + fp),
}
for nome in ("A", "B"):
m = metriche(y[g == nome], pred[g == nome])
print(nome, {k: round(float(v), 3) for k, v in m.items()})
Come leggere il codice. genera costruisce un gruppo: sceglie il tasso base p (la quota di positivi), estrae l'etichetta y e produce un unico segnale x che vale in media sep unità in più per i positivi che per i negativi (più sep è grande, più il segnale distingue le classi). Gruppo A è più numeroso (6000 esempi), con il fenomeno più frequente e un segnale migliore; gruppo B è piccolo e con segnale debole. Si addestra un solo modello su tutti (LogisticRegression, un modello che stima la probabilità della classe positiva e la trasforma in un verdetto con soglia 0.5) e si calcolano le metriche separatamente per gruppo con la funzione metriche, che legge le quattro caselle della matrice di confusione.
Output ottenuto (seed 7, scikit-learn 1.8):
| Gruppo | Accuratezza | Selezione | TPR (richiamo) | FPR | PPV (precisione) |
|---|---|---|---|---|---|
| A | 0.774 | 0.330 | 0.626 | 0.123 | 0.781 |
| B | 0.809 | 0.158 | 0.388 | 0.118 | 0.362 |
Leggilo con attenzione, perché è controintuitivo:
- Il gruppo B ha l'accuratezza più alta (0.809 contro 0.774).
- Ma nel gruppo B il modello trova solo il 39% dei casi positivi veri, contro il 63% di A. Una persona di B che meriterebbe l'esito positivo ha 24 punti percentuali in meno di probabilità di ottenerlo (0.388 contro 0.626).
- L'accuratezza di B è alta per lo stesso motivo del guardiano: i positivi sono rari (15%), quindi dire "no" quasi sempre è quasi sempre giusto.
- Il FPR è praticamente uguale (0.123 contro 0.118): se guardassi solo quello, concluderesti che il modello è equo.
Le quattro osservazioni contano in ordine inverso a quello in cui le leggi: l'uguaglianza del FPR è la più rassicurante e la più fuorviante, mentre il divario sul richiamo (0.626 contro 0.388, cioè circa 24 punti percentuali) è ciò che una persona di B subisce davvero. Nessuna singola metrica racconta la storia. Per questo si auditano più metriche, per gruppo. Per brevità qui le metriche sono calcolate sugli stessi dati dell'addestramento: con un modello a due parametri e ottomila esempi la differenza è piccola, ma in un audit vero si calcolano su dati tenuti da parte.
Esercizio 1
Lo stesso modello, due gruppi, due storie
Uno sportello smista automaticamente le candidature a un corso di formazione finanziato (scenario simulato, numeri scelti perché i conti vengano esatti). I candidati arrivano da due percorsi di studio, T e L. Il modello è uno solo, con una soglia sola, e produce lo stesso TPR (3/4) e lo stesso FPR (1/10) nei due gruppi: sulla carta, il massimo dell'imparzialità.
- T: 2000 candidature, il 40% ha davvero i requisiti.
- L: 1000 candidature, il 20% ha davvero i requisiti.
I due gruppi differiscono solo per dimensione e per tasso base, cioè per la quota di candidati idonei. È l'unica differenza, e l'esercizio serve a vedere quanto basta per far divergere precisione e accuratezza anche quando TPR e FPR coincidono.
- Ricostruisci le quattro caselle della matrice di confusione per ciascun gruppo.
- Calcola accuratezza e precisione (PPV) dei due gruppi. Quale gruppo ha l'accuratezza più alta?
- TPR e FPR sono identici. Perché la precisione no?
Conviene procedere in ordine: prima le otto caselle (quattro per gruppo), poi le due metriche, poi la spiegazione. Se la terza risposta ti sembra una sorpresa, torna all'identità che deriviamo più sotto: contiene già la risposta.
Mostra la soluzione
1. T: 800 idonei e 1200 non idonei; VP = 3/4 × 800 = 600, FN = 200, FP = 1/10 × 1200 = 120, TN = 1080. L: 200 idonei e 800 non idonei; VP = 150, FN = 50, FP = 80, TN = 720.
2. Accuratezza T: (600 + 1080)/2000 = 0.84. Accuratezza L: (150 + 720)/1000 = 0.87. Precisione T: 600/720 = 5/6 ≈ 0.833. Precisione L: 150/230 = 15/23 ≈ 0.652. L'accuratezza più alta ce l'ha L, che è il gruppo trattato peggio: fra i suoi selezionati solo due su tre hanno davvero i requisiti, contro cinque su sei in T.
3. Perché l'unica cosa che cambia è il tasso base, e basta quello. La precisione è VP/(VP+FP): il numeratore cresce con la quota di idonei del gruppo, il denominatore raccoglie anche i falsi positivi, che nascono dai non idonei — e in L i non idonei sono l'80% invece del 60%. Lo stesso FPR, applicato a una platea di negativi più grande, produce abbastanza falsi positivi da diluire i veri. L'accuratezza di L è alta per il motivo opposto e altrettanto vuoto: gli idonei sono pochi, quindi dire «no» quasi sempre è quasi sempre giusto. Un rapporto che riportasse la sola accuratezza per gruppo certificherebbe come equo esattamente il contrario.
Un secondo esempio, contrastante: il bias che entra dalla porta di servizio
Un errore comune: «togliamo la colonna gruppo dal modello e il problema scompare». Costruiamo un controesempio. Un gruppo minoritario (circa il 30% dei casi) ha, nei dati storici, un tasso di esito positivo più basso (le etichette incorporano una decisione ingiusta del passato). La competenza reale è identica nei due gruppi. Esiste anche una variabile, la «zona» di residenza, correlata con il gruppo. Confrontiamo tre modelli, con insiemi diversi di caratteristiche.
import numpy as np
from sklearn.linear_model import LogisticRegression
rng = np.random.default_rng(11)
n = 20_000
gruppo = (rng.random(n) < 0.3).astype(int) # 1 = gruppo minoritario
zona = gruppo * 1.2 + rng.normal(0, 1, n) # proxy: correlata con il gruppo
competenza = rng.normal(0, 1, n) # uguale nei due gruppi
# etichetta storica: dipende dalla competenza, ma anche (ingiustamente) dal gruppo
y = ((competenza - 0.8 * gruppo + rng.normal(0, 0.7, n)) > 0).astype(int)
print("correlazione zona-gruppo:", round(float(np.corrcoef(zona, gruppo)[0, 1]), 3))
print("tasso storico di esito positivo -> gruppo 0:", round(float(y[gruppo == 0].mean()), 3), "| gruppo 1:", round(float(y[gruppo == 1].mean()), 3))
insiemi = {
"solo competenza": np.column_stack([competenza]),
"competenza + zona (senza gruppo)": np.column_stack([competenza, zona]),
"competenza + zona + gruppo": np.column_stack([competenza, zona, gruppo]),
}
for nome, X in insiemi.items():
previsione = LogisticRegression().fit(X, y).predict(X)
tassi = [float(previsione[gruppo == g].mean()) for g in (0, 1)]
print(f"{nome:<34}: tasso di selezione gruppo 0 = {tassi[0]:.3f}, gruppo 1 = {tassi[1]:.3f}")
Output ottenuto:
correlazione zona-gruppo: 0.485
tasso storico di esito positivo -> gruppo 0: 0.494 | gruppo 1: 0.26
solo competenza : tasso di selezione gruppo 0 = 0.402, gruppo 1 = 0.407
competenza + zona (senza gruppo) : tasso di selezione gruppo 0 = 0.424, gruppo 1 = 0.359
competenza + zona + gruppo : tasso di selezione gruppo 0 = 0.490, gruppo 1 = 0.218
Come leggere il codice. y è costruita in modo che il gruppo minoritario sia svantaggiato nelle etichette storiche (il termine -0.8 * gruppo). Il primo modello vede solo la competenza, che è distribuita allo stesso modo nei due gruppi: seleziona quote praticamente uguali (circa 40% e 41%). Il secondo non riceve la colonna gruppo, ma riceve zona, che la riflette: il modello la usa per riprodurre il pattern delle etichette storiche, e la quota del gruppo 1 scende (circa 36% contro 42%). Il terzo, con anche la colonna gruppo, amplifica il gap (22% contro 49%). La lezione è precisa: togliere la colonna sensibile non basta se esistono proxy, e un modello addestrato su etichette distorte impara la distorsione se ne ha la possibilità. La contromisura non è un trucco di codice, è il processo: misurare l'esito per gruppo, interrogarsi sull'origine delle etichette, e togliere le variabili che servono solo a ricostruire il gruppo.
Intervenire sulla soglia: quanto costa riequilibrare
Una famiglia di rimedi agisce dopo l'addestramento: usare una soglia di decisione diversa per gruppo, scelta in modo da uguagliare il richiamo (la pari opportunità). Proviamolo sul modello della sezione precedente (stessi dati, stesso seme), cercando per il gruppo B la soglia che porta il suo richiamo al livello di A.
import numpy as np
from sklearn.linear_model import LogisticRegression
rng = np.random.default_rng(7)
def genera(n, p, sep):
y = (rng.random(n) < p).astype(int)
return (rng.normal(0, 1, n) + sep * y).reshape(-1, 1), y
XA, yA = genera(6000, 0.40, 1.5)
XB, yB = genera(2000, 0.15, 0.8)
modello = LogisticRegression().fit(np.vstack([XA, XB]), np.concatenate([yA, yB]))
pA, pB = modello.predict_proba(XA)[:, 1], modello.predict_proba(XB)[:, 1]
def metriche(y, p, soglia):
pred = p >= soglia
tp = int((pred & (y == 1)).sum()); fn = int((~pred & (y == 1)).sum())
fp = int((pred & (y == 0)).sum()); tn = int((~pred & (y == 0)).sum())
return tp / (tp + fn), fp / (fp + tn), tp / max(tp + fp, 1)
tpr_A = metriche(yA, pA, 0.5)[0]
for soglia_B in (0.5, 0.35, 0.25, 0.2, 0.15):
tpr, fpr, ppv = metriche(yB, pB, soglia_B)
print(f"soglia B = {soglia_B:.2f}: richiamo {tpr:.3f} (obiettivo {tpr_A:.3f}) | FPR {fpr:.3f} | precisione {ppv:.3f}")
Output ottenuto:
soglia B = 0.50: richiamo 0.388 (obiettivo 0.626) | FPR 0.118 | precisione 0.362
soglia B = 0.35: richiamo 0.527 (obiettivo 0.626) | FPR 0.230 | precisione 0.283
soglia B = 0.25: richiamo 0.673 (obiettivo 0.626) | FPR 0.346 | precisione 0.251
soglia B = 0.20: richiamo 0.728 (obiettivo 0.626) | FPR 0.433 | precisione 0.225
soglia B = 0.15: richiamo 0.816 (obiettivo 0.626) | FPR 0.539 | precisione 0.207
Come leggere il codice. predict_proba restituisce per ogni esempio la probabilità stimata della classe positiva; decidere «positivo» se supera una soglia è la regola di decisione, e cambiarla non richiede riaddestrare nulla. metriche calcola richiamo, tasso di falsi positivi e precisione per una data soglia. Al diminuire della soglia per il gruppo B il richiamo sale (si segnalano più casi) verso quello di A, ma il tasso di falsi positivi sale e la precisione scende: si paga in falsi allarmi. È l'identità della sezione precedente che si manifesta: con tassi base diversi, eguagliare il richiamo sposta le altre metriche. Con la soglia 0.25 il richiamo di B (0.673) raggiunge e supera quello di A (0.626), al prezzo di un tasso di falsi positivi di 0.346 e di una precisione di 0.251. Che sia accettabile dipende dal contesto: in una diagnosi precoce, qualche falso allarme per non mancare i casi veri può essere giusto; in un provvedimento punitivo, no.
Perché non si può sistemare tutto insieme: dimostrazione
Vorremmo un modello con TPR uguale, FPR uguale e PPV uguale tra i gruppi. Si può? Derivazione completa (Chouldechova 2017).
Sia p = P(y = 1) il tasso base del gruppo. Consideriamo una popolazione di N persone nel gruppo.
- Positivi veri:
N·p. Negativi veri:N·(1 − p). - Vero positivi:
VP = TPR · N·p. - Falsi positivi:
FP = FPR · N·(1 − p). - La precisione è
PPV = VP / (VP + FP). - Sostituisci:
PPV = TPR·p / ( TPR·p + FPR·(1 − p) ). - Moltiplica per il denominatore:
PPV·TPR·p + PPV·FPR·(1 − p) = TPR·p. - Isola il termine con FPR:
PPV·FPR·(1 − p) = TPR·p − PPV·TPR·p = TPR·p·(1 − PPV). - Quindi:
La derivazione usa solo due definizioni e un po' di algebra: i passi 1-3 contano le persone, il 4 e il 5 mettono la precisione in funzione di TPR, FPR e tasso base, dal 6 al 8 si isola il FPR. Il risultato qui sotto è un'identità, non un'approssimazione: vale per qualunque classificatore binario, perché dice come tre misure e il tasso base sono vincolati tra loro.
FPR = TPR · p · (1 − PPV) / ( PPV · (1 − p) )
L'identità lega le tre metriche al tasso base p. Ora il punto. Se due gruppi hanno stesso TPR e stesso PPV, ma tassi base diversi p_A ≠ p_B, allora il membro destro è diverso, quindi anche FPR è diverso (a meno dei casi degeneri PPV = 1 o TPR = 0). Non esiste un classificatore non banale che renda uguali TPR, FPR e PPV quando i tassi base differiscono. Kleinberg, Mullainathan e Raghavan (2017) dimostrano un risultato affine per i punteggi calibrati.
Verifica numerica sui nostri dati: l'identità deve tornare.
for nome in ("A", "B"):
yy, pp = y[g == nome], pred[g == nome]
m = metriche(yy, pp)
p = yy.mean()
fpr_formula = m["TPR"] * p * (1 - m["PPV"]) / (m["PPV"] * (1 - p))
print(nome, "FPR misurato", round(float(m["FPR"]), 4), "FPR da formula", round(float(fpr_formula), 4))
Output: A 0.1228 0.1228 e B 0.1178 0.1178. Coincidono: la formula è un'identità aritmetica, non un'approssimazione.
Conseguenza pratica. L'equità non è una proprietà che si "accende": è una scelta fra criteri incompatibili, e la scelta dipende dal contesto e dal danno. Decidere quale criterio proteggere è una decisione di prodotto e di governo, non un dettaglio tecnico, e va documentata.
Esercizio 2
Il prezzo della riparazione
Stesso sportello simulato dell'esercizio 1. La commissione decide: la precisione del gruppo L deve salire al livello di T (5/6), e per ottenerlo si alza la soglia del solo gruppo L. Il richiamo resta 3/4; cambia soltanto il FPR.
- Partendo dall'identità
PPV = TPR·p / (TPR·p + FPR·(1−p))derivata qui sopra, ricava il FPR necessario. Equazione di primo grado, niente tentativi. - Quanti falsi positivi restano in L? Quanti candidati vengono selezionati in tutto?
- Confronta la quota di selezionati dei due gruppi prima e dopo. La riparazione ha migliorato l'equità?
Il primo punto è puramente algebrico, il secondo è un conteggio, il terzo è un giudizio: la risposta dipende da quale criterio decidi di proteggere. Ricorda che le soluzioni usano numeri scelti perché i conti vengano esatti, non dati reali.
Mostra la soluzione
1. Isolando il FPR: FPR = TPR·p·(1 − PPV) / (PPV·(1 − p)). Con TPR = 3/4, p = 1/5, PPV = 5/6: FPR = (3/4 · 1/5 · 1/6) / (5/6 · 4/5) = (1/40)/(2/3) = 3/80 = 0.0375. Contro il 10% attuale, poco più di un terzo.
2. FP = 3/80 × 800 = 30, contro gli 80 di prima. I selezionati di L passano da 150 + 80 = 230 a 150 + 30 = 180.
3. No, non secondo tutte le definizioni. La quota di selezionati di L scende da 230/1000 = 0.23 a 180/1000 = 0.18, mentre T resta a 720/2000 = 0.36: il divario di accesso passa da 13 a 18 punti. La precisione è stata pareggiata togliendo 50 posti al gruppo che ne aveva già di meno. È l'impossibilità di Chouldechova vista da dentro: con tassi base diversi ogni correzione sposta il problema su un'altra colonna, e nessuna formula dice quale colonna conti di più. Quella decisione dipende da chi paga l'errore: se il danno grosso è escludere una persona idonea si guarda il TPR; se è dare un posto a chi non ne ha i requisiti, il PPV.
Il quadro normativo e di governo (mappa essenziale)
Non è consulenza legale: è la mappa per sapere dove guardare. I testi sono fonti ufficiali dell'Unione europea.
| Strumento | Cosa dice, in sintesi | Dove ti tocca |
|---|---|---|
| GDPR, Reg. (UE) 2016/679 | Art. 5: principi (liceità, minimizzazione dei dati, limitazione della finalità, esattezza). Art. 22: diritto a non essere sottoposti a decisioni basate unicamente sul trattamento automatizzato che producano effetti giuridici o incidano in modo analogo, con le eccezioni previste | Ogni dataset con dati personali; ogni decisione automatica su persone |
| AI Act, Reg. (UE) 2024/1689 | Approccio basato sul rischio: pratiche vietate, sistemi ad alto rischio con obblighi (gestione del rischio, qualità dei dati, documentazione, sorveglianza umana), obblighi di trasparenza per alcuni sistemi | Se il tuo sistema ricade in una categoria ad alto rischio, hai obblighi di processo, non solo di prestazione |
| NIST AI RMF 1.0 (2023) | Quadro volontario organizzato in quattro funzioni: Govern, Map, Measure, Manage | Come strutturare un processo interno di gestione del rischio |
Verifica sempre il testo vigente e le date di applicazione sul sito ufficiale (EUR-Lex per i regolamenti, nist.gov per il framework): l'applicazione dell'AI Act è graduale, e le scadenze possono essere aggiornate. In questa lezione non le riporto proprio per questo motivo.
Il ponte con quanto visto sopra. "Misurare" (funzione Measure del NIST RMF) è esattamente ciò che abbiamo fatto: scomporre le metriche per gruppo, e dichiarare quale criterio di equità si protegge.
Un vocabolario minimo
- Matrice di confusione: tabella 2×2 di previsioni contro verità.
- Accuratezza, precisione, richiamo, FPR: le quattro misure derivate (definizioni nel testo).
- Tasso base: la frequenza del fenomeno nella popolazione (
p). - Audit per gruppo: le stesse metriche calcolate separatamente per sottogruppo.
- Proxy: variabile che, pur non essendo sensibile, ne riflette un'altra.
- Soglia di decisione: valore di probabilità sopra il quale si dice «positivo».
- Model card: scheda che documenta scopo, dati e limiti di un modello.
Le sette voci si leggono in due gruppi: le prime tre sono misure (matrice, metriche, tasso base) e le ultime quattro sono pratiche o fenomeni (audit, proxy, soglia, scheda). Quando ti trovi a discutere di equità con chi non ha letto la lezione, parti dalla matrice di confusione: da lì si ricostruisce tutto il resto.
Errori tipici
| Errore | Sintomo | Causa | Prevenzione |
|---|---|---|---|
| Riportare solo l'accuratezza | Numero eccellente, utilità nulla | Classi sbilanciate | Matrice di confusione, precisione, richiamo, baseline |
| Auditare solo l'aggregato | "Funziona per tutti" smentito dal caso reale | La media nasconde i sottogruppi | Metriche per ogni gruppo rilevante |
| Eliminare la colonna sensibile e dichiararsi equi | Il bias resta | Altre variabili correlate (proxy) la ricostruiscono | Misurare l'esito per gruppo, non solo togliere la colonna |
| Cercare "il" modello equo | Tempo perso | I criteri sono incompatibili (dimostrazione sopra) | Scegliere e documentare il criterio prioritario |
| Dimenticare la finalità dei dati | Problema di conformità | Dati raccolti per uno scopo e riusati per un altro | Registro dei trattamenti, base giuridica verificata |
Best practice
- Scheda del modello (model card): scopo, dati di training, metriche per gruppo, limiti noti.
- Scheda del dataset: provenienza, finalità, periodo, lacune note.
- Soglia scelta con il costo degli errori, non lasciata al default 0.5.
- Revisione umana dove l'errore è grave o irreversibile.
- Monitoraggio nel tempo delle metriche per gruppo, non solo dell'aggregato.
- Registro delle decisioni: quale criterio di equità, perché, chi l'ha approvato.
Le prime due schede sono documenti, la terza è una regola di costo, le ultime tre sono processi continuativi. Nessuna richiede un'infrastruttura speciale: servono disciplina e un responsabile con nome, che è esattamente la risposta alla domanda sulla responsabilità posta all'inizio della lezione.
Mini-progetto
Prendi il codice della sezione sull'audit per gruppo e:
- Aggiungi un terzo gruppo C (tasso base 0.25, separazione 1.1, 1500 esempi) e ripeti l'audit.
- Calcola la differenza massima di TPR tra i gruppi (la violazione di pari opportunità).
- Prova a ridurla scegliendo una soglia diversa per gruppo (
modello.predict_proba). Cosa succede al FPR e alla precisione? Verifica con l'identità di Chouldechova che il risultato è coerente. - Scrivi la mini scheda del modello (8-10 righe) con la scelta del criterio e la motivazione.
I quattro passi vanno dal calcolo alla decisione: i primi due estendono l'audit a un gruppo in più e misurano la violazione di pari opportunità, il terzo ne mostra il prezzo, il quarto ti obbliga a mettere per iscritto la scelta. Se rimane tempo per un solo passo, fai il terzo: è quello che trasforma una formula in un compromesso.
Challenge
- Easy. Calcola a mano la matrice di confusione per 10 previsioni inventate e verifica con
confusion_matrix. - Medium. Disegna la curva precisione-richiamo variando la soglia di decisione sul gruppo B.
- Hard. Ripeti l'esperimento con tassi base uguali (0.3 e 0.3) ma separazioni diverse: il gap di richiamo resta? Cosa implica l'identità?
- Expert. Dimostra che con
TPR = 1eFPR = 0(classificatore perfetto) tutti i criteri coincidono, qualunque sia il tasso base. - Enterprise. Scrivi una procedura di audit trimestrale: quali gruppi, quali metriche, quale soglia di allarme, chi decide.
Le cinque sfide partono dal calcolo a mano e arrivano al processo aziendale. Hard e Expert sono le più istruttive: la prima isola l'effetto dell'informatività del segnale dal tasso base, la seconda mostra perché il classificatore perfetto è l'unico caso in cui l'incompatibilità sparisce.
Codice di questa lezione
I due esercizi qui sopra, con il programma che ricalcola ogni casella e ogni metrica in frazioni esatte, prima e dopo la riparazione. In appendice una trappola che negli audit veri fa danni: un gruppo senza selezionati rende la precisione 0/0, e il nan si propaga nella media di colonna in silenzio. Richiede Python 3.12+ e NumPy 2.3.
Eseguilo con python3 esercizi.py: gira anche con le parti non completate e ti dice quali mancano; il file è nella cartella di download del sito.
Recap
Mappa mentale. Matrice di confusione → quattro metriche (accuratezza, TPR, FPR, PPV). Audit = stesse metriche per sottogruppo. Identità FPR = TPR·p·(1−PPV)/(PPV·(1−p)) → con tassi base diversi, non si uguagliano tutte le metriche. Governo: GDPR, AI Act, NIST RMF.
3 concetti: matrice di confusione; audit per gruppo; incompatibilità dei criteri. 3 errori: accuratezza sola; media come verità; "togliere la colonna" come cura. 3 best practice: scheda del modello; soglia dal costo degli errori; monitoraggio per gruppo. 1 esercizio: il mini-progetto di questa lezione.
Prossima lezione: come trasformare un problema di business in un problema di dati, e come scegliere la soglia con i costi reali.
Nella stessa serie trovi anche: 02 - Dal modello all'agente (la lezione precedente), 04 - Implementare l'IA in azienda (la lezione successiva).
Fonti
- Regolamento (UE) 2016/679 (GDPR), EUR-Lex - l'articolo 22 (diritto a non essere sottoposti a una decisione basata unicamente sul trattamento automatizzato che produca effetti giuridici o incida in modo analogo) e i principi dell'articolo 5, consultata il 2026-11-12
- Regolamento (UE) 2024/1689 (AI Act), EUR-Lex - il titolo, la data (13 giugno 2024) e le regole sui sistemi di IA ad alto rischio; le date di applicazione non sono riportate nell'articolo perché sono graduali, consultata il 2026-11-12
- NIST AI 100-1, Artificial Intelligence Risk Management Framework (AI RMF 1.0) - le quattro funzioni GOVERN, MAP, MEASURE, MANAGE (lette nel PDF); la pagina NIST AI RMF dichiara l'uso volontario, la data del 26 gennaio 2023 e che la versione 1.0 è in revisione, consultate il 2026-11-12
- Hardt, Price, Srebro: Equality of Opportunity in Supervised Learning (arXiv:1610.02413) - il criterio di pari opportunità, consultata il 2026-11-12
- Chouldechova: Fair prediction with disparate impact (arXiv:1703.00056) - la relazione tra FPR, TPR, PPV e tasso base, consultata il 2026-11-12
- Kleinberg, Mullainathan, Raghavan: Inherent Trade-Offs in the Fair Determination of Risk Scores (arXiv:1609.05807) - l'incompatibilità dei criteri per i punteggi calibrati, consultata il 2026-11-12
- scikit-learn: confusion_matrix - la convenzione righe = classe vera, colonne = classe prevista e l'estrazione
tn, fp, fn, tpconravel(), consultata il 2026-11-12
I listati Python sono stati eseguiti due volte, con seme fisso, con Python 3.14.4, NumPy 2.3.5 e scikit-learn 1.8.0, e le uscite coincidono. L'ultimo listato (verifica dell'identità) usa le variabili del listato dell'audit per gruppo e va eseguito di seguito a quello. Tutti i dati sono simulati. L'articolo non è consulenza legale e non riporta le scadenze dell'AI Act.
Commenti
Caricamento commenti...
Accedi per commentare