Generalisierte Regression#

Das Leben ist die Summe all unserer Entscheidungen

— Albert Camus

Folien#

Generalisierte Lineare Modelle#

Generalisierte Lineare Modelle (GLM) sind eine Verallgemeinerung der Linearen Modelle, die wir bereits kennen gelernt haben. Dadurch lassen sich zum Beispiel Lineare Regressionsmodelle und Logistische Regressionsmodelle kombinieren. Sie folgt im Wesentlichen der Idee, die wir schon bei der logistischen Regression kennen gelernt haben, dass wir eine lineare Basisfunktion \(z_i\) haben:

\[ z_i = \beta_0 + \beta_1\cdot x_{1,i} + \beta_2 \cdot x_{2,i} + \ldots + \beta_n\cdot x_{n,i}. \]

die wir über eine Verknüpfungsfunktion \(g(z_i)\) in eine Vorhersage unserer Zielvariable \(\hat z_i\) transformieren

\[ y_i = g(z_i) + \varepsilon. \]

Diese Verknüpfungsfunktion kann eine Sigmoid-Funktion sein (Logistische Regression), eine Exponential-Funktion (Poisson Regression), eine Gamma-Funktion (Gamma Regression) oder eine unverändertes \(z_i\) (Lineare Regression). Das Erlaubt je nach Verteilungstyp der Zielvariable Transformationen der Eingangsvariablen aus anderen Verteilungsformen vorzunehmen und somit Variablen, die eigentlich andere Verteilungsformen haben in einem Vorhersagemodell kombinieren. Somit muss der Vorhersagefehler \(\varepsilon\) auch nicht mehr Normalverteilt sein, sondern kann andere Verteilungsformen annehmen.

Das Entscheidende hierbei ist, dass die Basisfunktion \(z_i\) immer noch linear ist und nur transformiert wird, das bedeutet, dass wenn sich die unabhängigen Variable \(x_{k,i}\) ändert, sich auch die abhängige Variable \(y_i\) ändert, unabhängig vom Wert der anderen unabhängigen Variablen.

Die Koeffizienten \(\beta_0, \beta_1, \ldots, \beta_n\) werden auch hier durch die schon diskutierte Maximum-Likelihood-Schätzung (MLE) bestimmt und zum Beispiel durch das Newtonverfahren iterativ angenähert.

Generalisierte Additive Modelle#

Bisher wurde immer eine Lineare Beziehung zwischen den Eingangsvariablen und der Zielvariable angenommen. Das sorgt für Modelle mit einfach zu verstehenden Parametern \(\beta_0, \beta_1, \ldots, \beta_n\). Dadurch sind die Modelle einfach zu berechnen und auch Praktikern gut zu erklären.

Allerdings ist die Annahme eines linearen Zusammenhanges für viele praktische Szenarien nicht immer haltbar, da z.B. in der Physik nichtlineare Zusammenhänge häufig vorkommen. Deshalb haben sich Generalisierte Additive Modelle (GAM) entwickelt, die die Idee der Verknüpfungsfunktion aus GLM übernehmen aber direkt auf die additiven einzelnen Elemente der linearen Gleichung anwenden. Dadurch das resultierende Modell zwar additiv, wie das lineare Modell, aber nicht notwendigerweise linear, da jede einzelne Transformationsfunktion \(s_j(x_{j,i})\) nichtlinear sein kann.

\[ y_i = \beta_0 + s_1(x_{1,i}) + s_2(x_{2,i}) + \ldots + s_n(x_{n,i}) + \varepsilon = \beta_0 + \sum_{j=1}^n s_j(x_{j,i}) + \varepsilon. \]

Die Schwierigkeit besteht darin die Transformationsfunktion \(s_j(x_{j,i})\) in ihren Beiträgen zu \(y_i\) zu bestimmen. Hierfür nimmt man an, dass \(s_j(x_{j,i})\) eine glatte Funktion ist (stetig und beliebig oft differenzierbar (zum Fitting)). Hierfür werden meist Spline-Funktionen benutzt.

