Ga naar hoofdinhoud

Leerhandleiding voor leercurves: wat zijn leercurves?

Ontdek hoe leercurves je kunnen helpen je data te evalueren en optimale oplossingen te vinden.
· 15 min lezen

Verken met AI

Er zijn twee belangrijke oorzaken van fouten in machine learning-modellen:

  • Bias beschrijft een model dat vereenvoudigde aannames maakt zodat de doelfunctie makkelijker te benaderen is; een model kan bijvoorbeeld leren dat elke man van 1,75 m ter wereld maat M draagt – dat is duidelijk bevooroordeeld.
  • Variantie beschrijft de variabiliteit in de modelvoorspelling; hoeveel de voorspelling van het model verandert wanneer we de data veranderen waarmee het is getraind.

Om tot een nauwkeurigere oplossing te komen, willen we de hoeveelheid bias en variantie in ons model verminderen. Dat is niet eenvoudig. Bias en variantie staan op gespannen voet met elkaar – het verlagen van de ene verhoogt de andere, vanwege het concept dat bekendstaat als de bias-variantie-afweging.

In dit artikel leer je:

  • Hoe je ontdekt of een model last heeft van hoge bias of hoge variantie
  • Hoe je een model diagnosticeert dat aan een van beide symptomen lijdt
  • Hoe je een model met een goede fit bouwt

Voordat we de fouten gaan opsporen, gaan we eerst dieper in op de bias-variantie-afweging.

Een blik op de bias-variantie-afweging

Alle supervised learning-algoritmen streven hetzelfde doel na: het schatten van de afbeeldingsfunctie (f_hat) voor een doelvariabele (y) gegeven wat invoerdata (X). De functie die een machine learning-model probeert te benaderen noemen we de doelfunctie.

Het veranderen van de invoerdata die wordt gebruikt om de doelvariabele te benaderen zal waarschijnlijk resulteren in een andere doelfunctie, wat invloed kan hebben op de uitkomsten die door het model worden voorspeld. Hoeveel onze doelfunctie varieert wanneer de trainingsdata verandert, staat bekend als de variantie. We willen niet dat ons model een hoge variantie heeft, want hoewel ons algoritme tijdens training foutloos kan presteren, generaliseert het dan slecht naar onbekende voorbeelden.

variantie
[Bron: Wikipedia]

In de bovenstaande afbeelding is de benaderde doelfunctie de groene lijn en de lijn van de beste fit is zwart. Let op hoe goed het model de trainingsdata leert met de groene lijn. Het doet zijn best om alle rode en blauwe observaties te scheiden. Als we dit model op nieuwe observaties zouden trainen, zou het een geheel nieuwe doelfunctie leren en proberen hetzelfde gedrag te vertonen.

Stel je een scenario voor waarin we een lineaire methode zoals lineaire regressie gebruiken om de doelfunctie te benaderen. Het eerste om op te merken bij lineaire regressie is dat het een lineaire relatie veronderstelt tussen de invoerdata en het doel dat we proberen te voorspellen. Gebeurtenissen in de echte wereld zijn veel complexer. Tegen de prijs van wat flexibiliteit maakt deze eenvoudige aanname het leren van de doelfunctie veel sneller en makkelijker te begrijpen. We noemen dit paradigma bias.

Bias
[Bron: Wikipedia]

In de bovenstaande afbeelding geeft de rode lijn de geleerde doelfunctie weer. Veel observaties liggen ver van de waarden die door het model worden voorspeld.

We kunnen de bias in een model verminderen door het flexibeler te maken, maar dat introduceert variantie. Andersom kunnen we de variantie van een model verlagen door het te vereenvoudigen, maar daarmee introduceren we bias. Aan deze relatie valt niet te ontsnappen. De beste optie is een model kiezen en configureren zodat het een balans vindt in de afweging tussen bias en variantie.

afweging tussen bias en variantie.
[Bron: Wikipedia]

Door onbekende factoren die de doelfunctie beïnvloeden, zal er altijd enige fout in het model aanwezig zijn, de zogeheten onherleidbare fout. Dit is in de bovenstaande afbeelding te zien als de hoeveelheid fout die optreedt onder het laagste punt van de grafiek Total Error. Om het ideale model te bouwen, moeten we een balans vinden tussen bias en variantie zodat de totale fout wordt geminimaliseerd. Dit is geïllustreerd met de gestippelde lijn genaamd Optimale Modelcomplexiteit.

Laten we bias en variantie verder uitwerken met leercurves.

De anatomie van een leercurve

