V úvodním příkladu s krajinou jsme si metriku vymýšleli sami. Existuje samozřejmě řada standardním metrik, které se k hodnocení modelů používají. Uvedeme si přehled nejnámějších z nich:
($y = y_1, \ldots, y_N$ jsou reálné hodnoty odezvy, $\hat{y} = \hat{y}_1, \ldots, \hat{y}_N$ jsou predikované hodnoty)
MAE (Mean absolute error) - průměr absolutních hodnot odchylek požadovaných výstupů od predikovaných výstupů
$$ MAE(y, \hat{y}) = \frac{1}{N} \sum_{i=1}^N |y_i - \hat{y}_i| $$
MSE (Mean squared error) - průměr sumy čterců odchylek požadovaných výstupů od predikovaných výstupů
$$ MSE(y, \hat{y}) = \frac{1}{N} \sum_{i=1}^N (y_i - \hat{y}_i)^2 $$
$R^2$ score (Koeficient determinace) - koeficient determinace vyjadřuje, jaký podíl variability závislé proměnné (odezvy) model vyjadřuje. Dá se interpretovat tak, že říká, jak moc je náš model lepší než konstantní baseline daná jako průměr. $$ R^2(y, \hat{y}) = 1 - \frac{MSE(model)}{MSE(baseline)} = 1 - \frac{MSE(y, \hat{y})}{MSE(y, \bar{y})}; \qquad \mbox{kde}\quad \bar{y} = \frac{1}{N} \sum_{i=1}^N y_i $$ $R^2$ skóre dosahuje maximálně hodnoty jedna, což znamená dokonalou predikci.
Pokud nemáš ráda vzorečky, nelam si s nimi hlavu. Podívej se na následující příklad:
Vytvoříme dataframe, který bude obsahovat odezvy (sloupec "správně") a predikované hodnoty (sloupec "predikováno"). Pro jednoduchost hodnoty odezvy vygenerujeme náhodně a jejich "predikce" vytvoříme tak, že k těmto odezvám přičteme náhodné číslo z intervalu (-10, 10).
import pandas as pd
import random
df = pd.DataFrame({"správně": [random.randint(10, 90) for _ in range(10)]})
df["predikováno"] = df["správně"].apply(lambda predikovano: predikovano + random.randint(-10, 10))
df
Spočteme si MSE, MAE a $R^2$ skóre. Napišme si na to funkci:
def spocti_metriky(skutecna_odezva, predikovano):
chyby = pd.DataFrame()
chyby["absolutní_chyba"] = abs(skutecna_odezva - predikovano)
chyby["chyba_na_druhou"] = (skutecna_odezva - predikovano)**2
baseline = skutecna_odezva.mean()
chyby["chyba_na_druhou_baseline"] = (skutecna_odezva - baseline)**2
MSE = chyby["chyba_na_druhou"].mean()
MAE = chyby["absolutní_chyba"].mean()
R2 = 1 - MSE/chyby["chyba_na_druhou_baseline"].mean()
return chyby, MSE, MAE, R2
df_chyby, MSE, MAE, R2 = spocti_metriky(df["správně"], df["predikováno"])
# zobrazme si tabulku spolu s odpovídajícími chybami
pd.concat([df, df_chyby], axis="columns")
# vypišme si hodnoty metrik
print(f"MSE = {MSE}")
print(f"MAE = {MAE}")
print(f"R2 = {R2}")
Z tabulky výše i ze zobrazených chyb vidíme, že MSE daleko více penalizuje větší chyby.
Zkusme si ještě nasimulovat řešení, které bude poměrně přesné (náhodná odchylka, kterou přičítáme, bude z intervalu (-1,1)).
df2 = pd.DataFrame()
df2["správně"] = df["správně"]
df2["predikováno"] = df2["správně"].apply(lambda predikovano: predikovano + random.uniform(-1., 1.))
df2
Opět zorbrazme chyby:
df2_chyby, MSE_2, MAE_2, R2_2 = spocti_metriky(df2["správně"], df2["predikováno"])
pd.concat([df2, df2_chyby], axis="columns")
A vypišme si hodnoty metrik:
print(f"MSE = {MSE_2:.3f} (minule: {MSE})") # :.2f znamená float na dvě desetinná místa
print(f"MAE = {MAE_2:.3f} (minule: {MAE})")
print(f"R2 = {R2_2:.3f} (minule: {R2})")
Vidíme, že hodnoty MSE a MAE jsou teď výrazně menší než minule. To je proto, že "predikované" hodnoty jsou velmi blízko hodnotám skutečným. $R^2$ skóre vyšlo naopak vyšší (blíže jedné).
Pozn.: Pozor, nyní vyšla hodnota MAE vyšší než MSE, to je proto, že jednotlivé chyby jsou teď menší než jedna (mocnina je menší než absolutní hodnota).