Viele moderne Implementierungen von GAMs nutzen zum Bestimmen der Transformationsfunktionen den Ansatz der Rankreduktion(Reduced-rank Minimization), da er eine schnelle Schätzung der Parameter ermöglicht. Hierfür wird für die Transformationsfunktion angenommen, dass sie ein Spline aus \(K_j\) Basisfunktionen ist, die gegeben ist durch

\[ s_j(x_j) = \sum_{k=1}^{K_j} \beta_{j,k} b_{j,k}(x_j) \]

wobei die \(b_{j,k}(x_j)\) bekannte Basisfunktionen sind, die in der Regel aufgrund guter Approximationseigenschaften gewählt werden (z.B. B-Splines) und die \(\beta_{j,k}\) Koeffizienten sind, die im Rahmen der Modellanpassung geschätzt werden müssen. Die Basisdimension \(K_j\) sollte dabei so gewählt werden, dass eine gute Anpassung der vorliegenden Daten zu erwarten ist, aber klein genug, um die Effizienz der Berechnung zu erhalten.

Durch ersetzen aller Transformationsfunktionen \(s_j(x_{j,i})\) durch Basisfunktionen, können diese in bekannter Weise durch Ableitung iterativ die Koeffizienten \(\beta_{j,k}\) bestimmen können.

\[ y_i = \beta_0 + \sum_{j=1}^n \sum_{k=1}^{K_j} \beta_{j,k} b_{j,k}(x_j) + \varepsilon. \]

GAM in Python mit Statsmodels#

Für GAM Modelle eignet sich insbesondere die statsmodels Bibliothek. Als Beispiel nutzen wir wieder den Energiedatensatz der Universität Rostock. Wir wollen noch einmal den Energiekonsum vorhersagen.

import pandas as pd # Import von Pandas
import plotly.express as px # Import von Plotly

egywth = pd.read_csv("../data/UROS/Energy1D_weather_clean.csv", parse_dates=[0])
egywth["Weekday"] = egywth["Date"].dt.day_name()
egywthN=egywth.dropna().copy()
egywthN.head()
Date EV_HT_740 EV_NT_740 E_AV_Lab E_SV_Lab ES_Lab DATUM_DT STATIONS_ID MESS_DATUM QN_3 ... UPM TXK TNK TGK eor TemperaturKlasse HeizKuehlTage QNS_4 QNF_4 Weekday
2 2021-01-01 0.0 4080.0 1221.0 290.0 1.0 2021-01-01 4271.0 20210101.0 10.0 ... 90.0 3.0 1.1 0.3 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Friday
3 2021-01-02 1170.0 2630.0 1243.0 284.0 2.0 2021-01-02 4271.0 20210102.0 10.0 ... 95.0 4.0 2.6 2.0 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Saturday
4 2021-01-03 0.0 3750.0 1222.0 283.0 2.0 2021-01-03 4271.0 20210103.0 10.0 ... 81.0 4.6 2.4 0.8 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Sunday
5 2021-01-04 3240.0 1110.0 1263.0 295.0 5.0 2021-01-04 4271.0 20210104.0 10.0 ... 84.0 4.4 3.0 2.4 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Monday
6 2021-01-05 3470.0 1120.0 1346.0 299.0 1.0 2021-01-05 4271.0 20210105.0 10.0 ... 88.0 4.7 3.0 2.6 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Tuesday

5 rows × 31 columns

Um ein GAM-Modell zu erzeugen, nutzen wir die GAM API von Statsmodels. Dafür müssen wir separat die B-Splines initialisieren.

import statsmodels.api as sm
from statsmodels.gam.api import GLMGam, BSplines

bs = BSplines(egywthN[['TMK', "SDK", "NM", "VPM"]], df=[4, 4, 4, 4], degree=[3, 3, 3, 3])