Leercurves zijn grafieken die de prestaties van een model laten zien naarmate de trainingsset groter wordt. Een andere manier om ze te gebruiken is om de prestaties van het model over een bepaalde periode te tonen. We gebruiken ze meestal om algoritmen te diagnosticeren die incrementeel van data leren. Het werkt door een model te evalueren op de trainings- en validatiesets en vervolgens de gemeten prestaties te plotten.

Stel bijvoorbeeld dat we de relatie tussen invoer en uitvoer hebben gemodelleerd met een machine learning-algoritme. We beginnen met het trainen van het model op één voorbeeld en valideren tegen honderd voorbeelden. Wat denk je dat er gebeurt? Als je zegt dat het model de trainingsdata perfect zal leren, dan heb je gelijk – er zouden geen fouten zijn.

Het is niet moeilijk om de relatie van één input naar output te modelleren; je hoeft die relatie alleen maar te onthouden. Het lastige deel is om nauwkeurige voorspellingen te doen wanneer je nieuwe, onbekende voorbeelden krijgt. Omdat ons model de trainingsdata zo goed heeft geleerd, zal het heel slecht generaliseren naar data die het nog niet eerder heeft gezien. Het model zal daarom slecht presteren op onze validatiedata. Dit betekent dat er een groot verschil is tussen de prestaties van ons model op de trainingsdata en de validatiedata. We noemen dit verschil de generaliseringsfout.

Als ons algoritme een kans wil maken om betere voorspellingen te doen op de validatieset, moeten we meer data toevoegen. Het introduceren van nieuwe voorbeelden in de trainingsdata zal onvermijdelijk de doelfunctie van ons model veranderen. Hoe het model presteert terwijl we de trainingsset laten groeien, kan worden gemonitord en geplot om de ontwikkeling van de trainings- en validatiefoutscores te laten zien.

Dit betekent dat de grafiek twee verschillende resultaten zal tonen:

  • Trainingscurve: De curve berekend op basis van de trainingsdata; laat zien hoe goed een model leert.
  • Validatiecurve: De curve berekend op basis van de validatiedata; laat zien hoe goed het model generaliseert naar onbekende voorbeelden.

Deze curves laten zien hoe goed het model presteert naarmate de data groeit, vandaar de naam leercurves.

Let op: Ditzelfde proces kan worden gebruikt om ons te informeren over hoe ons model in de tijd leert. In plaats van te volgen hoe het model het doet naarmate de data groter wordt, volgen we hoe goed het model in de tijd leert. Stel dat je een nieuwe taal besluit te leren. Je beheersing van die taal kan worden geëvalueerd en een numerieke score krijgen om te laten zien hoe je het over de loop van 52 weken hebt gedaan.

Je weet nu uit welke onderdelen een leercurve bestaat; laten we dit toepassen met een echte dataset om je een visueel begrip te geven.

Use case: vastgoedwaarderingen voorspellen

We gebruiken de dataset: de historische marktdata voor vastgoedwaardering. Deze data is verzameld in Sindian Dist., New Taipei, Taiwan en bestaat uit historische marktdata.

Onze taak is om de vastgoedwaardering te voorspellen op basis van de volgende features:

  • X1=de transactiedatum (bijvoorbeeld, 2013.250=maart 2013, 2013.500=juni 2013, enz.)
  • X2=de leeftijd van het huis (eenheid: jaar)
  • X3=de afstand tot het dichtstbijzijnde MRT-station (eenheid: meter)
  • X4=het aantal buurtwinkels binnen loopafstand (integer)
  • X5=de geografische coördinaat, breedtegraad (eenheid: graden)
  • X6=de geografische coördinaat, lengtegraad (eenheid: graden)

De doelvariabele is gedefinieerd als:

  • Y= woningprijs per eenheidsoppervlak (10.000 Nieuwe Taiwanese dollar/Ping, waarbij Ping een lokale eenheid is, 1 Ping = 3,3 vierkante meter)

Het doel dat we voorspellen is continu, dus het probleem vereist regressietechnieken.

Laten we beginnen met een eerste blik op de data:

import pandas as pd

data = pd.read_excel("/content/gdrive/MyDrive/real_estate_valuation_data.xlsx")
print(data.info())
data.head()

>>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 414 entries, 0 to 413
Data columns (total 8 columns):
 #   Column                                  Non-Null Count  Dtype  
