In [710]:
from datetime import datetime
print(f'Päivitetty {datetime.now().strftime('%d.%m.%Y')} / Tatu Erkinjuntti')
Päivitetty 06.12.2024 / Tatu Erkinjuntti

Tehtävä 3, koneoppiminen¶

Osa 1 - luokittelumalli¶

Valitse jompikumpi seuraavista datoista (löytyvät data-kansiosta alla) tai vaihtoehtoisesti käytä omaa dataa. Kokeile vähintään kahta luokittelumallia ja vertaile mallien paremmuutta.

Datoja¶

Viinien luokittelu rypälelajikkeen mukaan (luokittelu) Wine.xlsx¶

Eri rypälelajikkeista valmistettuja viinejä. Kokeile miten eri luokittelumallit osaavat tunnistaa viinin ominaisuuksien perusteella rypälelajikkeen (Y), josta viini on valmistettu.

Lähde: https://archive.ics.uci.edu/ml/datasets/Wine

Data aukeaa komennolla df=pd.read_excel('wine.xlsx')

Ostavien asiakkaiden tunnistaminen (luokittelu) KidCreative.xlsx¶

Voiko taustamuuttujien perusteella tunnistaa asiakkaat, jotka ostavat tietyn tuotteen. Obs no. -muuttuja pitää pudottaa pois ennen mallin laskemista.

Data aukeaa komennolla df = pd.read_excel('KidCreative.xlsx')

Osa 2 - regressiomalli¶

Valitse jokin seuraavista datoista (löytyvät data-kansiosta) tai vaihtoehtoisesti voit käyttää omaa dataa. Valitse tilanteeseen sopivat selittävät muuttujat (perustele valintasi), laadi regressiomalli ja arvioi mallin hyvyyttä.

Datoja¶

Betonin lujuuteen vaikuttavia tekijöitä (regressio) Concrete_Data.xlsx¶

Lähde: https://archive.ics.uci.edu/ml/datasets/Concrete+Compressive+Strength

Data aukeaa komennolla df=pd.read_excel('Concrete_Data.xlsx')

Valitse selitettäväksi muuttujaksi 'Concrete compressive strength(MPa, megapascals) '

Energiatehokkuuteen vaikuttavia tekijöitä (regressio) ENB2012_data.xlsx¶

Lähde: https://archive.ics.uci.edu/ml/datasets/Energy+efficiency

Data aukeaa komennolla df=pd.read_excel('ENB2012_data.xlsx')

Valitse selitettäväksi muuttujaksi Y1 tai Y2.

Tehtävissä 1 ja 2 esiintynyt kunnat-data (regressio) kunnat.xlsx¶

Lähde: Tilastokeskus. Tietoa Suomen kunnista.

Ota selitettävksi muuttujaksi 'Sosiaali- ja terveystoiminta yhteensä, nettokäyttökustannukset, euroa/asukas, 2020' ja valitse muutama selittävä muuttuja, joita käyttäen saat regressomallille mahdollisimman korkean selityskertoimen.

Tehtävän alustus¶

Haetaan tarvittavat kirjastot ja määritellään käytetyt data-aineistot. Itse teen tämän aina kerralla ohjelman alussa, näin yhdellä silmäyksellä näkee ohjelman riippuvaisuudet. Jos käytössä olisi pysyviä muuttujia, tulisi ne myös alustaa samalla.

In [711]:
import pandas as pd 
import matplotlib.pyplot as plt 
import seaborn as sns

# train_test_split jakaa datan opetusdataan ja testidataan
from sklearn.model_selection import train_test_split

from sklearn.linear_model import LogisticRegression, LinearRegression, RidgeClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, GradientBoostingRegressor, RandomForestRegressor

# 'Sekaannus'-matriisin näyttämiseen
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay

%matplotlib inline

wines_data = '../Data/wine.xlsx'
concrete_data = '../Data/Concrete_Data.xlsx'

Osa 1 - luokittelumalli - Viinien luokittelu rypälelajikkeen mukaan¶

