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.
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.
# Aloitetaan lukemalla data-ainesto ja tarkastellaan mistä se koostuu,
df_wines=pd.read_excel(wines_data)
df_wines
| 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
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
df_wines.describe()
| 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 :
- Alcohol
- Malic acid
- Ash
- Alcalinity of ash
- Magnesium
- Total phenols
- Flavanoids
- Nonflavanoid phenols
- Proanthocyanins
- Color intensity
- Hue
- OD280/OD315 of diluted wines
- 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ä).
# 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
| 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.
df_wines['Grape'].value_counts()
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.
# 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'])
<seaborn.axisgrid.PairGrid at 0x1f386a79f30>
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
# 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ä.
# 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
# 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
Sija : 2 Luokittelumalli : Satunnaismetsä Luokittelumallin tarkkuus testidatasta: 100.00 Luokittelumallin tarkkuus opetusdatasta: 100.00 Sekaannusmatriisi
Sija : 3 Luokittelumalli : Harjanne regressio Luokittelumallin tarkkuus testidatasta: 97.78 Luokittelumallin tarkkuus opetusdatasta: 100.00 Sekaannusmatriisi
Sija : 4 Luokittelumalli : Päätöspuu Luokittelumallin tarkkuus testidatasta: 95.56 Luokittelumallin tarkkuus opetusdatasta: 100.00 Sekaannusmatriisi
Sija : 5 Luokittelumalli : Gradientitehostus Luokittelumallin tarkkuus testidatasta: 86.67 Luokittelumallin tarkkuus opetusdatasta: 100.00 Sekaannusmatriisi
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.
# Aloitetaan lukemalla data-aineisto ja tarkastellaan mitä se sisältää.
df_concrete = pd.read_excel(concrete_data)
df_concrete
| 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
df_concrete.describe()
| 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 |
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ää.
correlation_matrix = df_concrete.corr().round(2)
sns.heatmap(data=correlation_matrix, annot=True)
<Axes: >
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
# 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.
# 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
# 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
Sija : 2 Regressiomalli : Gradienttitehostus-regressio Regressiomallin tarkkuus testidatasta: 81.84 Regressiomallin tarkkuus opetusdatasta: 89.00 Regressionmallin tulokset kaavioina
Sija : 3 Regressiomalli : Lineaarinen-regressio Regressiomallin tarkkuus testidatasta: 53.23 Regressiomallin tarkkuus opetusdatasta: 48.74 Regressionmallin tulokset kaavioina
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.