---  ------                                  --------------  -----  
 0   No                                      414 non-null    int64  
 1   X1 transaction date                     414 non-null    float64
 2   X2 house age                            414 non-null    float64
 3   X3 distance to the nearest MRT station  414 non-null    float64
 4   X4 number of convenience stores         414 non-null    int64  
 5   X5 latitude                             414 non-null    float64
 6   X6 longitude                            414 non-null    float64
 7   Y house price of unit area              414 non-null    float64
dtypes: float64(6), int64(2)
memory usage: 26.0 KB
None

No    X1 transaction date    X2 house age    X3 distance to the nearest MRT station    X4 number of convenience stores    X5 latitude    X6 longitude    Y house price of unit area
0    1    2012.916667    32.0    84.87882    10    24.98298    121.54024    37.9
1    2    2012.916667    19.5    306.59470    9    24.98034    121.53951    42.2
2    3    2013.583333    13.3    561.98450    5    24.98746    121.54391    47.3
3    4    2013.500000    13.3    561.98450    5    24.98746    121.54391    54.8
4    5    2012.833333    5.0    390.56840    5    24.97937    121.54245    43.1

Er is een extra feature genaamd No die niet werd vermeld in de documentatie van de data. Mogelijk verwijst het naar een index, maar voor de eenvoud gaan we deze verwijderen. Ook komen de featurenamen niet overeen met wat in de documentatie staat, dus dat gaan we opschonen.

# rename the columns
renamed_columns = [col.split()[0] for col in data.columns]
renamed_columns_map = {data.columns[i]:renamed_columns[i] for i in range(len(data.columns))}

data.rename(renamed_columns_map, axis=1, inplace=True)

# remove No column
data.drop("No", axis=1, inplace=True)

print(data.head())

# separate features and target data
features, target = data.columns[:-1], data.columns[-1]

X = data[features]
y = data[target]

Zo ziet de uiteindelijke dataset eruit voordat we de features en doelvariabele splitsen:


        X1          X2          X3      X4      X5          X6        Y
0   2012.916667     32.0    84.87882    10  24.98298    121.54024   37.9
1   2012.916667     19.5    306.59470   9   24.98034    121.53951   42.2
2   2013.583333     13.3    561.98450   5   24.98746    121.54391   47.3
3   2013.500000     13.3    561.98450   5   24.98746    121.54391   54.8
4   2012.833333     5.0     390.56840   5   24.97937    121.54245   43.1

Om bias, variantie en good fit-oplossingen te demonstreren, bouwen we drie modellen: een decision tree regressor, een support vector machine voor regressie en een random forest regressor. Nadat we het model hebben gebouwd, plotten we voor elk leercurves en delen we enkele diagnostische technieken.

Leercurves diagnosticeren

Leercurves worden geïnterpreteerd door hun vorm te beoordelen. Zodra de vorm en dynamiek zijn geïnterpreteerd, kunnen we ze gebruiken om problemen in het gedrag van een machine learning-model te diagnosticeren.

De functie learning_curve() in Scikit-learn maakt het makkelijk om trainings- en validatiescores te monitoren, wat nodig is om een leercurve te plotten.

De parameters die we doorgeven aan de functie learning_curve() zijn als volgt:

  • estimator: het model dat wordt gebruikt om de doelfunctie te benaderen
  • X: de invoerdata
  • y: het doel
  • cv: de crossvalidatiestrategie
  • scoring: de maatstaf die wordt gebruikt om de prestaties van het model te evalueren
  • train_sizes: het absolute aantal trainingsexemplaren dat wordt gebruikt om de leercurve te genereren; de waarden die we gebruiken zijn volledig willekeurig.

Model 1: Decision tree regressor

Een model met hoge variantie heet overfit. Het leert de trainingsdata en de willekeurige ruis extreem goed, wat resulteert in een model dat goed presteert op de trainingsdata, maar niet kan generaliseren naar onbekende voorbeelden. We zien dit gedrag wanneer het gebruikte algoritme te flexibel is voor het probleem dat wordt opgelost, of wanneer het model te lang wordt getraind.

De decision tree regressor is bijvoorbeeld een niet-lineair machine learning-algoritme. Niet-lineaire algoritmen hebben doorgaans lage bias en hoge variantie. Dit suggereert dat veranderingen in de dataset tot grote variaties in de doelfunctie zullen leiden.

Laten we hoge variantie demonstreren met onze decision tree regressor:

from sklearn.model_selection import learning_curve
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt

# overfitting
decision_tree = DecisionTreeRegressor()

train_sizes, train_scores, test_scores = learning_curve(
    estimator=decision_tree,
    X=X,
    y=y,
    cv=5,
    scoring="neg_root_mean_squared_error",
    train_sizes = [1, 75, 165, 270, 331]
)