# Fit the GAM model
smfgam = GLMGam.from_formula(formula="ES_Lab ~ TMK + SDK + NM + VPM + Weekday", data=egywthN, smoother=bs)
smfgam = smfgam.fit()
egywthN["gam"]=smfgam.predict()
smfgam.summary()
Generalized Linear Model Regression Results
Dep. Variable: ES_Lab No. Observations: 916
Model: GLMGam Df Residuals: 897
Model Family: Gaussian Df Model: 18.00
Link Function: Identity Scale: 140.96
Method: PIRLS Log-Likelihood: -3556.6
Date: Fri, 12 Jul 2024 Deviance: 1.2645e+05
Time: 12:30:58 Pearson chi2: 1.26e+05
No. Iterations: 3 Pseudo R-squ. (CS): 0.9994
Covariance Type: nonrobust
coef std err z P>|z| [0.025 0.975]
Intercept -16.9526 4.580 -3.701 0.000 -25.930 -7.975
Weekday[T.Monday] -0.3399 1.470 -0.231 0.817 -3.220 2.540
Weekday[T.Saturday] -0.0973 1.474 -0.066 0.947 -2.986 2.792
Weekday[T.Sunday] 1.2628 1.478 0.855 0.393 -1.633 4.159
Weekday[T.Thursday] -0.1677 1.472 -0.114 0.909 -3.053 2.718
Weekday[T.Tuesday] 1.0461 1.472 0.711 0.477 -1.840 3.932
Weekday[T.Wednesday] -0.3203 1.476 -0.217 0.828 -3.213 2.573
TMK 2.3254 0.280 8.299 0.000 1.776 2.875
SDK 6.9210 0.197 35.082 0.000 6.534 7.308
NM 3.8209 0.459 8.319 0.000 2.921 4.721
VPM -2.1580 0.429 -5.029 0.000 -2.999 -1.317
TMK_s0 10.7403 9.344 1.149 0.250 -7.574 29.054
TMK_s1 21.3749 8.604 2.484 0.013 4.511 38.238
TMK_s2 -20.5221 4.429 -4.634 0.000 -29.202 -11.842
SDK_s0 -15.3776 3.412 -4.507 0.000 -22.065 -8.691
SDK_s1 -3.9177 4.190 -0.935 0.350 -12.130 4.295
SDK_s2 8.1667 2.195 3.720 0.000 3.864 12.469
NM_s0 -7.3902 4.881 -1.514 0.130 -16.957 2.177
NM_s1 8.9931 2.975 3.023 0.003 3.162 14.824
NM_s2 -3.0544 1.421 -2.149 0.032 -5.840 -0.269
VPM_s0 -13.5880 8.606 -1.579 0.114 -30.455 3.279
VPM_s1 -12.6270 6.747 -1.872 0.061 -25.851 0.597
VPM_s2 15.0970 3.274 4.611 0.000 8.680 21.514

Das Besondere ist, dass wir die einzelnen Transferfunktionen uns anzeigen lassen können, mit dem gewichteten Residuen des Eingangs. Dadurch bleibt das Modell erklärbar.

fig = smfgam.plot_partial(0, cpr=True)
../_images/f75dd2ca2cc93f867034b9d9fecd82822b63ce331212cb18523216b798fc45f6.png
fig = smfgam.plot_partial(1, cpr=True)
../_images/f205752c4e95c67a463fc812b3ea58750a4ab6c8d52476f9c1b8f00c7f9e846b.png
fig = smfgam.plot_partial(2, cpr=True)
../_images/5bc23a38aca8e7e1ecc25b762f4551834f310d2b2878fb8d8af5d39a6a7a8563.png
fig = smfgam.plot_partial(3, cpr=True)
../_images/2106c4d6fc20030cc1e5b50b95772ea0cedd6fa7b17699f0f1545e36352c259a.png

Vergleichen wir das mit dem alten Linearen Modell.