Ennen siirtymistäni IT-alalle, tein pitkän uran ravintola-alalla. Tästä syystä viinien luokittelu tuntui suorastaan luontevalta.

In [712]:
# Aloitetaan lukemalla data-ainesto ja tarkastellaan mistä se koostuu,
df_wines=pd.read_excel(wines_data)
df_wines
Out[712]:
Y X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13
0 1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
1 1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
2 1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
3 1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
4 1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93 735
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
173 3 13.71 5.65 2.45 20.5 95 1.68 0.61 0.52 1.06 7.70 0.64 1.74 740
174 3 13.40 3.91 2.48 23.0 102 1.80 0.75 0.43 1.41 7.30 0.70 1.56 750
175 3 13.27 4.28 2.26 20.0 120 1.59 0.69 0.43 1.35 10.20 0.59 1.56 835
176 3 13.17 2.59 2.37 20.0 120 1.65 0.68 0.53 1.46 9.30 0.60 1.62 840
177 3 14.13 4.10 2.74 24.5 96 2.05 0.76 0.56 1.35 9.20 0.61 1.60 560

178 rows × 14 columns

In [713]:
df_wines.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 14 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   Y       178 non-null    int64  
 1   X1      178 non-null    float64
 2   X2      178 non-null    float64
 3   X3      178 non-null    float64
 4   X4      178 non-null    float64
 5   X5      178 non-null    int64  
 6   X6      178 non-null    float64
 7   X7      178 non-null    float64
 8   X8      178 non-null    float64
 9   X9      178 non-null    float64
 10  X10     178 non-null    float64
 11  X11     178 non-null    float64
 12  X12     178 non-null    float64
 13  X13     178 non-null    int64  
dtypes: float64(11), int64(3)
memory usage: 19.6 KB
In [714]:
df_wines.describe()
Out[714]:
Y X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13
count 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000 178.000000
mean 1.938202 13.000618 2.336348 2.366517 19.494944 99.741573 2.295112 2.029270 0.361854 1.590899 5.058090 0.957449 2.611685 746.893258
std 0.775035 0.811827 1.117146 0.274344 3.339564 14.282484 0.625851 0.998859 0.124453 0.572359 2.318286 0.228572 0.709990 314.907474
min 1.000000 11.030000 0.740000 1.360000 10.600000 70.000000 0.980000 0.340000 0.130000 0.410000 1.280000 0.480000 1.270000 278.000000
25% 1.000000 12.362500 1.602500 2.210000 17.200000 88.000000 1.742500 1.205000 0.270000 1.250000 3.220000 0.782500 1.937500 500.500000
50% 2.000000 13.050000 1.865000 2.360000 19.500000 98.000000 2.355000 2.135000 0.340000 1.555000 4.690000 0.965000 2.780000 673.500000
75% 3.000000 13.677500 3.082500 2.557500 21.500000 107.000000 2.800000 2.875000 0.437500 1.950000 6.200000 1.120000 3.170000 985.000000
max 3.000000 14.830000 5.800000 3.230000 30.000000 162.000000 3.880000 5.080000 0.660000 3.580000 13.000000 1.710000 4.000000 1680.000000

Rehellisesti Data-aineisto ei ollut ihan siinä muodossa kuin olisin äkkiseltäni odottanut. Y kertoo viinissä käytetyn rypäleen ja X-arvot kertovat viinin omainaisuuksista.

Voitaisiin aloittaa tämä tehtävä hieman kaunistamalla tätä data-aineistoa. Hieman tutkin lähdemateriaalia ja sain kun sainkin tietoon mitä X1...13 arvot on :

  1. Alcohol
  2. Malic acid
  3. Ash
  4. Alcalinity of ash
  5. Magnesium
  6. Total phenols
  7. Flavanoids
  8. Nonflavanoid phenols
  9. Proanthocyanins
  10. Color intensity
  11. Hue
  12. OD280/OD315 of diluted wines
  13. Proline

