Leren a.d.h.v. een simpel leermodel : K-NNΒΆ

K. VerbeeckΒΆ

Data Science (Theory) -- OGI02i

neighbors.jpg

Supervised Machine LearningΒΆ

TypeML.png

Classification & RegressionΒΆ

Classificatie is een ML taak waarbij een label voorspeld moet worden uit een mogelijke lijst van antwoorden.

Wanneer er slechts 2 mogelijke labels zijn dan noemt men dit binaire classificatie

Voorbeeld : je spam filter : een mail is spam of ham - je lost in dit geval een ja/nee vraag op

Wanneer er meerdere labels mogelijk zijn dan noemt men dit multiclass classificatie

Voorbeeld : herkennen van handgeschreven cijfers - het antwoord kan zijn : 0,1,...,9

Regressie is een ML taak waarbij een cijfer (continue waarde) voorspeld moet worden

Voorbeeld : iemand zijn leeftijd voorspellen, iemand zijn jaarlijks inkomen voorspellen, ...

Generalizatie, Overfitting, en UnderfittingΒΆ

Wanneer je leert aan de hand van een supervisor dan heb je gelabelde trainingsdata ter beschikking en leer je een model op basis van deze data.

Een model zal je instaat stellen om een beslissing te nemen voor elk geval (instantie) waarvan je een voorspelling wil doen. Een model mag echter niet alleen goed presteren op de trainingsdata, het model moet algemeen genoeg zijn om ook ongeziene instanties correct te gaan voorspellen.

Men zegt dat het model moet kunnen generalizeren / veralgemenen van de trainingsdata naar de test data. De test data is een deel van de data die je ter beschikking hebt, maar niet meeneemt tijdens het trainen van je model.

Wanneer je model extreem goed presteert op je trainingsdata, maar niet zo goed presteert op je test data spreekt men van overfitting.

Wanneer je model zelfs niet goed presteert op je trainingsdata dan spreek je van underfitting.

Zoek een punt waarbij je data goed presteert op zowel trainings- als test-data.

Overfitting : een voorbeeldΒΆ

Voorspel wanneer iemand een boot koopt aan de hand van onderstaande gegevens.

Age Nr cars owns house nr children status owns dog bought a boat
66 1 yes 2 widowed no yes
52 2 yes 3 married no yes
22 0 no 0 married yes no
25 1 no 1 single no no
44 0 no 2 divorced yes no
39 1 yes 2 married yes no
26 1 no 2 single no no
40 3 yes 1 married yes no
53 2 yes 2 divorced no yes
64 2 yes 3 divorced no no
58 2 yes 2 married yes yes
33 1 no 1 single no no

mogelijke hypothesen :

  • ouder dan 45, en minder dan 3 kinderen of niet gescheiden -> dan zal je een boot kopen (100% accuracy -> overfitting)

  • exact 66, 52, 53 of 58 jaar oud zijn -> dan zal je een boot kopen (100% accuracy -> overfitting)

  • ouder dan 50 -> dan zal je een boot kopen (simpelere regel die min of meer ok presteert)

  • bezitter van een huis dan -> zal je een boot kopen (underfitting !)

overfitting_underfitting_cartoon.png

  • Hoe complexer het model wordt, hoe beter de trainingsdata voorspeld zal worden maar voorbij een zeker punt zal de accuracy op de testdata afnemen. (er wordt teveel gefocust op elk individueel trainingspunt)

  • Hoe simpeler het model wordt, hoe slechter trainingsdata Γ©n testdata voorspeld zal worden.

  • Er is een sweet spot in het midden vlak voor de accuracy op de testdata begint af te nemen. Op dit punt zal je hypothese het best veralgemenen.

k-NN : k-Nearest NeighborsΒΆ

Waarschijnlijk het simpelste leermodel : er wordt niet echt een model opgebouwd, het enige wat er gedaan wordt is de dataset van trainingspunten bijhouden. Wanneer een voorspelling moet gebeuren voor een nieuw datapunt wordt in de dataset de dichtste buur gezocht (wanneer $N=1$), of de k-dichtste buren (waneer $N=k$).

De voorspelling van het nieuwe datapunt zal afhangen van de waarden van zijn buren.