import statsmodels.formula.api as smf
smflm = smf.ols("ES_Lab ~ TMK + SDK + NM + VPM + Weekday", data=egywthN).fit()
egywthN["ols"]=smflm.predict()
smflm.summary()
OLS Regression Results
Dep. Variable: ES_Lab R-squared: 0.873
Model: OLS Adj. R-squared: 0.872
Method: Least Squares F-statistic: 621.6
Date: Fri, 12 Jul 2024 Prob (F-statistic): 0.00
Time: 12:30:59 Log-Likelihood: -3591.7
No. Observations: 916 AIC: 7205.
Df Residuals: 905 BIC: 7258.
Df Model: 10
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept -20.2008 3.196 -6.320 0.000 -26.474 -13.928
Weekday[T.Monday] -0.6513 1.519 -0.429 0.668 -3.632 2.329
Weekday[T.Saturday] -0.3169 1.522 -0.208 0.835 -3.305 2.671
Weekday[T.Sunday] 0.5073 1.524 0.333 0.739 -2.483 3.498
Weekday[T.Thursday] -0.4597 1.519 -0.303 0.762 -3.441 2.522
Weekday[T.Tuesday] 1.1055 1.518 0.728 0.467 -1.875 4.085
Weekday[T.Wednesday] -0.3329 1.520 -0.219 0.827 -3.315 2.650
TMK 1.8619 0.218 8.557 0.000 1.435 2.289
SDK 7.0105 0.189 37.032 0.000 6.639 7.382
NM 3.5985 0.349 10.310 0.000 2.914 4.284
VPM -1.4871 0.322 -4.616 0.000 -2.119 -0.855
Omnibus: 36.205 Durbin-Watson: 1.115
Prob(Omnibus): 0.000 Jarque-Bera (JB): 77.580
Skew: -0.219 Prob(JB): 1.42e-17
Kurtosis: 4.357 Cond. No. 147.


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Vergleichen wir die Qualität beider Modelle

from sklearn.metrics import mean_absolute_error, r2_score
r2_score(egywthN.ES_Lab, egywthN.ols), mean_absolute_error(egywthN.ES_Lab, egywthN.ols)
(0.872909238506527, 9.238732131049016)
r2_score(egywthN.ES_Lab, egywthN.gam), mean_absolute_error(egywthN.ES_Lab, egywthN.gam)
(0.8822826884210837, 8.869769884021526)

so sehen wir das das GAM-Modell etwas besser ist, aber nicht deutlich. Das zeigt sich auch im Plot.

fig=px.line(egywthN, x="Date", y=["ES_Lab", "ols", "gam"])
fig.show()
/Users/jploennigs/miniconda3/envs/lehre/lib/python3.11/site-packages/_plotly_utils/basevalidators.py:105: FutureWarning:

The behavior of DatetimeProperties.to_pydatetime is deprecated, in a future version this will return a Series containing python datetime objects instead of an ndarray. To retain the old behavior, call `np.array` on the result

ARMA - Autoregressive Moving Average#

Ein Aspekt den wir bisher in unserem Datensatz ignoriert haben, ist die Tatsache, dass es sich bei der Energie um eine Zeitreihe handelt und wir im Linien-Diagramm bereits beobachtet haben, dass Werte sehr stark vom Vorgängerwert abhängen. Diese Abhängigkeit bezeichnet man als Autoregression. Um diese Autoregression zu modellieren, gibt es spezielle Modelle. Ein sehr typisches Modell ist das ARIMA-Modell. Es gleicht einem Linearem Regressionsmodell, das als Eingang bis zu \(p\) vergangenen Zielwerte \(y_{i-k}\) für \(0<k<p\) betrachtet als auch die \(q\) früheren Vorhersagefehler \(\varepsilon_{i-j}\) integriert.

\[ y_i = \beta_0 + \overbrace{\sum_{k=1}^p a_k y_{i-k}}^{AR-Modell} + \overbrace{\sum_{j=1}^q b_j \varepsilon_{i-j}}^{MA-Modell} + \varepsilon_i. \]

Hierbei ist das AR-Modell ein Modell das mit den Koeffizient \(a_k\) den Einfluss des \(k\)-ten vergangenen Werts \(y_{i−k}\) auf den aktuellen Wert \(y_i\) darstellt. Das MA-Modell modelliert die Abweichung vom gleitenden Durchschnitt in Form der vergangenen Fehlerterme \(\varepsilon_{i−k}\). Die Ordnungen \(p\) und \(q\) können bestimmt werden durch Analyse der Autokorrelationsfunktion (ACF) zur Bestimmung der Ordnung \(q\) des MA-Teils und der Partielle Autokorrelationsfunktion (PACF) zur Bestimmung der Ordnung \(p\) des AR-Teils.

