#!/usr/bin/env python # coding: utf-8 # In[1]: from datetime import datetime print(f'Päivitetty {datetime.now().date()} / Aki Taanila') #

Ensimmäinen esimerkki luokittelusta

# # Tästä muistiosta opit luokittelumallien opettamiseen liittyviä perustekniikoita, jotka toistuvat samankaltaisina aina luokittelumalleja opetettaessa: # # * Selittävien muuttujien arvojen (**X**) ja kohdemuuttujan arvojen (**y**) määrittely. # * **Testidata**n erottaminen opetusdatasta. # * Mallin opettaminen/sovittaminen **fit**-funktiolla. # * Mallin **tarkkuus** opetusdatalle ja testidatalle. # * Mallin antamien ennusteiden tarkastelu **sekaannusmatriisi**na opetusdatalle ja testidatalle. # * Mallin **ennusteiden** laskeminen täysin uudelle datalle. # # Kurjenmiekkojen (iris) luokittelu on klassinen esimerkki, joka usein otetaan ensimmäisenä esimerkkinä luokittelumalleista. # # Tässä opetan mallin erottelemaan kurjenmiekan lajikkeita (setosa, versicolor ja virginica) toisistaan verholehtien (sepal) ja terälehtien (petal) pituuksien ja leveyksien perusteella. # # Tässä käytän mallina **päätöspuuta** (decision tree), jonka rakenteen voin esittää havainnollisena kaaviona. Parempiakin malleja löytyy, mutta käytän tarkoituksella tässä ensimmäisessä esimerkissä mallia, jota voin havainnollistaa kaaviona. # # Koneoppimisen peruskirjasto on **scikit-learn** tai lyhyemmin **sklearn**: https://scikit-learn.org/stable/index.html. # In[2]: import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # train_test_split osaa jakaa datan opetusdataan ja testidataan from sklearn.model_selection import train_test_split # Käytän luokittelumallina päätöspuuta (DecisionTreeClassifier), plot_tree osaa piirtää päätöspuun from sklearn.tree import DecisionTreeClassifier, plot_tree # Sekaannusmatriisin näyttämiseen from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay # ## Datan tarkastelua # In[3]: # Lataan datan seaborn-kirjastosta df = sns.load_dataset('iris') df.info() # In[4]: df # In[5]: # Parittaiset hajontakaaviot, joissa eri lajikkeet (species) eri väreillä sns.pairplot(df, hue='species') # Hajontakaavioiden perusteella setosat ovat helposti eroteltavissa, mutta versicolor ja virginica menevät jossain määrin päällekkäin. Erityisesti terälehden pituus ja leveys (petal_length ja petal_width) näyttäisivät erottelevan lajikkeita hyvin. # ## Mallin sovitus # # Mallin opettamiseen tarvitaan selittävien muuttujien arvot ja kohdemuuttujan (ennustettava muuttuja) arvot. Tässä verholehtien ja terälehtien mitat ovat selittäviä muuttujia ja kurjenmiekan lajike on kohdemuuttuja. # # On tärkeää erottaa osa opetusdatasta testidataksi. Opetusdataa käyttäen malli opetetaan ja testidataa käyttäen varmistetaan mallin toimivuus datalla, jota ei olla käytetty opettamiseen. # # Jako opetus- ja testidataan tapahtuu sattumanvaraisesti, joten eri suorituskerroilla saan erilaisia jakoja. Koska eri suorituskerroilla on erilaisia opetusdatoja, niin mallikin voi hieman vaihdella suorituskerroittain. Tässä annan **random_state**-parametrille kiinteän arvon, jonka seurauksena jako tehdään jokaisella suorituskerralla samalla tavalla. # In[6]: # Selittävät muuttujat X = df.drop('species', axis=1) # Kohdemuuttuja y = df['species'] # Datan jako opetus- ja testidataan X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=2) # Päätöspuu kuten muutkin sklearn-kirjaston mallit opetetaan **fit**-funktiolla, jolle annetaan parametreina opetusdatan selittävien muuttujien arvot ja kohdemuuttujan arvot. # # Opetettavalle mallille voidaan määrittää niin kutsuttuja hyperparametreja. Tässä määritän päätöspuun maksimi syvyyden eli haarautumisten määrän (**max_depth**). Voit kokeilla muitakin arvoja. Mallin opettamiseen liittyy sattumanvaraisuutta, joten eri suorituskerroilla voidaan saada toisistaan poikkeavia päätöspuita. Kiinteä arvo **random_state**-parametrille takaa että eri suorituskerroilla saadaan samanlainen päätöspuu. # In[7]: # Mallin sovitus (opettaminen) malli = DecisionTreeClassifier(max_depth=3, random_state=2) malli.fit(X_train, y_train) # ## Mallin arviointia # Mallin tarkkuus opetusdatassa kasvaa päätöspuun haarautumisten lisääntyessä, mutta samalla kasvaa ylisovituksen riski. Jos mallin tarkkuus opetusdatassa on selvästi suurempi kuin testidatassa, niin tämä kertoo ylisovituksesta. # # Tässä opetusdatan ja testidatan tarkkuudet ovat lähellä toisiaan, joten päätöspuun syvyys 3 oli hyvä valinta. # In[8]: print(f'Mallin tarkkuus opetusdatassa {malli.score(X_train, y_train):.3f}') print(f'Mallin tarkkuus testidatassa {malli.score(X_test, y_test):.3f}') # Edellä käytetään tarkkuuden esittämiseen muotoiltua merkkijonoa. Muotoiltua merkkijonoa edeltää **f**. Muotoiltuun merkkijonoon voin lisätä muuttujan arvon aaltosulkujen sisään ja voin samalla antaa muotoiluohjeen. Tässä muotoiluohje **:.3f** muotoilee desimaaliluvun kolmen desimaalin tarkkuuteen. # # Mallin antamia ennusteita päästään tarkastelemaan **sekaannusmatriisin** (confusion matrix) avulla. # In[9]: # Mallin antamat ennusteet opetusdatalle y_train_malli = malli.predict(X_train) # Sekaannus-matriisi opetusdatalle cm = confusion_matrix(y_train, y_train_malli) ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['setosa', 'versicolor', 'virginica']).plot() # * jokainen opetusdatan 34 setosasta ennustetaan oikein setosaksi. # * opetusdatan 39 versicolorista 37 ennustetaan oikein versicoloriksi ja 2 ennustetaan virheellisesti virginicaksi. # * jokainen opetusdatan 39 virginista ennustetaan oikein virginaksi. # # Opetusdatan sekaannusmatriisi ei sellaisenaan kerro, toimiiko malli myös opetusdatan ulkopuolella (ylisovittamisen takia opetusdatasssa hyvin toimiva malli ei välttämättä toimi opetusdatan ulkopuolella). # Testidatan sekaannusmatriisista nähdään toimiiko opetettu malli myös opetukseen käytetyn datan ulkopuolella. # In[10]: # Mallin antamat ennusteet testidatalle y_test_malli = malli.predict(X_test) # Sekaannus-matriisi testidatalle cm = confusion_matrix(y_test, y_test_malli) ConfusionMatrixDisplay(confusion_matrix=cm, display_labels = ['setosa', 'versicolor', 'virginica']).plot() # Testidatassa malli ennustaa yhden versicolorin virheellisesti virginicaksi. # In[11]: # Voin havainnollistaa päätöspuumallin opetusdatassa kaaviona plt.figure(figsize=(10, 6)) plot_tree(decision_tree=malli, feature_names=['sepal_length', 'sepal_width', 'petal_length', 'petal_width']) # #### Selitystä # # Opetusdatassa on 34 setosaa, 39 versicoloria ja 39 virginicaa. # # Ensimmäisessä haarautumisessa päätössääntönä on **petal_width <= 0.8**, jonka perusteella saadaan eroteltua kaikki setosa-lajikkeeseen kuuluvat omaan haaraansa. # # Ensimmäisessä vaiheessa **gini** = (34/112)^2 + (39/112)^2 + (39/112)^2 (todennäköisyyksien neliöiden summa). Ginin arvosta voidaan johtaa **gini impurity**: # # **gini impurity** = 1 - gini = 0.665. # # Harhaanjohtavasti kaaviossa käytetään nimitystä **gini** vaikka kyseessä on **gini impurity**. Päätöspuu-algoritmi määrittää haarautumiskohdat siten että päästään mahdollisimman pieniin gini impurity -arvoihin. # # Jos en käytä mallin sovituksessa kiinteää **random_state**-parametrin arvoa, niin eri suorituskerroilla päätöspuussa voi olla toisistaan poikkeavia päätössääntöjä. # ## Mallin käyttö ennustamiseen # In[12]: # Avaan uuden datan, jossa lajikkeet (species) eivät ole tiedossa # Datassa täytyy olla samat selittävät muuttujat kuin mallia opetettaessa Xnew = pd.read_excel('https://taanila.fi/irisnew.xlsx') Xnew # Ennusteet voin laskea **predict**-funktiolla. # # Todennäköisyydet voin laskea **predict_proba**-funktiolla. Funktio palautta todennäköisyyden jokaiselle kategorialla (tässä kolmelle lajikkeelle). # In[13]: # Lasken ennusteet ennuste = malli.predict(Xnew) # Lasken todennäköisyydet todnak = malli.predict_proba(Xnew).round(2) # Lisään ennusteet ja todennäköisyydet dataan Xnew['ennuste'] = ennuste Xnew[['tn_setosa', 'tn_versicolor', 'tn_virginica']] = todnak Xnew # Ensimmäinen ja viimeinen ennustetaan setosaksi, toinen virginicaksi. Tässä ennusteet olivat lähes varmoja (todennäköisyys 1 eli 100 %). # ## Lisätietoa # # Päätöspuu sklearn-kirjaston käyttöoppaassa: https://scikit-learn.org/stable/modules/tree.html#tree # # Päätöspuun dokumentaatio sklearn-kirjastossa: https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html # # Data-analytiikka Pythonilla: https://tilastoapu.wordpress.com/python/