Concetti e tecniche di Data Science in Python

A cura di Andrea D'Agostino

Valutazione delle performance di un modello di regressione

Valutazione delle performance di un modello di regressione

La fase di valutazione del modello inizia quando creiamo un set di validazione che consiste in esempi che l'algoritmo di apprendimento non ha visto durante l'addestramento. Se il nostro modello si comporta bene su questo set allora possiamo dire che generalizza bene ed è di buona qualità.

Il modo più comune per valutare se un modello è valido o meno è calcolare una metrica di performance proprio sul set di validazione o di test.

Questo articolo si concentrerà sulle metriche di performance per i modelli di regressione. Vale la pena specificarlo perché task di classificazione hanno metriche tracciabili completamente diverse.

Metriche di Performance per la Regressione

Parleremo di errore al quadratico medio (Mean Square Error, MSE), errore assoluto medio (Mean Absolute Error, MAE), errore assoluto mediano (Median Absolute Error, MdAE), il tasso di errore delle previsioni quasi corrette (Almost Correct Predictions Error Rate, ACPER), l'errore percentuale assoluto medio (Mean Absolute Percentage Error, MAPE) e lo scarto quadratico medio (Root Mean Square Error, RMSE). A mio avviso queste sono le metriche più utili per un modello di regressione.

Inizieremo con MSE, che è abbastanza facile da capire.

Errore quadratico medio (Mean Square Error, MSE)

La metrica più comune è la funzione di costo della regressione: l'errore quadratico medio (MSE). È definito come

dove f è il modello che prende un vettore di feature x come input e genera una previsione y. i, che va da 1 a N, denota l'indice di un punto nel set di dati. La somma delle previsioni meno i valori reali su N indica la media. Elevando al quadrato rimuoviamo il segno negativo e diamo più peso a differenze maggiori.

Un modello di regressione tenta di adattare i dati tracciando una linea che riduce al minimo la distanza dai punti dati reali e dal punto sulla stessa linea. Più i valori sono vicini alla linea, migliore è il comportamento del modello per quel particolare punto. Pertanto, più basso è l'MSE, meglio è.

La metrica MSE viene solitamente confrontata con un modello di baseline che solitamente è un modello di regressione basato sulla media. Questo modello restituisce sempre la media dei valori dei dati di addestramento. Se l'MSE del nostro modello di regressione è maggiore dell'MSE della baseline, allora c'è qualcosa che non va, come ad esempio un errore nel dataset o un bug.

L'MSE è influenzato da valori anomali (outliers), ovvero valori di dati che sono anormalmente distanti dalla vera retta di regressione. Per definizione, l'errore al quadrato per punti così distanti sarà molto alto. In queste situazioni, è meglio applicare il MdAE che sta per Median Absolute Error (che vedremo in basso).

Ecco come implementare MSE in Python

def mean_squared_error(y_true, y_pred):
    """
    Funzione che calcola MSE.
    :param y_true: lista di numeri che rappresentano i valori reali
    :param y_pred: lista di numeri che rappresentano i valori predetti
    :restituisce: MSE
    """
    return np.mean(np.abs(np.array(y_pred) - np.array(y_true))**2, axis=0)

Errore assoluto medio (Mean Absolute Error, MAE)

MAE è simile a MSE in quanto restituisce i valori assoluti dei residui f(x) - y senza l'elevazione al quadrato. Non considera la direzione dell'errore, il che significa che non sapremo se gli errori negativi o positivi pesano di più sulla media complessiva. Detto questo, MAE è più robusto ai valori anomali proprio grazie all'assenza dell'elevazione al quadrato dei valori degli errori di previsioni lontane.

Ecco come implementare MAE in Python

def mean_absolute_error(y_true, y_pred):
    """
    Funzione che calcola MAE.
    :param y_true: lista di numeri che rappresentano i valori reali
    :param y_pred: lista di numeri che rappresentano i valori predetti
    :restituisce: MAE
    """
    return np.mean(np.abs(np.array(y_pred) - np.array(y_true)), axis=0)

Errore assoluto mediano (Median Absolute Error, MdAE)

La mediana, come sappiamo dalle basi della statistica, non è influenzata da valori anomali come lo è la media. Il MdAE indica la distanza assoluta delle previsioni dalla retta di regressione mediana.

dove \( |f(x_i) — y_i| \) indica l'insieme dei valori di errore assoluti per tutti i punti su cui viene eseguita la valutazione del modello.

Se sono presenti valori anomali e non trattati conviene utilizzare MdAE invece di MSE o MAE, poiché fornisce una migliore rappresentazione dell'errore per i punti che non sono così distanti dalla retta di regressione.