Visualisatie van k-nn (classificatie) :ΒΆ

$k=1$

KNNClassificatie.PNG

Datapunten worden hier beschreven door 2 features (x en y - as). Het label (rode driehoek / blauw bolletje) geeft de classificatie aan.

De nieuwe testpunten krijgen het label van hun dichtste buur.

$k = 3$

image.png

Wanneer het aantal buren $k > 1$ dan wordt het label hier bepaald door voting. Welke label is meest voorkomend onder de k-dichtste buren?

Beslissingsgrenzen bepaald door het aantal buren :

image.png

Wanneer het aantal buren $k$ toeneemt wordt de beslissingsgrens smoother en dus eenvoudiger.

Hoe het aantal buren kiezen? Hoe meer buren, hoe simpeler het model.

testtrainingaccuracy.png

  • Wanneer het model gebaseerd is op weinig buren is de beslissingsgrens of het model complexer en zal dit model overfitten.

  • Wanneer het model gebaseerd is op veel buren, dan wordt de beslissingsgrens en het model eenvoudiger en zal dit model waarschijnlijk underfitten.

  • Het optimaal aantal buren kan ook hier bepaald worden door te sweet spot te bepalen, vanaf welk punt daalt de test accuracy. Dit is in dit geval wanneer $k = 6$.

  • Bij k-NN kan je dus zeggen dat de complexiteit van het model afhangt van het aantal buren $k$

  • Wat gebeurt er wanneer $k =$ alle punten in de volledige dataset?

Visualisatie van k-NN (regressie) $k=1$ΒΆ

In deze figuur wordt de data beschreven aan de hand van 1 feature (de x-as). De waarde van de target lees je af van de y-as. Voor een testpunt wordt de buur die zich het dichtsbij op de x-as gezocht. Het testpunt krijgt dezelfde targetwaarde als deze buur.

image.png

$k=3$ Voor deze testpunten worden 3 punten dichtsbij op de x-as gezocht. De targetwaarde van het testpunt wordt nu bekomen door het gemiddelde te nemen van de targetwaarden van deze 3 buren.

image.png

Uitgewerkt Voorbeeld k-NN classificatieΒΆ

De classificatie van Iris species : voorbeeld uit :

An Introduction to Machine Learning with Python, MΓΌller & Guido

iris_petal_sepal.png

petal = bloemblad, sepal = kelkblad

ML learning module in Python :ΒΆ

sklearn.png

InΒ [1]:
from sklearn.datasets import load_iris
iris_dataset = load_iris()
InΒ [2]:
print("Keys of iris_dataset:\n", iris_dataset.keys())
Keys of iris_dataset:
 dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
InΒ [3]:
print(iris_dataset['DESCR'][:193] + "\n...")
.. _iris_dataset:

Iris plants dataset
--------------------

**Data Set Characteristics:**

    :Number of Instances: 150 (50 in each of three classes)
    :Number of Attributes: 4 numeric, pre
...
InΒ [4]:
print("Feature names:\n", iris_dataset['feature_names'])
Feature names:
 ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
InΒ [5]:
print("Type of data:", type(iris_dataset['data']))
Type of data: <class 'numpy.ndarray'>
InΒ [6]:
print("Shape of data:", iris_dataset['data'].shape)
Shape of data: (150, 4)
InΒ [7]:
print("First five rows of data:\n", iris_dataset['data'][:5])
First five rows of data:
 [[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 [4.6 3.1 1.5 0.2]
 [5.  3.6 1.4 0.2]]
InΒ [8]:
print("Type of target:", type(iris_dataset['target']))
Type of target: <class 'numpy.ndarray'>
InΒ [9]:
print("Shape of target:", iris_dataset['target'].shape)
Shape of target: (150,)
InΒ [10]:
print("Target:\n", iris_dataset['target'])
Target:
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

Training versus TestingΒΆ

InΒ [11]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    iris_dataset['data'], iris_dataset['target'], random_state=0)
#door een randomstate in te stellen wordt de split telkens op dezelfde manier genomen
#wanneer niet ingesteld, zal 25% van de data als testdata genomen worden
InΒ [12]:
print("X_train shape:", X_train.shape)
print("y_train shape:", y_train.shape)
X_train shape: (112, 4)
y_train shape: (112,)
InΒ [13]:
print("X_test shape:", X_test.shape)
print("y_test shape:", y_test.shape)
X_test shape: (38, 4)
y_test shape: (38,)