Aloitetaan siis päivittämällä hieman data-aineiston nimiä, jotta sitä on mukavampi katsella. Pitäydytään Englannin kielessä, koska meillä ei nyt oikeastaan ole mitään painavaa syytä käyttää Suomea data-aineiston nimissä. Y arvo nimetään muotoon Grape.

describe funktio kertoo meille että data-aineistossa on käytetty vain kolmea rypälettä. Houkutus olisi kovin suuri muuttaa näidenkin nimeämistä, mutta ei tehdä sitä vielä, sillä tähän ei varsinaisesti ole tarvetta tässä vaiheessa. Tehdään silti tulosten tarkastelua varten rypäleiden nimeämiset, jotta aineisto olisi helpommin luettavissa.

Lajikkeita en tähän löytänyt, joten voisimme käyttää esimerkiksi: 1 : Merlot, 2 : Sangiovese, 3 : Nebbiolo (päättelin alkoholi prosentista ja fenoleista että nämä ovat todennäköisesti punaviinejä).

In [715]:
# Luodaan dictionary muuttuja johon syötetään muutokset. 
# Teen tämän on puhtaasti luettavuuden takia, nämä voi myös syöttää yhtenä pötkönä rename() funktioon mutta siitä tulee silloin niin ikävän pitkä.
rename_dict = {
    'Y': 'Grape',
    'X1': 'Alcohol',
    'X2': 'Malic acid',
    'X3': 'Ash',
    'X4': 'Alcalinity of ash',
    'X5': 'Magnesium',
    'X6': 'Total phenols',
    'X7': 'Flavanoids',
    'X8': 'Nonflavanoid phenols',
    'X9': 'Proanthocyanins',
    'X10': 'Color intensity',
    'X11': 'Hue',
    'X12': 'OD280/OD315 of diluted wines',
    'X13': 'Proline '    
    }

# Muutetaan sarakkeiden nimet. Tehdään muutokset suoraan dataframeen (inplace=True)
df_wines.rename(columns = rename_dict, inplace=True)

# Luodaan taas lista viinirypäleiden nimistä, jota käytetään tulosten esittämisessä.
grape_names = ['Merlot', 'Sangiovese','Nebbiolo']

# Tarkastetaan muuokset
df_wines
Out[715]:
Grape Alcohol Malic acid Ash Alcalinity of ash Magnesium Total phenols Flavanoids Nonflavanoid phenols Proanthocyanins Color intensity Hue OD280/OD315 of diluted wines Proline
0 1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
1 1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
2 1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
3 1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
4 1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93 735
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
173 3 13.71 5.65 2.45 20.5 95 1.68 0.61 0.52 1.06 7.70 0.64 1.74 740
174 3 13.40 3.91 2.48 23.0 102 1.80 0.75 0.43 1.41 7.30 0.70 1.56 750
175 3 13.27 4.28 2.26 20.0 120 1.59 0.69 0.43 1.35 10.20 0.59 1.56 835
176 3 13.17 2.59 2.37 20.0 120 1.65 0.68 0.53 1.46 9.30 0.60 1.62 840
177 3 14.13 4.10 2.74 24.5 96 2.05 0.76 0.56 1.35 9.20 0.61 1.60 560

178 rows × 14 columns

No niin, nyt näyttää nimeämiset paremmalta. Tarkastellaan vielä hieman miten rypäleet jakautuvat aineistossa.

In [716]:
df_wines['Grape'].value_counts()
Out[716]:
Grape
2    71
1    59
3    48
Name: count, dtype: int64

Kohdemuuttujien jako on ihan OK, ei liian epätasainen, vaikka tietenkin se voisi olla tasaisempi.

Nyt kun aineisto on helpommin luettavissa, niin tarkastellaan hieman sitä hajontakaavion avulla.

In [717]:
# määritellään hajontakaavioon erojakorostavat värit, taulu kelpaa nyt koska rypäleiden arvot ovat numeraaliset,
# string-muutujien kanssa tulisi dictionary:a 
sns.pairplot(df_wines, hue='Grape', palette=['tab:blue', 'tab:green', 'tab:red'])
Out[717]:
<seaborn.axisgrid.PairGrid at 0x1f386a79f30>
No description has been provided for this image

