from datetime import datetime
print(f'Päivitetty {datetime.now().date()} / Aki Taanila')
Päivitetty 2024-04-02 / Aki Taanila
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
# Tuon lineaarisen regressiomallin
from sklearn.linear_model import LinearRegression
# Perinteisempään regressio-statistiikkaan tarvitsen statsmodels-kirjastoa
import statsmodels.api as sm
# Avaan datan (kesämökkien hintoja tuhansina euroina)
df = pd.read_excel('http://taanila.fi/mokki.xlsx')
df
nro | ranta | pinta-ala | sähkö | hinta | |
---|---|---|---|---|---|
0 | 1 | 30 | 50 | 0 | 95 |
1 | 2 | 35 | 42 | 0 | 95 |
2 | 3 | 40 | 25 | 1 | 80 |
3 | 4 | 50 | 30 | 1 | 100 |
4 | 5 | 55 | 45 | 0 | 135 |
5 | 6 | 60 | 24 | 1 | 100 |
6 | 7 | 60 | 60 | 1 | 210 |
7 | 8 | 70 | 34 | 1 | 160 |
8 | 9 | 80 | 32 | 0 | 150 |
9 | 10 | 85 | 28 | 0 | 150 |
# Riippuvuuksien tarkastelua seaborn-kirjaston hajontakaavioina
sns.pairplot(df, kind='reg')
<seaborn.axisgrid.PairGrid at 0x1f727134d70>
# Riippuvuuksien tarkastelua korrelaatiokertoimien avulla
correlation_matrix = df.corr().round(2)
sns.heatmap(data=correlation_matrix, annot=True)
<Axes: >
# Selittävät muuttujat
X = df[['ranta', 'pinta-ala', 'sähkö']]
# Ennustettava muuttuja
y = df['hinta']
malli = LinearRegression().fit(X,y)
malli.coef_ # regressiosuoran kulmakerroin
array([ 1.9750098 , 2.77578415, 20.29877373])
Esimerkiksi rantaviivan kulmakertoimesta näemme: Jos muut tekijät pysyvät vakiona, niin 1 metri lisää rantaviivaa kasvattaa mallin mukaan hintaa noin 2 yksiköllä (2000 tuhatta euroa).
malli.intercept_ # regressiosuoran vakiotermi
-96.94145434036429
malli.score(X,y) # selityskerroin
0.9819136190845802
Selityskertoimen mukaan noin 98 % hintojen vaihtelusta voidaan selittää selittävien muuttujien vaihtelulla.
# Mallin virhetermit pistekaaviona
plt.scatter(malli.predict(X), malli.predict(X) - y)
# Vaakaviiva nollapoikkeaman kohdalle
plt.hlines(y = 0, xmin = 50, xmax = 250)
plt.xlabel('Ennuste')
plt.ylabel('Poikkeama todellisesta')
# On hyvä jos virheet vaihtelevat sattumanvaraisesti nollan molemmin puolin
Text(0, 0.5, 'Poikkeama todellisesta')
# Todellisen hinnan ja mallin antamien ennusteiden vastaavuus pistekaaviona
plt.scatter(y, malli.predict(X))
plt.xlabel('Todellinen hinta')
plt.ylabel('Ennuste')
# On hyvä jos pisteet seuraavat suoraa viivaa vasemmasta alakulmasta oikeaan yläkulmaan
Text(0, 0.5, 'Ennuste')
# Perinteisempi regressio-statistiikka statsmodels-kirjastosta
# Seuraava rivi tarvitaan, jotta malliin lasketaan vakiotermi
X = sm.add_constant(X)
# Mallin sovitus (OLS = Ordinary Least Squares)
malli_sm = sm.OLS(y, X).fit()
print(malli_sm.summary())
# Kannattaa tarkistaa selittäviin muuttujiin liittyvät p-arvot P>|t| -sarakkeesta
# On hyvä jos p-arvot (sarake P>|t|) ovat pienempiä kuin 0.05
OLS Regression Results ============================================================================== Dep. Variable: hinta R-squared: 0.982 Model: OLS Adj. R-squared: 0.973 Method: Least Squares F-statistic: 108.6 Date: Tue, 02 Apr 2024 Prob (F-statistic): 1.29e-05 Time: 15:25:03 Log-Likelihood: -30.630 No. Observations: 10 AIC: 69.26 Df Residuals: 6 BIC: 70.47 Df Model: 3 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ const -96.9415 12.767 -7.593 0.000 -128.180 -65.702 ranta 1.9750 0.128 15.470 0.000 1.663 2.287 pinta-ala 2.7758 0.203 13.674 0.000 2.279 3.272 sähkö 20.2988 4.348 4.668 0.003 9.660 30.938 ============================================================================== Omnibus: 0.493 Durbin-Watson: 1.969 Prob(Omnibus): 0.782 Jarque-Bera (JB): 0.497 Skew: -0.087 Prob(JB): 0.780 Kurtosis: 1.922 Cond. No. 421. ============================================================================== Notes: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
C:\Users\akita\miniconda3\Lib\site-packages\scipy\stats\_stats_py.py:1971: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=10 k, _ = kurtosistest(a, axis)
# Avaan uuden datan, jossa samat muuttujat kuin selittävinä muuttujina
Xuudet = pd.read_excel('http://taanila.fi/mokkinew.xlsx')
Xuudet
ranta | pinta-ala | sähkö | |
---|---|---|---|
0 | 100 | 90 | 1 |
1 | 60 | 56 | 1 |
2 | 30 | 25 | 0 |
3 | 50 | 30 | 0 |
# Hintaennusteet
Xuudet['Hintaennuste'] = malli.predict(Xuudet)
Xuudet
ranta | pinta-ala | sähkö | Hintaennuste | |
---|---|---|---|---|
0 | 100 | 90 | 1 | 370.678873 |
1 | 60 | 56 | 1 | 197.301820 |
2 | 30 | 25 | 0 | 31.703444 |
3 | 50 | 30 | 0 | 85.082560 |
Data-analytiikka Pythonilla: https://tilastoapu.wordpress.com/python/