Ein ARMA-Modell kann erstellt werden mit dem ARIMA-Modul von Statsmodels. Wichtig ist hierbei, dass wir einen äquidistanten Zeitreihe mit einer festen Abtastrate nutzen, auch wenn dieser fehlende Werte enthält, da wir ja die Vorgängerwerte mit betrachten.

from statsmodels.tsa.arima.model import ARIMA

arma_mod = ARIMA(egywth.ES_Lab, order=(3, 0, 1), trend="n")
arma_res = arma_mod.fit()
egywth["arma"]=arma_res.predict()
arma_res.summary()
SARIMAX Results
Dep. Variable: ES_Lab No. Observations: 1098
Model: ARIMA(3, 0, 1) Log Likelihood -4623.891
Date: Fri, 12 Jul 2024 AIC 9257.781
Time: 12:31:00 BIC 9282.787
Sample: 0 HQIC 9267.242
- 1098
Covariance Type: opg
coef std err z P>|z| [0.025 0.975]
ar.L1 1.1804 0.030 39.333 0.000 1.122 1.239
ar.L2 -0.1256 0.035 -3.563 0.000 -0.195 -0.057
ar.L3 -0.0570 0.030 -1.873 0.061 -0.117 0.003
ma.L1 -0.8497 0.022 -38.682 0.000 -0.893 -0.807
sigma2 300.4701 9.893 30.373 0.000 281.081 319.859
Ljung-Box (L1) (Q): 0.01 Jarque-Bera (JB): 276.57
Prob(Q): 0.91 Prob(JB): 0.00
Heteroskedasticity (H): 0.86 Skew: -0.54
Prob(H) (two-sided): 0.16 Kurtosis: 5.21


Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).

Wenn wir das Modell vergleichen mit den vorherigen Modellen, so ist das Vorhersagemodell schlechter und im Diagramm zeigt sich, dass die Vorhersagen geglätteter sind. Allerdings bemötigt das Modell auch keine weitere externen Eingangsvariablen.

egywthN=egywth.dropna()
r2_score(egywthN.ES_Lab, egywthN.arma), mean_absolute_error(egywthN.ES_Lab, egywthN.arma)
(0.7665645561291471, 11.362262254731204)
fig=px.line(egywthN, x="Date", y=["ES_Lab", "arma"])
fig.show()
/Users/jploennigs/miniconda3/envs/lehre/lib/python3.11/site-packages/_plotly_utils/basevalidators.py:105: FutureWarning:

The behavior of DatetimeProperties.to_pydatetime is deprecated, in a future version this will return a Series containing python datetime objects instead of an ndarray. To retain the old behavior, call `np.array` on the result

Autoregressive Lineare und GAM Modelle#

Wir können auch in unsere bisherigen Modelle die Autoregressive Komponente integrieren, indem wir uns eine verschobene Zielvariable definieren. Da wir wissen, dass es auch einen wöchentlichen Saison gibt, fügen wir auch den 7-Tage Lag hinzu.

egywth["ES_Lab1"]=egywth.ES_Lab.shift(-1)
egywth["ES_Lab7"]=egywth.ES_Lab.shift(-7)
egywth.head()
Date EV_HT_740 EV_NT_740 E_AV_Lab E_SV_Lab ES_Lab DATUM_DT STATIONS_ID MESS_DATUM QN_3 ... TGK eor TemperaturKlasse HeizKuehlTage QNS_4 QNF_4 Weekday arma ES_Lab1 ES_Lab7
0 2020-12-30 NaN NaN NaN NaN NaN 2020-12-30 4271.0 20201230.0 10.0 ... 2.2 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Wednesday 0.000000 5.0 3.0
1 2020-12-31 NaN NaN 1256.0 291.0 5.0 2020-12-31 4271.0 20201231.0 10.0 ... 0.9 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Thursday 0.000000 1.0 2.0
2 2021-01-01 0.0 4080.0 1221.0 290.0 1.0 2021-01-01 4271.0 20210101.0 10.0 ... 0.3 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Friday 4.523641 2.0 2.0
3 2021-01-02 1170.0 2630.0 1243.0 284.0 2.0 2021-01-02 4271.0 20210102.0 10.0 ... 2.0 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Saturday 2.534921 2.0 3.0
4 2021-01-03 0.0 3750.0 1222.0 283.0 2.0 2021-01-03 4271.0 20210103.0 10.0 ... 0.8 eor Cold Heizgradtag nicht alle Parameter korrigiert 5 Sunday 2.339946 5.0 9.0