Pääasiassa rypäleet erottuvat kyllä, mutta ovat hieman enemmän limittäin kuin toivoisi, alkoholipitoisuus, kokonais fenolien määärä ("total phenols") ja flavonoidit korostavat eri rypäleitä paremmin. Katsotaan miten eri luokittelumallit onnistuvat tunnistaa rypäleet. Koska rypäleiden välillä on havaittavissa eroja niiden ominaisuuksien osalta, en tee erikseen erottelua selittävästä muuttujasta, vaan aineistossa käytetään kaikkia ominaisuuksia selittävänä muuttujana

In [718]:
# train_test_split function random state parametrin random seed voi olla numeraalinen arvo väliltä 0 - 42.
# Koska Douglas Adams on hieno mies ja hänen vastauksensa elämälle sattuu olemaan sama kuin ikäni nyt, käytetään arvoa 42.

# Määritellään random seed omaksi muuttujaksi, joten voidaan tarvittaessa testata miten sen muuttaminen vaikuttaa tuloksiin.
random_seed = 42

# train_test_split funktion parametrit : selittävät muuttujat, kohdemuuttuja, random_seed
wines_x_training_data, wines_x_testing_data, wines_y_training_data, wines_y_testing_data = train_test_split(df_wines.drop('Grape', axis=1), df_wines['Grape'], random_state=random_seed)

Koska olen eri luokittelumallien tuloksista kovin utelias, niin käytetään tähän viittä eri luokittelumallia

  • Logistinen regressio
  • Harjanne regressio (Ridge-regressio)
  • Päätöspuu
  • Satunnaismetsä
  • Gradientitehostus

Jotta voidaan hieman hifistellä, tehdään erikseen funkti joka käsittelee eri luokittelumallit sekä koulutus ja testidatan ja antaa antaa meille tulokset niistä.

In [719]:
# Tehdään vertalilua varten oma funktionsa.
# Funktion parametreina on (dict) luokittelumalleista, koulutus- ja testidatasta sanakirjoina ja viinirypäleiden nimet listana.
# määritellään funktion parametreihin sen tarvitsevt muuttujat, jotta ei tarvitse luottaa "globaalien" muuttujiin.
def compare_classification_model(models, training_data, testing_data, display_names):

    #Valmistellaan mallit
    for value in models.values():
        #sovitetaan mallit opetusdataan
        value['model'].fit(training_data[0], training_data[1])
        # Pisteytetään arvioinnin tarkkuus
        value['score'] = value['model'].score(testing_data[0],testing_data[1])
    
    # Järjestetään dictionary arvojen mukaan
    models_sorted = dict(sorted(models.items(), key=lambda item: item[1]['score'], reverse=True))

    #Tulosteaan mallit paremmuus järjestyksessä ja tehdään niistä sekaannusmatriisi.
    print('Luokittelu mallien tulokset, mikä on tarkin testidatan perusteella?\n')
    i = 1
    for key, value in models_sorted.items():
        print(f'Sija : {i}\n')
        print(f'Luokittelumalli : {key}')
        print(f'Luokittelumallin tarkkuus testidatasta: {(value['score']*100):.2f}')
        print(f'Luokittelumallin tarkkuus opetusdatasta: {(value['model'].score(training_data[0], training_data[1])*100):.2f}\n')
        print('Sekaannusmatriisi')
        cm = confusion_matrix(testing_data[1], value['model'].predict(testing_data[0]))
        disp = ConfusionMatrixDisplay(confusion_matrix = cm, display_labels=display_names)
        disp.plot()
        plt.title(f'Luokittelumalli : {key}')
        plt.show()
        i+=1
In [ ]:
# Tehdään sanakirja eri luokittelumalleja varten.
classification_model = {}
# HUOM! En käytä eri luokittelumalleista lyhentteitä, jotta koodi olisi helpommin luettavissa.