Wat zegt de data ?ΒΆ

Het is steeds een goed idee om je data te visualiseren, bvb. via een scatterplot, om eventuele trends in de data te visualiseren. Het geeft je ook een idee van welk leermodel je zou kunnen gebruiken.

InΒ [14]:
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import datasets
%matplotlib inline

iris_dataframe = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
# create a scatter matrix from the dataframe, color by y_train
pd.plotting.scatter_matrix(iris_dataframe, c=y_train, figsize=(4, 4), 
                           marker='o', hist_kwds={'bins': 20})
plt.show()
No description has been provided for this image

Een model bouwen a.d.h.v. k-Nearest NeighborsΒΆ

InΒ [15]:
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=1)
#knn is een object waarop de verdere fit/predict/score operaties zullen gebeuren
InΒ [16]:
knn.fit(X_train, y_train)
#het model wordt gebouwd 
Out[16]:
KNeighborsClassifier(n_neighbors=1)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KNeighborsClassifier(n_neighbors=1)

minkowski afstandsmaat = $L^p$ = veralgemening van de Manhattan (p = 1) en Euclidische afstand (p = 2) \begin{equation} d(\bf{x_1},\bf{x_2}) = (\sum_{i=1}^{d} |x_{1i} - x_{2i}|^{1/p})^{p} \end{equation}

Populaire afstandsmaten in python :ΒΆ

http://dataaspirant.com/2015/04/11/five-most-popular-similarity-measures-implementation-in-python/

maten.png

Voorspellingen makenΒΆ

InΒ [17]:
import numpy as np
X_new = np.array([[5, 2.9, 1, 0.2]])
print("X_new.shape:", X_new.shape)
X_new.shape: (1, 4)
InΒ [18]:
#nieuwe voorspellingen worden gemaakt a.d.h.v. het model
prediction = knn.predict(X_new)
print("Prediction:", prediction)
print("Predicted target name:",
       iris_dataset['target_names'][prediction])
Prediction: [0]
Predicted target name: ['setosa']

Hoe goed is het model?ΒΆ

InΒ [19]:
y_pred = knn.predict(X_test)
print("Test set predictions:\n", y_pred)
Test set predictions:
 [2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0
 2]
InΒ [20]:
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
Test set score: 0.97
InΒ [21]:
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Test set score: 0.97

AccuracyOverfittingSmall.jpg

Parameters van k-NNΒΆ

