Luokittelu - KNN (K-nearest neighbors)

Klassinen esimerkki luokittelusta on kurjenmiekkojen (iris) luokittelu kolmeen lajiin (setosa, versicolor, virginica) terä- (petal) ja verholehtien (sepal) koon mukaan. Seuraavassa käytän luokitteluun K-nearest neighbors -menelmää.

K-nearest neighbors -menetelmän idea

Parametrina annetaan naapurien lukumäärä K (kannattaa kokeilla eri arvoja).

Etsitään luokiteltavalle havainnolle K lähintä naapuria opetusdatasta.

Luokiteltava havainto sijoitetaan siihen luokkaan, joka on enemmistönä K:n lähimmän naapurin joukossa.

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
In [2]:
# Esimerkkidata löytyy seaborn-kirjastosta:
iris = sns.load_dataset('iris')
iris.head()
Out[2]:
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
In [3]:
# Seaborn-kirjaston pairplot havainnollistaa hyvin lajin (species) riippuvuutta petal- ja sepal-mitoista:
sns.pairplot(iris, hue='species')
Out[3]:
<seaborn.axisgrid.PairGrid at 0x25437fdb9d0>
In [4]:
# Feature-matriisi on iris-data ilman species-muuttujaa:
X = iris.drop('species', axis=1)

# Target on species (laji):
y = iris['species']
In [5]:
# train_test_split jakaa datan opetusdataan ja testidataan (25 % datasta, jolloin toisin määrätä).
# random_state määrittää satunnaislukugeneraattorin siemenluvun. Sama siemenluku takaa saman jaottelun
# eri suorituskerroilla.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=5)
In [6]:
# KNN-mallin tuonti:
from sklearn.neighbors import KNeighborsClassifier

# Mallin sovitus:
malli = KNeighborsClassifier(n_neighbors=5)
malli.fit(X_train, y_train)

# Mallin mukaisten ennusteiden laskeminen opetusdatalle ja testidatalle:
y_train_malli = malli.predict(X_train)
y_test_malli = malli.predict(X_test)
In [7]:
# Oikeaan osuneiden ennusteiden osuus opetusdatassa:

from sklearn.metrics import accuracy_score

accuracy_score(y_train, y_train_malli)
Out[7]:
0.9821428571428571
In [8]:
# Oikeaan osuneiden ennusteiden osuus testidatassa:
accuracy_score(y_test, y_test_malli)
Out[8]:
0.9473684210526315
In [9]:
# Confusion-matriisi opetusdatalle:
from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_train, y_train_malli))
[[38  0  0]
 [ 0 35  1]
 [ 0  1 37]]

Kaikki Setosa-lajiin kuuluvat ennustetaan oikein, yksi Versicolor ennustetaan virheellisesti Virginica-lajiin kuuluvaksi, yksi Virginica-lajiin kuuluvaa ennustetaan virheellisesti Versicolor-lajiin kuuluvaksi.

In [10]:
# Confusion-matriisi testidatalle:
print(confusion_matrix(y_test, y_test_malli))
[[12  0  0]
 [ 0 12  2]
 [ 0  0 12]]

Kaikki Setosa-lajiin kuuluvat ennustetaan oikein, kaksi Versicoloria ennustetaan virheellisesti Virginica-lajiin kuuluviksi, kaikki Virginica lajiin kuuluvat ennustetaan oikein.

In [11]:
# Uusi data, jota ei ole valmiiksi luokiteltu:
Xnew = pd.read_excel('http://taanila.fi/irisnew.xlsx')
Xnew
Out[11]:
sepal_length sepal_width petal_length petal_width
0 5.0 3.5 1.5 0.3
1 8.1 3.3 6.5 1.9
2 6.0 3.0 3.0 0.5
In [12]:
# Luokittelu:
malli.predict(Xnew)
Out[12]:
array(['setosa', 'virginica', 'versicolor'], dtype=object)