# Tätä tehdessä kävi ilmi että data-aineisto olikin sen verran iso, että LogisticRegression funktion
# iterointi määrää piti nostaa oletuksesta (100) huomattavasti.
# Tämä siis antaa virheen " STOP: TOTAL NO. of ITERATIONS REACHED LIMIT. " suorituksessa.
classification_model['Logistinen regressio'] = {'model':LogisticRegression(random_state=random_seed, max_iter=10000)}

# Määritellään harjanneregressiolle samat arvot kuin lineeriselle regressiolle. 
classification_model['Harjanne regressio'] = {'model':RidgeClassifier(random_state=random_seed, max_iter=10000)}

# Ei määritellä Päätöspuulle, satunnaismetsälle tai gradientitehostukselle syvyyttä, vaan oletaan että se on "none".
# Oletuksella tämä on "none" päätöspuussa ja satunnaismetsässä mutta gradientitehostuksessa oletus on 3.
# Käytännössä tämä määrittelee paljon kerroksia muodostetaan, jos arvo on "none" niin niitä tulee sen mukaan miten materiaalia on.
# Manuaalista lainattuna : If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples.
# Koska tarkoitus ei ole yritää ennustaa tulevaa vaan luokitella, en koe että ylimallennuksella olisi tähän negatiivista vaikutusta tähän.

classification_model['Päätöspuu'] =  {'model':DecisionTreeClassifier(max_depth=None, random_state=random_seed)}
classification_model['Satunnaismetsä'] = {'model':RandomForestClassifier(max_depth=None, random_state=random_seed)}
classification_model['Gradientitehostus'] = {'model':GradientBoostingClassifier(max_depth=None, random_state=random_seed)}

# Syötetään vertailufunktiolle luokittelumallit, koulutus sekä testidata ja tulosteita varten rypäleiden nimet joita halutaan käyttää.
compare_classification_model(classification_model, [wines_x_training_data, wines_y_training_data], [wines_x_testing_data, wines_y_testing_data], grape_names)
Luokittelu mallien tulokset, mikä on tarkin testidatan perusteella?

Sija : 1

Luokittelumalli : Logistinen regressio
Luokittelumallin tarkkuus testidatasta: 100.00
Luokittelumallin tarkkuus opetusdatasta: 99.25

Sekaannusmatriisi
No description has been provided for this image
Sija : 2

Luokittelumalli : Satunnaismetsä
Luokittelumallin tarkkuus testidatasta: 100.00
Luokittelumallin tarkkuus opetusdatasta: 100.00

Sekaannusmatriisi
No description has been provided for this image
Sija : 3

Luokittelumalli : Harjanne regressio
Luokittelumallin tarkkuus testidatasta: 97.78
Luokittelumallin tarkkuus opetusdatasta: 100.00

Sekaannusmatriisi
No description has been provided for this image
Sija : 4

Luokittelumalli : Päätöspuu
Luokittelumallin tarkkuus testidatasta: 95.56
Luokittelumallin tarkkuus opetusdatasta: 100.00

Sekaannusmatriisi
No description has been provided for this image
Sija : 5

Luokittelumalli : Gradientitehostus
Luokittelumallin tarkkuus testidatasta: 86.67
Luokittelumallin tarkkuus opetusdatasta: 100.00

Sekaannusmatriisi
No description has been provided for this image

Analyysi¶

Logistinen regressio ja satunnaismetsä luokittelevat tarkimmin (100%) testidatasta. Yllättävää kyllä Logistinen regressio ei ollut niin tarkka kun luokittelu tehtiin opetusdatasta. Harjanne regressio antaa erheellisen arvion vain yhdessä tapauksessa. Päätöspuu antaa erheellisen vastauksen kahdessa (2) tapauksessa testidatasta. Gradientitehostus antaa eniten virheitä ennusteessa, kuusi (6) virheellistä vastausta.