2 belangrijke parameters :

  • het aantal buren k
  • hoe afstanden meten tussen 2 elementen uit de data set (Euclidische afstand (zie ook $L^2$ norm)

Minkowski afstand (zie $L^p$ norm)

Pro's and Cons van k-NNΒΆ

Sterktes:

  • eenvoudig te begrijpen leermodel
  • snelle trainingsfase want LAZY LEARNING (verschil t.o.v. EAGER LEARNING)
  • voor kleinere datasets : snel en goede performantie met weinig parameter tuning
  • kan zowel voor classificatie als regressieproblemen gebruikt worden

Zwaktes:

  • bij grote datasets (d.i. veel data of veel features of beide) is het voorspellen traag
  • k-NN gebruikt de euclidische afstandsmaat, deze schaalt niet goed bij hogere dimensies (beter : cosinus similariteit)
  • grote geheugenopslag moet ter beschikking zijn om de trainingset ter beschikking te houden tijdens het leren
  • niet zo geschikt voor de zgn. sparse datasets (veel features die 0 zijn) (zie verder curse of dimensionality)

Hoe K kiezen ?ΒΆ

  • k noemt men een hyperparameter : deze moet je vooraf instellen (tijdens de fase model building) en kan het resultaat van het voorspellen serieus beΓ―nvloeden.

  • er bestaat geen algemene optimale keuze voor k. Deze is dataset afhankelijk.

  • wanneer k klein is (weinig buren worden gebruikt) dan heeft ruis in de data meer effect op het resultaat dan wanneer k groot is

  • wanneer k groot is (veel buren mee laten beslissen) dan wordt het effect van ruis wel geminimaliseerd, maar dan vergt het voorspellen veel rekenkracht.

  • Meestal wordt een oneven getal gebruikt als de waarde voor k als het aantal te voorspellen klassen even is - (dit om gelijkstand te vermijden bij voting)

  • Vuistregel die vaak gebruikt wordt : kies $k = \sqrt(n)$ met $n$ het aantal datapunten

  • Andere methoden gebaseerd op parameter tuning : trial-and-error in combinatie met berekenen van errors, i. e. Elbow-methode

Elbow method :ΒΆ


rmse_val = [] #to store rmse values for different k
for k in range(20):
    k = k + 1
    model = neighbors.KNeighborsRegressor(n_neighbors = k)
    model.fit(x_train, y_train)  #fit the model
    pred=model.predict(x_test) #make prediction on test set
    error = sqrt(mean_squared_error(y_test,pred)) #calculate rmse
    rmse_val.append(error) #store rmse values

elbowcurve.png

Bias - Variance tradeoffΒΆ

Bias is een fout / error in het leermodel die onstaat doordat verkeerde assumpties gebruikt zijn om het model op te stellen. Een model met hoge bias zal (te) weinig rekening houden met de trainingsdata en zal het model oversimplificeren.

Variantie is eveneens een fout, maar deze is te wijten aan te gevoelig zijn voor de fluctuaties in de trainingsset, waardoor ruis mee gemodelleerd kan worden en het model dus de trainingsdata te goed modelleert (overfitting!)

de trade-off : beide effecten moeten vermeden worden maar vaak is het zo dat lage bias, veel variantie inhoudt en vice versa.

een kleine k heeft weinig last van bias maar geeft een hoge variantie, terwijl een grote k minder variantie geeft maar gevoeliger is aan bias

Bias - Variance tradeoffΒΆ

tradeoff.png

Curse of dimensionalityΒΆ

Wanneer heel veel features aanwezig zijn in de data, dan is het moelijker om datapunten te vinden die dichtbij zijn (ze zijn misschien dichtbij in een bepaalde feature maar als er heel veel zijn heeft dit weinig effect op de afstand)

Dus in dit geval zullen er heel veel extra datavoorbeelden nodig zijn om goede dichte buren te vinden !

M.a.w. je helpt het leerprobleem niet vooruit door je data steeds rijker te beschrijven als je geen extra datavoorbeelden hebt. Bovendien bestaat ook het gevaar voor overfitting.

Als je toch extra features toevoegt dan zal je dus ook meer trainingsdata moeten toevoegen maar deze zal exponentieel moeten groeien om hetzelfde aandeel van data te voorzien en overfitting te vermijden.

Oplossing : investeren in feature selection methoden, zoals Principal component en singular value decomposition

Curse of dimensionalityΒΆ

zie ook artikel : http://www.visiondummy.com/2014/04/curse-dimensionality-affect-classification/

Classificatietaak : Leer honden van katten onderscheiden

features gebaseerd op kleurverschillen RGB

  • feature 1 : gemiddelde R-waarden
  • feature 2 : gemiddelde G-waarden
  • feature 3 : gemiddelde B-waarden

Stel er zijn slechts 10 datavoorbeelden : bij verhogen van het aantal features wordt de dataruimte steeds sparser, het wordt dus eenvoudiger om een grens tussen katten en honden aan te duiden.

curse1.png

curse2.png

curse3.png

Echter de datapunten worden hierdoor serieus overfit. Wanneer de separator in 3D wordt geprojecteerd op de 2D ruimte dan merk je deze overfitting. Bij een gelijke hoeveelheid data loont het dus niet om features te blijven toevoegen!

curse4.png

Goede tutorials :ΒΆ

KNN Classification using Scikit-learn Learn K-Nearest Neighbor(KNN) Classification and build KNN classifier using Python Scikit-learn package. online @ https://www.datacamp.com/community/tutorials/k-nearest-neighbor-classification-scikit-learn

A Practical Introduction to K-Nearest Neighbors Algorithm for Regression (with Python code) online @ https://www.analyticsvidhya.com/blog/2018/08/k-nearest-neighbor-introduction-regression-python/