5 rows × 34 columns

import statsmodels.formula.api as smf

egywthN=egywth.dropna().copy()
smflmAR = smf.ols("ES_Lab ~ TMK + SDK + NM + VPM + Weekday + ES_Lab1 + ES_Lab7", data=egywthN).fit()
egywthN["olsAR"]=smflmAR.predict()
smflmAR.summary()
OLS Regression Results
Dep. Variable: ES_Lab R-squared: 0.934
Model: OLS Adj. R-squared: 0.933
Method: Least Squares F-statistic: 1051.
Date: Fri, 12 Jul 2024 Prob (F-statistic): 0.00
Time: 12:31:00 Log-Likelihood: -3242.5
No. Observations: 903 AIC: 6511.
Df Residuals: 890 BIC: 6574.
Df Model: 12
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept -16.8304 2.345 -7.176 0.000 -21.433 -12.227
Weekday[T.Monday] -0.7007 1.103 -0.635 0.525 -2.865 1.464
Weekday[T.Saturday] -0.8303 1.103 -0.753 0.452 -2.994 1.334
Weekday[T.Sunday] -0.1096 1.108 -0.099 0.921 -2.283 2.064
Weekday[T.Thursday] -0.1587 1.104 -0.144 0.886 -2.325 2.007
Weekday[T.Tuesday] 0.2843 1.103 0.258 0.797 -1.880 2.449
Weekday[T.Wednesday] 0.1509 1.105 0.137 0.891 -2.019 2.320
TMK 1.0641 0.160 6.661 0.000 0.751 1.378
SDK 5.2692 0.153 34.430 0.000 4.969 5.570
NM 2.6722 0.260 10.276 0.000 2.162 3.183
VPM -1.1198 0.233 -4.811 0.000 -1.577 -0.663
ES_Lab1 0.2399 0.016 15.343 0.000 0.209 0.271
ES_Lab7 0.1472 0.014 10.384 0.000 0.119 0.175
Omnibus: 27.485 Durbin-Watson: 1.835
Prob(Omnibus): 0.000 Jarque-Bera (JB): 62.194
Skew: -0.085 Prob(JB): 3.12e-14
Kurtosis: 4.275 Cond. No. 624.


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
bs = BSplines(egywthN[['TMK', "SDK", "NM", "VPM", "ES_Lab1", "ES_Lab7"]], df=[4, 4, 4, 4, 4, 4], degree=[3, 3, 3, 3, 3, 3])