Lyhyesti voi todeta että tässä tapauksessa satunnaismetsä luokittelumalli sopii parhaiten tunnistamaan viinirypäleet niiden ominaisuuksien perusteella. Logistinen regressio regressio voisi olla toinen hyvä vaihtoehto, mutta epätarkkuus opetusdatan luokitellussa vei siltä ykköspaikan.

Osa 2 - regressiomalli - Betonin lujuuteen vaikuttavia tekijöitä¶

Tausta tämän kyseisen data-aineiston valintaan johtuu oikeastaan rakentamiseen liittyvästä perin mielenkiintoisesta argumentista. Aikaisemassa työssäni erään kohteen aloitus myöhästyi useammalla kuukaudella ja selite tälle oli että 'Betoni ei ole kuivunut kunnolla, odotettu jo vuosi', vaikka voisi luulla että tämä olisi ollut vitsi, niin tämä näytti olevan se virrallinen vastausta rakennuttajalta. Tästä syystä olen perin utelias tietämään mikä vaikuuttaa Betonin lujuuteen.

In [721]:
# Aloitetaan lukemalla data-aineisto ja tarkastellaan mitä se sisältää.
df_concrete = pd.read_excel(concrete_data)
df_concrete
Out[721]:
Cement (component 1)(kg in a m^3 mixture) Blast Furnace Slag (component 2)(kg in a m^3 mixture) Fly Ash (component 3)(kg in a m^3 mixture) Water (component 4)(kg in a m^3 mixture) Superplasticizer (component 5)(kg in a m^3 mixture) Coarse Aggregate (component 6)(kg in a m^3 mixture) Fine Aggregate (component 7)(kg in a m^3 mixture) Age (day) Concrete compressive strength(MPa, megapascals)
0 540.0 0.0 0.0 162.0 2.5 1040.0 676.0 28 79.986111
1 540.0 0.0 0.0 162.0 2.5 1055.0 676.0 28 61.887366
2 332.5 142.5 0.0 228.0 0.0 932.0 594.0 270 40.269535
3 332.5 142.5 0.0 228.0 0.0 932.0 594.0 365 41.052780
4 198.6 132.4 0.0 192.0 0.0 978.4 825.5 360 44.296075
... ... ... ... ... ... ... ... ... ...
1025 276.4 116.0 90.3 179.6 8.9 870.1 768.3 28 44.284354
1026 322.2 0.0 115.6 196.0 10.4 817.9 813.4 28 31.178794
1027 148.5 139.4 108.6 192.7 6.1 892.4 780.0 28 23.696601
1028 159.1 186.7 0.0 175.6 11.3 989.6 788.9 28 32.768036
1029 260.9 100.5 78.3 200.6 8.6 864.5 761.5 28 32.401235

1030 rows × 9 columns

In [722]:
df_concrete.describe()
Out[722]:
Cement (component 1)(kg in a m^3 mixture) Blast Furnace Slag (component 2)(kg in a m^3 mixture) Fly Ash (component 3)(kg in a m^3 mixture) Water (component 4)(kg in a m^3 mixture) Superplasticizer (component 5)(kg in a m^3 mixture) Coarse Aggregate (component 6)(kg in a m^3 mixture) Fine Aggregate (component 7)(kg in a m^3 mixture) Age (day) Concrete compressive strength(MPa, megapascals)
count 1030.000000 1030.000000 1030.000000 1030.000000 1030.000000 1030.000000 1030.000000 1030.000000 1030.000000
mean 281.165631 73.895485 54.187136 181.566359 6.203112 972.918592 773.578883 45.662136 35.817836
std 104.507142 86.279104 63.996469 21.355567 5.973492 77.753818 80.175427 63.169912 16.705679
min 102.000000 0.000000 0.000000 121.750000 0.000000 801.000000 594.000000 1.000000 2.331808
25% 192.375000 0.000000 0.000000 164.900000 0.000000 932.000000 730.950000 7.000000 23.707115
50% 272.900000 22.000000 0.000000 185.000000 6.350000 968.000000 779.510000 28.000000 34.442774
75% 350.000000 142.950000 118.270000 192.000000 10.160000 1029.400000 824.000000 56.000000 46.136287
max 540.000000 359.400000 200.100000 247.000000 32.200000 1145.000000 992.600000 365.000000 82.599225
In [723]:
df_concrete.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1030 entries, 0 to 1029
Data columns (total 9 columns):
 #   Column                                                 Non-Null Count  Dtype  