Ecco come implementare MdAE in Python

def median_absolute_error(y_true, y_pred):
    """
    Funzione che calcola MdAE.
    :param y_true: lista di numeri che rappresentano i valori reali
    :param y_pred: lista di numeri che rappresentano i valori predetti
    :restituisce: MdAE
    """
    return np.median(np.abs(np.array(y_pred) - np.array(y_true)), axis=0)

Tasso di errore delle previsioni quasi corrette (Almost Correct Predictions Error Rate, ACPER)

L'ACPER è la percentuale di previsioni che è distante p valori percentuali del valore reale. Si tratta di impostare un intervallo arbitrario e calcolare quanti punti predetti ricadono in tale intervallo.

Ecco un semplice algoritmo per calcolare l'ACPER:

  1. definisci una soglia percentuale di errore che ritieni accettabile (diciamo 2%)
  2. Per ogni valore vero del target y, la previsione desiderata dovrebbe essere compresa tra \( y_i - 0.02 \times y_i \) e \(y_i+0.02 \times y_i \)
  3. utilizzando tutti i punti, calcolare la percentuale di valori predetti che soddisfano la regola di cui sopra. Questo ci darà l'ACPER per il nostro modello.

Ecco come implementare ACPER in Python

def acper(y_true, y_pred):
    """
    Funzione che calcola ACPER.
    :param y_true: lista di numeri che rappresentano i valori reali
    :param y_pred: lista di numeri che rappresentano i valori predetti
    :restituisce: punteggio ACPER
    """
    threshold = 0.02
    for yt, yp in zip(y_true, y_pred):
        lower_bound = yt - (threshold * yt)
        upper_bound = yt + (threshold * yt)
        if (yp >= lower_bound) & (yp <= upper_bound):
          yield True
        else:
          yield False
          
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2.01, 8]

list(acper(y_true, y_pred))

Risultato: [Falso, Falso, Vero, Falso]. Possiamo semplicemente contare il numero di valori True e dividerlo per la lunghezza della lista per ottenere una percentuale.

Errore percentuale assoluto medio (Mean Absolute Percentage Error, MAPE)

L'errore percentuale medio assoluto (MAPE) misura l'errore in percentuale e può essere calcolato applicando una leggera modifica al MAE e moltiplicandolo per 100 per ottenere un punteggio percentuale. È una delle metriche più utili e utilizzate per la valutazione del modello di regressione.

Supponiamo che MAPE per il nostro modello sia del 5%: ciò indicherebbe che la differenza media tra il valore previsto e il valore osservato è in media del 5%. Comodo e interpretabile, giusto?

Come MAE, soffre della presenza di valori anomali, quindi dobbiamo assicurarci di trattarli in modo appropriato.

Ecco come implementare MAPE in Python

def mean_absolute_percentage_error(y_true, y_pred):
    """
    Funzione che calcola MAPE.
    :param y_true: lista di numeri che rappresentano i valori reali
    :param y_pred: lista di numeri che rappresentano i valori predetti
    :restituisce: punteggio MAPE
    """
    return np.mean(np.abs(np.array(y_pred) - np.array(y_true)) / np.array(y_true), axis=0)

Scarto quadratico medio (Root Mean Square Error, RMSE)

Lo scarto quadratico medio è una misura dell'errore assoluto in cui gli errori sono al quadrato per evitare che valori positivi e negativi si annullino a vicenda (proprio come MSE). Rappresenta la deviazione standard dei residui.

Il termine residuo si riferisce alla distanza tra il punto previsto e il punto osservato. Essendo la deviazione standard, indica quanto sono distribuiti i residui attorno alla nostra linea di regressione.

Citando un collega su Medium

RMSE can be thought of as some kind of (normalized) distance between the vector of predicted values and the vector of observed values.

RMSE può essere considerato come una sorta di distanza (normalizzata) tra il vettore dei valori previsti e il vettore dei valori osservati.

L'implementazione è molto semplice, poiché si tratta solo di applicare np.sqrt al nostro calcolo MSE visto sopra.

Usate pure il codice presente in questo post per implementare le metriche di performance in Python puro, con l'ausilio di NumPy. Tenete presente però che c'è un'API dedicata di Scikit-Learn che ci semplifica la vita.

Andrea D'Agostino
Data scientist con 6 anni di esperienza nell'applicare tecniche di data science per aiutare i clienti a risolvere problemi nei loro asset e a sfruttare le debolezze dei competitor a loro vantaggio.