# Fit the GAM model
smfgamAR = GLMGam.from_formula(formula="ES_Lab ~ TMK + SDK + NM + VPM + Weekday + ES_Lab1 + ES_Lab7", data=egywthN, smoother=bs)
smfgamAR = smfgamAR.fit()
egywthN["gamAR"]=smfgamAR.predict()
smfgamAR.summary()
Generalized Linear Model Regression Results
Dep. Variable: ES_Lab No. Observations: 903
Model: GLMGam Df Residuals: 878
Model Family: Gaussian Df Model: 24.00
Link Function: Identity Scale: 72.947
Method: PIRLS Log-Likelihood: -3205.4
Date: Fri, 12 Jul 2024 Deviance: 64047.
Time: 12:31:00 Pearson chi2: 6.40e+04
No. Iterations: 3 Pseudo R-squ. (CS): 1.000
Covariance Type: nonrobust
coef std err z P>|z| [0.025 0.975]
Intercept -17.4815 3.362 -5.199 0.000 -24.071 -10.892
Weekday[T.Monday] -0.5792 1.067 -0.543 0.587 -2.670 1.512
Weekday[T.Saturday] -0.8967 1.069 -0.839 0.402 -2.992 1.198
Weekday[T.Sunday] 0.2925 1.074 0.272 0.785 -1.812 2.397
Weekday[T.Thursday] -0.1385 1.070 -0.129 0.897 -2.236 1.959
Weekday[T.Tuesday] -0.0400 1.071 -0.037 0.970 -2.138 2.058
Weekday[T.Wednesday] -0.3121 1.077 -0.290 0.772 -2.422 1.798
TMK 1.1854 0.216 5.486 0.000 0.762 1.609
SDK 5.2207 0.160 32.706 0.000 4.908 5.534
NM 3.0381 0.338 8.990 0.000 2.376 3.701
VPM -1.1884 0.316 -3.765 0.000 -1.807 -0.570
ES_Lab1 0.2497 0.019 13.071 0.000 0.212 0.287
ES_Lab7 0.1443 0.017 8.379 0.000 0.111 0.178
TMK_s0 2.2618 6.956 0.325 0.745 -11.372 15.896
TMK_s1 -0.8353 6.335 -0.132 0.895 -13.252 11.582
TMK_s2 -3.0084 3.335 -0.902 0.367 -9.544 3.527
SDK_s0 -14.7653 2.520 -5.859 0.000 -19.705 -9.826
SDK_s1 -0.7000 3.237 -0.216 0.829 -7.044 5.644
SDK_s2 5.7120 1.733 3.295 0.001 2.314 9.110
NM_s0 -3.2865 3.552 -0.925 0.355 -10.247 3.674
NM_s1 7.0927 2.172 3.265 0.001 2.835 11.351
NM_s2 -3.2532 1.038 -3.135 0.002 -5.287 -1.220
VPM_s0 1.2826 6.374 0.201 0.841 -11.210 13.775
VPM_s1 -6.0830 4.893 -1.243 0.214 -15.673 3.507
VPM_s2 5.8977 2.386 2.471 0.013 1.220 10.575
ES_Lab1_s0 5.8210 3.137 1.856 0.064 -0.327 11.969
ES_Lab1_s1 -0.5841 3.122 -0.187 0.852 -6.704 5.536
ES_Lab1_s2 -1.5488 1.537 -1.008 0.314 -4.561 1.464
ES_Lab7_s0 0.1835 2.923 0.063 0.950 -5.546 5.913
ES_Lab7_s1 0.4058 2.878 0.141 0.888 -5.236 6.047
ES_Lab7_s2 -0.3305 1.414 -0.234 0.815 -3.102 2.441

Die resultierenden Modelle sind durch Hinzufügen der autoregressiven Komponente deutlich besser. Es erfordert allerdings eine äquidistante Zeitreihe da sonst Abhängigkeiten inkorrekt aufgelöst werden.

r2_score(egywthN.ES_Lab, egywthN.olsAR), mean_absolute_error(egywthN.ES_Lab, egywthN.olsAR)
(0.9341028559113053, 6.4849636708421405)
r2_score(egywthN.ES_Lab, egywthN.gamAR), mean_absolute_error(egywthN.ES_Lab, egywthN.gamAR)
(0.9392984503858443, 6.149861158597452)

Auch zeigt sich das bei den täglichen Werten das einfache Lineare Modell bereits gut genug ist und das komplexere GAM-Modell nicht besser abschneidet. Das ist jedoch nicht zu verallgemeinern, sondern kann sich stark nach Datensatz unterscheiden.

fig=px.line(egywthN, x="Date", y=["ES_Lab", "olsAR", "gamAR"])
fig.show()
/Users/jploennigs/miniconda3/envs/lehre/lib/python3.11/site-packages/_plotly_utils/basevalidators.py:105: FutureWarning:

The behavior of DatetimeProperties.to_pydatetime is deprecated, in a future version this will return a Series containing python datetime objects instead of an ndarray. To retain the old behavior, call `np.array` on the result