---  ------                                                 --------------  -----  
 0   Cement (component 1)(kg in a m^3 mixture)              1030 non-null   float64
 1   Blast Furnace Slag (component 2)(kg in a m^3 mixture)  1030 non-null   float64
 2   Fly Ash (component 3)(kg in a m^3 mixture)             1030 non-null   float64
 3   Water  (component 4)(kg in a m^3 mixture)              1030 non-null   float64
 4   Superplasticizer (component 5)(kg in a m^3 mixture)    1030 non-null   float64
 5   Coarse Aggregate  (component 6)(kg in a m^3 mixture)   1030 non-null   float64
 6   Fine Aggregate (component 7)(kg in a m^3 mixture)      1030 non-null   float64
 7   Age (day)                                              1030 non-null   int64  
 8   Concrete compressive strength(MPa, megapascals)        1030 non-null   float64
dtypes: float64(8), int64(1)
memory usage: 72.6 KB

Jotta vaihdaan päättää mitä selittäviä muuttujia käytettäisiin regressiomallia, voitaisiin tutkia rippuvuuksien korrelaatiota. Oletan että tehtävänannossa kohdemuuttujaksi, ei selittäväksi muuttujaksi on tarkoitettu tuo "Concrete compressive strength(MPa, megapascals)", sillä tätä haluamme selvittää.

In [724]:
correlation_matrix = df_concrete.corr().round(2)
sns.heatmap(data=correlation_matrix, annot=True)
Out[724]:
<Axes: >
No description has been provided for this image

Sementin määrällä, Superpehmitin (paras suomennos mitä löysin sanalle Superplasticizer) ja ajalla on selkeä positiivinen korrelaattio betonin lujuuden kanssa. Veden määrällä on selkeästi negatiivinen korretaalio betonin lujuuden kanssa (vähemmän vettä, lujempaa betonia), joten otetaan nämä mukaan selittäviksi muuttujiksi. Todettakoon että otannan raja on että korrelaatiokerroin on joko alle -0.25 (negatiivinen) tai yli 0.25 (positiivinen).

Aloitetaan muodostamalla koulutus ja testidata

In [ ]:
# train_test_split funktion parametrit : valitut selittävät muuttuja, kohdemuuttuja, random_seed
# käytetään samaa random_seed arvoa kuin edellisessä tehtävässä.

concrete_x_training_data, concrete_x_testing_data, concrete_y_training_data, concrete_y_testing_data = train_test_split(df_concrete[['Cement (component 1)(kg in a m^3 mixture)','Water  (component 4)(kg in a m^3 mixture)','Superplasticizer (component 5)(kg in a m^3 mixture)','Age (day)']], df_concrete['Concrete compressive strength(MPa, megapascals) '], random_state=random_seed)

Koska meillä on mahdollista käyttää useampaa eri regressiomallia, niin voitaisiin tehdä samanlainen funktio kuin aikaisemassa tehtävässä. Voidaan kokeilla useampaa eri mallia jotta voidaan niiden eroja arvioida paremmin. Pyritään pitämään funktion pääasiallinen rakenne samanlaisena.