train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)

plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")

plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")

plt.show()
Model 1: Decision tree regressor

Het model maakt heel weinig fouten wanneer het voorbeelden moet voorspellen die het tijdens training heeft gezien, maar presteert slecht op nieuwe voorbeelden waarmee het niet is geconfronteerd. Je kunt dit gedrag zien aan het grote generalisatieverschil tussen de trainingscurve en de validatiecurve. Een oplossing om dit gedrag te verbeteren kan zijn om meer voorbeelden aan onze trainingsset toe te voegen, wat bias introduceert. Een andere oplossing is om regularisatie aan het model toe te voegen (d.w.z. voorkomen dat de boom tot zijn volledige diepte groeit).

Model 2: Support Vector Machine

Een model met hoge bias heet underfit. Het maakt simplistische aannames over de trainingsdata, waardoor het moeilijk wordt om de onderliggende patronen te leren. Dit resulteert in een model met hoge fout op zowel de trainings- als de validatiesets. We zien dit gedrag wanneer het gebruikte model te simpel is voor het probleem, of wanneer het model niet lang genoeg wordt getraind.

De support vector machine is bijvoorbeeld een lineair machine learning-algoritme. Lineaire algoritmen hebben doorgaans hoge bias en lage variantie. Dit suggereert dat er meer aannames worden gedaan over de vorm van de doelfunctie. Om meer bias in ons model te introduceren, hebben we regularisatie toegevoegd door de parameter C in ons model in te stellen.

Laten we hoge bias demonstreren met onze support vector machine:

from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler

# Underfitting
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

svm = SVR(C=0.25)

train_sizes, train_scores, test_scores = learning_curve(
    estimator=svm,
    X=X_scaled,
    y=y,
    cv=5,
    scoring="neg_root_mean_squared_error",
    train_sizes = [1, 75, 150, 270, 331]
)

train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)

plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")

plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")

plt.show()
Model 2: Support Vector Machine

Het generalisatiegat tussen de trainings- en validatiecurve wordt extreem klein naarmate de omvang van de trainingsset toeneemt. Dit geeft aan dat het toevoegen van meer voorbeelden aan ons model de prestaties niet gaat verbeteren. Een oplossing voor dit probleem kan zijn om meer features te creëren of het model flexibeler te maken om het aantal aannames te verminderen.

Model 3: Random Forest Regressor

Een model met een goede fit bevindt zich in het grijze gebied tussen een underfit en overfit model. Het model is misschien niet zo goed op de trainingsdata als in het overfit-geval, maar het maakt veel minder fouten bij onbekende voorbeelden. Dit gedrag is te zien wanneer de trainingsfout toeneemt, maar slechts tot een stabiel punt, terwijl de validatiefout afneemt tot een stabiel punt.

Om dit te demonstreren gebruiken we een random forest, een ensemble van beslissingsbomen. Dit betekent dat het model ook niet-lineair is, maar dat er bias aan het model wordt toegevoegd door meerdere diverse modellen te maken en hun voorspellingen te combineren.

We hebben ook extra regularisatie toegevoegd door de max_depth, die de maximale diepte van elke boom bepaalt, in te stellen op drie.

Laten we kijken hoe dit eruitziet in code:

from sklearn.ensemble import RandomForestRegressor

# better
random_forest = RandomForestRegressor(max_depth=3)

train_sizes, train_scores, test_scores = learning_curve(
    estimator=random_forest,
    X=X,
    y=y,
    cv=5,
    scoring="neg_root_mean_squared_error",
    train_sizes = [1, 75, 150, 270, 331]
)

train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)

plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")

plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")

plt.show()
Model 3: Random Forest Regressor

Je ziet nu dat we de fout in de validatiedata hebben verminderd. Dat ging ten koste van een zwakkere prestatie op de trainingsdata, maar al met al is het een beter model.

De generaliseringsfout is veel kleiner, met weinig fouten. Ook zijn beide curves stabiel voorbij een trainingssetgrootte van 250, wat impliceert dat het toevoegen van meer voorbeelden dit model niet veel verder zal verbeteren.

Samengevat: het gedrag van een model kun je observeren met leercurves. Het ideale scenario bij het bouwen van machine learning-modellen is om de fout zo laag mogelijk te houden. Twee factoren die tot hoge fout leiden, zijn bias en variantie, en een goede balans tussen beide zorgt voor een beter presterend model.

Onderwerpen

Gerelateerd