Quale miglioramento stiamo premiando?
Un classificatore di documenti aziendali passa dal 92,3% al 96,5% di risposte corrette. Sembra un aggiornamento facile da approvare. Eppure la seconda versione non riconosce più nessun documento della categoria meno frequente. Non è una contraddizione: la maggioranza dei casi può migliorare abbastanza da compensare numericamente la scomparsa di una classe. Vogliamo capire come leggere questo risultato e quale domanda deve risolvere ogni metrica. I dati sono costruiti per l’analisi, non provengono da clienti o prodotti EL-AI.
Consideriamo classificazione a etichetta singola: ogni documento appartiene a una sola delle tre classi A, B, C e il sistema ne predice una. Il test rimane identico per entrambe le versioni: 900 casi A, 90 B, 10 C, mille in tutto. Il supporto è il numero di casi reali di una classe, non il numero di volte in cui il modello la propone. Non discutiamo qui la scelta delle soglie né la qualità di probabilità predette: confrontiamo decisioni già prese, per isolare l’effetto dell’aggregazione.
La matrice racconta ciò che la percentuale nasconde
Nelle matrici seguenti le righe indicano la classe reale e le colonne quella predetta. La diagonale conta le risposte corrette. La prima riga del modello A significa 850 casi A riconosciuti, 45 scambiati per B e 5 per C. La versione B riconosce 895 casi A, ma tutti i dieci C finiscono in A. Il totale corretto cresce da 850+65+8=923 a 895+70+0=965. L’accuratezza divide questi totali per mille; pesa ogni documento allo stesso modo e non promette di proteggere ogni classe.
| Versione / reale | A | B | C |
|---|---|---|---|
| A / A | 850 | 45 | 5 |
| A / B | 20 | 65 | 5 |
| A / C | 0 | 2 | 8 |
| B / A | 895 | 5 | 0 |
| B / B | 20 | 70 | 0 |
| B / C | 10 | 0 | 0 |
Una classe alla volta: precisione, richiamo e F1
Per una classe c separiamo veri positivi TP, falsi positivi FP e falsi negativi FN. TP sta sulla diagonale; FP arriva dalle altre righe della colonna c; FN dalle altre colonne della riga c. La precisione TP/(TP+FP) chiede quante proposte della classe siano giuste. Il richiamo TP/(TP+FN) chiede quanti casi reali della classe vengano trovati. Sono domande diverse: fare poche proposte può rendere alta la precisione lasciando molti casi non riconosciuti.
F1 è la media armonica di precisione e richiamo, ma per calcolarlo senza denominatori intermedi usiamo 2TP/(2TP+FP+FN). Per C nel modello A abbiamo TP=8, FP=10, FN=2: F1=16/28≈0,571429, precisione 8/18 e richiamo 8/10=0,8. Nel modello B TP=0, FP=0, FN=10: F1=0 e richiamo zero. La precisione non è definita perché non esistono proposte C; questo non rende indefinito F1, il cui denominatore vale dieci. Una convenzione software sulla divisione per zero non deve nascondere la perdita di copertura.
Tre aggregazioni, tre domande
Macro-F1 calcola prima F1 per ciascuna delle K classi e poi la media aritmetica: ogni classe pesa 1/K. Per A la terna è circa (0,960452;0,643564;0,571429), media 0,725148. Per B è (0,980822;0,848485;0), media 0,609769. Non è la media armonica della precisione media e del richiamo medio: l’ordine delle operazioni conta, perché F1 non è lineare. La versione B migliora due classi ma perde integralmente la terza, e macro lo rende visibile.
La media pesata usa invece i supporti 0,90, 0,09 e 0,01: vale circa 0,928042 per A e 0,959103 per B. Non contraddice macro; risponde a una domanda diversa, dando alla classe rara solo l’1% del peso. Micro somma TP, FP e FN prima del rapporto. In questa classificazione singola completa, ogni errore aggiunge un FP e un FN: se i corretti sono T, micro-F1=2T/[2T+2(N−T)]=T/N, proprio l’accuratezza. Questa equivalenza non va trasferita automaticamente a problemi multietichetta o a sottoinsiemi di classi.
| Metrica | A | B |
|---|---|---|
| accuracy / micro | 0.923 | 0.965 |
| macro-F1 | 0.725148 | 0.609769 |
| weighted-F1 | 0.928042 | 0.959103 |
| recall C | 0.8 | 0 |