In [726]:
# Tehdään vertalilua varten oma funktionsa.
# Funktion parametreina on (dict) luokittelumalleista, koulutus- ja testidatasta sanakirjoina ja viinirypäleiden nimet listana.
# määritellään funktion parametreihin sen tarvitsevt muuttujat, jotta ei tarvitse luottaa "globaalien" muuttujiin.
def compare_regression_model(models, training_data, testing_data):

    #Valmistellaan mallit
    for value in models.values():
        #sovitetaan mallit opetusdataan
        value['model'].fit(training_data[0], training_data[1])
        # Pisteytetään arvioinnin tarkkuus
        value['score'] = value['model'].score(testing_data[0],testing_data[1])
    
    # Järjestetään dictionary arvojen mukaan
    models_sorted = dict(sorted(models.items(), key=lambda item: item[1]['score'], reverse=True))

    #Tulosteaan mallit paremmuus järjestyksessä ja tehdään niistä sekaannusmatriisi.
    print('Regressiomallien tulokset, mikä on tarkin testidatan peruteella?\n')
    i = 1
    for key, value in models_sorted.items():
        print(f'Sija : {i}\n')
        print(f'Regressiomalli : {key}')
        print(f'Regressiomallin tarkkuus testidatasta: {(value['score']*100):.2f}')
        print(f'Regressiomallin tarkkuus opetusdatasta: {(value['model'].score(training_data[0], training_data[1])*100):.2f}\n')
        print('Regressionmallin tulokset kaavioina\n')

        # Opetusdatan virhetermit kaaviona
        fig, ax = plt.subplots(1, 2, figsize=(10, 4))
        ax[0].set_title('Ennustevirheiden jakauma opetusdatassa')
        sns.histplot((training_data[1]-value['model'].predict(training_data[0])), kde=True, ax=ax[0])
        ax[0].set_xlabel('Opetusdata - Opetusdatan ennuste')

        # toteutuneet ja ennustetut hajontakaaviona testidatalle
        ax[1].set_title('Ennusteen tarkkuus testidatasta')
        ax[1].scatter(x=testing_data[1], y=value['model'].predict(testing_data[0]))
        ax[1].set_xlabel('toteutunut')
        ax[1].set_ylabel('ennuste')
        
        plt.show()
       
        
        i+=1

Valitaan kokeiltavaksi:

  • Lineaarinen regressio
  • Satunnaismetsä regressio
  • Gradientitehostus regressio
In [727]:
# Tehdään sanakirja eri regressiomalleja varten.
regression_model = {}
# HUOM! En käytä eri luokittelumalleista lyhentteitä, jotta koodi olisi helpommin luettavissa.

regression_model['Lineaarinen-regressio'] = {'model':LinearRegression()}
regression_model['Satunnaismetsä-regressio'] = {'model':RandomForestRegressor()}
regression_model['Gradienttitehostus-regressio'] = {'model':GradientBoostingRegressor()}


# Syötetään vertailufunktiolle luokittelumallit, koulutus sekä testidata ja tulosteita varten rypäleiden nimet joita halutaan käyttää.
compare_regression_model(regression_model, [concrete_x_training_data, concrete_y_training_data], [concrete_x_testing_data, concrete_y_testing_data])
Regressiomallien tulokset, mikä on tarkin testidatan peruteella?

Sija : 1

Regressiomalli : Satunnaismetsä-regressio
Regressiomallin tarkkuus testidatasta: 84.40
Regressiomallin tarkkuus opetusdatasta: 97.46

Regressionmallin tulokset kaavioina

No description has been provided for this image
Sija : 2

Regressiomalli : Gradienttitehostus-regressio
Regressiomallin tarkkuus testidatasta: 81.84
Regressiomallin tarkkuus opetusdatasta: 89.00

Regressionmallin tulokset kaavioina

No description has been provided for this image
Sija : 3

Regressiomalli : Lineaarinen-regressio
Regressiomallin tarkkuus testidatasta: 53.23
Regressiomallin tarkkuus opetusdatasta: 48.74

Regressionmallin tulokset kaavioina

No description has been provided for this image

Satunnaismetsä osoittautui taas tarkimmaksi kolmesta kokeillusta regressiomallista. Kokeilin hieman muutella selittäviä muuttujia tarkkuus testidatassa ei muuttunut merkittävästi ja koen että valitut muuttujat ovat korrelaationsa ansiosta perusteltuja.