Luokittelu - päätöspuu

Klassinen esimerkki luokittelusta on kurjenmiekkojen (iris) luokittelu kolmeen lajiin (setosa, versicolor, virginica) terä- (petal) ja verholehtien (sepal) koon mukaan. Seuraavassa käytän luokitteluun päätöspuuta.

Päästöspuu-menetelmän idea

Päätöspuumenetelmälle annetaan parametrina puun syvyys (kuinka monta haarautumista enimmillään?).

Jokaisessa haarautumisessa algoritmi valitsee parhaiten erottelevan selittävän muuttujan ja siihen liittyvän rajakohdan.

Gini = millä todennäköisyydellä tehdään väärä luokittelu? Toimivassa päätöspuussa on haarautumisten jälkeen vain pieniä gini-arvoja.

In [1]:
import pandas as pd
import matplotlib 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 0x1cd41cec970>
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]:
# Päätöspuumallin tuonti:
from sklearn import tree

# Parametrilla max_depth määrätään päätöspuun maksimi syvyys.
malli = tree.DecisionTreeClassifier(max_depth = 4)
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

print(accuracy_score(y_train, y_train_malli))
0.9910714285714286
In [8]:
# Oikeaan osuneiden ennusteiden osuus testidatassa:

print(accuracy_score(y_test, y_test_malli))
0.9210526315789473
In [9]:
# Confusion-matriisi opetusdatalle:

from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_train, y_train_malli))
[[38  0  0]
 [ 0 36  0]
 [ 0  1 37]]
In [10]:
# Confusion-matriisi testidatalle:

print(confusion_matrix(y_test, y_test_malli))
[[12  0  0]
 [ 0 12  2]
 [ 0  1 11]]

Päätäspuun graafista esittämistä varten tarvitset pydotplus pakettia, joita ei ole Anacondan vakioasennuksessa. Voit asentaa sen Anaconda Navigatorin kautta. Löydät sen valitsemalla Environments - Not Installed.

Aikaisemmissa versiossa asennukseen liittyi monelaisia konekohtaisia ongelmia. Jos törmäät ongelmiin, niin lue https://github.com/ContinuumIO/anaconda-issues/issues/1666

In [11]:
# Seuraava edellyttää pydotplus-paketin asentamista
import pydotplus 
from IPython.display import Image  

dot_data = tree.export_graphviz(malli, out_file = None, 
                         feature_names = X.columns,
                         class_names = ['setosa', 'versicolor', 'virginica'],
                         filled = True, rounded = True, special_characters = True)  
graph = pydotplus.graph_from_dot_data(dot_data)  
Image(graph.create_png())
Out[11]:

Ensimmäinen haarautuminen tehdään petal_length-muuttujan perusteella. Jos petal_length on pienempi tai yhtäsuuri kuin 2,45, niin havainto luokitellaan setosaksi (38 kpl, gini=0). Jäljelle jää 36 versicoloria ja 38 virginicaa (gini=0,5). Jos ajat koodin uudelleen, niin ensimmäinen haarautuminen voi toteutua myös petal_width-muuttujan perusteella, mutta johtaa samaan tulokseen.

Seuraava jako tehdään petal_width-muuttujan arvon 1,75 kohdalta. Toiseen haaraan jää 36 versicoloria ja 3 virginicaa (gini=0,142) ja toiseen haaraan 35 virginicaa (gini=0) jne.

In [12]:
# Päätöspuun kuvan voi tallentaa pdf-muodossa:
graph.write_pdf("iris.pdf")
Out[12]:
True
In [13]:
# Uusi data, jota ei ole valmiiksi luokiteltu:
Xnew = pd.read_excel('http://taanila.fi/irisnew.xlsx')
Xnew
Out[13]:
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 [14]:
# Luokittelu:
malli.predict(Xnew)
Out[14]:
array(['setosa', 'virginica', 'versicolor'], dtype=object)