Nemmeno macro decide al posto nostro
Un peso uguale per classe non significa costo uguale degli errori. Se la classe rara è marginale, macro può darle più importanza di quanto richieda il servizio; se segnala un evento critico, persino quel peso può essere insufficiente. Inoltre dieci casi C sostengono una stima molto meno stabile di novecento A. Il grafico è un conteggio esatto di questo dataset, non una prova statistica di superiorità futura. Servono set indipendenti, supporti dichiarati, incertezza e criteri di accettazione per classe fissati prima della selezione.
Il codice legge la matrice, calcola le somme di righe e colonne e ricostruisce ogni rapporto; l’archivio conserva entrambe le versioni e le asserzioni sul paradosso. Non abbiamo eseguito scikit-learn: ne abbiamo consultato definizioni e convenzioni, implementando i conteggi direttamente in Python. Il costo dei conteggi su una matrice K×K è proporzionale a K²; su N etichette si può costruirla in un passaggio. Nessun tempo di esecuzione viene presentato come benchmark del servizio.
Che cosa cambia se un errore costa di più?
Assegniamo un costo sintetico di 100 unità a ogni errore su un vero caso C e di una unità agli altri errori; le risposte corrette costano zero. Non sono costi aziendali misurati. A sbaglia 50 casi A, 25 B e 2 C: costo 50+25+2·100=275. B sbaglia 5 A, 20 B e 10 C: costo 5+20+10·100=1025. Su mille documenti otteniamo 0,275 contro 1,025 unità per documento, come verifica lo script. La versione con accuratezza maggiore risulta peggiore rispetto a questa funzione di costo.
Il costo medio è la somma di ciascun conteggio di errore moltiplicato per il costo relativo, divisa per N. Macro-F1 non stima questo costo: i due criteri preferiscono entrambi A soltanto in questo esempio e per ragioni diverse. Se ogni errore costasse uno, il costo medio sarebbe 1−accuratezza e preferirebbe B. La scelta richiede dunque un obiettivo operativo, non una metrica presentata come sempre superiore. Anche duplicando ogni documento, i rapporti resterebbero identici: il punteggio da solo non racconta quante prove indipendenti abbiamo.
Migliore per chi, e su quali casi?
La seconda versione è migliore per accuratezza e media pesata, peggiore per macro e incapace di riconoscere C in questo test. Tutte queste frasi possono essere vere insieme. Per valutare un modello verticale non basta scegliere il numero più alto: bisogna esplicitare popolazione, classi, costi e copertura richiesta, poi leggere insieme matrice, supporti e indicatori. La domanda iniziale trova così una risposta concreta: il totale può crescere proprio mentre il servizio perde una capacità che ci interessa conservare.
Fonti e calcoli
scikit-learn 1.9.1 — F1, averaging and undefined cases.
scikit-learn — multiclass aggregation definitions.
m=[[895,5,0],[20,70,0],[10,0,0]]
f=[];N=sum(map(sum,m))
for c in range(3):
tp=m[c][c];fp=sum(row[c] for row in m)-tp;fn=sum(m[c])-tp
f.append(2*tp/(2*tp+fp+fn))
print('accuracy',sum(m[c][c] for c in range(3))/N)
print('per-class F1',f,'macro',sum(f)/3)
assert f[2]==0
Codice, dati e istruzioni · JSON. Calcoli didattici eseguiti con Python 3.14.0; figure con Matplotlib 3.11.2. Analisi con assistenza AI, senza dichiarare peer review o revisione umana. Copertina originale ImageGen, illustrativa: non documenta persone, sedi o installazioni EL-AI. Fonti consultate il 24 ottobre 2026.

