Zeitreihenanalyse: Von den Daten zur Prognose

PVA-Tutorial – Explorative Analyse und Vorbereitung der Modellierung

Autor:in
Zugehörigkeit

Markus Geuss

Fernfachhochschule Schweiz

TippLernziele

Lernziele

Nach der Bearbeitung dieses Tutorials …

  • kann ich zentrale Strukturen einer Zeitreihe wie Trend, Saisonalität und Autokorrelation erkennen und interpretieren.
  • kann ich Zeitplot, saisonale Darstellungen, Lag-Plots, ACF und Zerlegung zur explorativen Untersuchung einer Zeitreihe sinnvoll einsetzen.
  • kann ich begründen, warum Datenbereinigung und ein korrekt definierter Zeitindex vor der Modellierung wichtig sind.
  • kann ich aus der explorativen Analyse Anforderungen an ein geeignetes Prognosemodell ableiten.

In dieser Fallstudie untersuchen wir die monatlichen Bestellungen eines Onlinehändlers. Wir gehen schrittweise vor: Zuerst lernen wir den Datensatz kennen und prüfen seine Qualität. Anschliessend untersuchen wir die zeitliche Struktur der Bestellungen. Erst danach stellt sich die Frage, welche Modellierungsansätze sich für eine Prognose eignen.

Teil 1: Explorative Zeitreihenanalyse – den Datensatz verstehen

Fallstudie: Wie viele Bestellungen erwarten wir?

Ein Schweizer Onlinehändler verkauft Haushalts- und Lifestyleprodukte. Für die Planung von Lagerbestand, Logistik und Personal möchte das Unternehmen abschätzen, mit wie vielen Bestellungen in den kommenden Monaten zu rechnen ist.

Aus dem ERP- und Marketingsystem wurden monatliche Daten der Jahre 2013 bis 2019 exportiert. Der Datensatz enthält folgende Variablen:

Variable Bedeutung
Month Monat der Beobachtung
Orders Anzahl der Bestellungen
Marketing Marketingausgaben in Tsd. CHF
Discount durchschnittlich gewährter Rabatt in %

Unsere Forecastvariable ist damit

\[ y_t = \text{Anzahl der Bestellungen im Monat } t. \]

Die zentrale Frage der Fallstudie lautet:

Wie viele Bestellungen erwarten wir in den kommenden Monaten?

Bevor wir Prognosemodelle verwenden, müssen wir zunächst verstehen, mit welcher Art von Zeitreihe wir es zu tun haben.

1. Die Daten kennenlernen

Code
glimpse(shop_raw)
Rows: 84
Columns: 4
$ Month     <chr> "2013-01", "2013-02", "2013-03", "2013-04", "2013-05", "2013…
$ Orders    <int> 1349, 1372, 1543, 1809, 1723, 1863, 1715, 1627, 1682, 1869, …
$ Marketing <dbl> 30.9, 28.2, 36.8, 32.8, 35.4, 33.2, 35.1, 36.2, 33.0, 30.5, …
$ Discount  <dbl> 4.2, 5.6, 6.4, 6.9, 6.7, 7.1, 6.0, 5.9, 7.0, 5.4, 11.6, 10.6…

Diskussion

Was stellt in diesem Datensatz eine Beobachtung dar?

Welche Besonderheit besitzt dieser Datensatz gegenüber den bisher im Modul verwendeten Querschnittsdaten?

Was sollten wir überprüfen, bevor wir mit der eigentlichen Analyse beginnen?

Eine Beobachtung entspricht einem Monat und fasst die Bestellungen dieses Monats zusammen. Unsere Beobachtungen besitzen deshalb eine natürliche zeitliche Ordnung:

\[ y_1, y_2, \ldots, y_T. \]

Vor der Analyse sollten wir insbesondere prüfen:

  • ob der Zeitindex korrekt repräsentiert wird,
  • ob Zeitpunkte fehlen,
  • ob Zeitpunkte mehrfach vorkommen,
  • ob Werte innerhalb vorhandener Beobachtungen fehlen,
  • ob Werte offensichtlich unplausibel sind.

Typische Fehlvorstellung: Ein fehlender Zeitpunkt und ein NA in einem vorhandenen Zeitpunkt sind nicht dasselbe. Im ersten Fall fehlt eine ganze Beobachtung auf der Zeitachse, im zweiten Fall existiert der Zeitpunkt, aber eine Variable wurde dort nicht beobachtet.

2. Einen geeigneten Zeitindex erzeugen

Schauen wir uns zunächst die Variable Month an.

Code
class(shop_raw$Month)
[1] "character"
Code
head(shop_raw$Month)
[1] "2013-01" "2013-02" "2013-03" "2013-04" "2013-05" "2013-06"

Diskussion

Month wurde als Zeichenkette importiert.

Ist das tatsächlich ein Problem? Wir Menschen verstehen doch ohne Weiteres, was "2016-04" bedeutet.

Für Menschen ist "2016-04" eindeutig, für die Zeitreihenanalyse enthält eine Zeichenkette aber noch keine explizite Information über die regelmäßige monatliche Zeitachse.

Wir wandeln Month deshalb in einen monatlichen Zeitindex um und erzeugen daraus ein tsibble.

Code
shop <- shop_raw |>
  mutate(Month = yearmonth(Month)) |>
  as_tsibble(index = Month)

shop
# A tsibble: 84 x 4 [1M]
      Month Orders Marketing Discount
      <mth>  <int>     <dbl>    <dbl>
 1 2013 Jan   1349      30.9      4.2
 2 2013 Feb   1372      28.2      5.6
 3 2013 Mar   1543      36.8      6.4
 4 2013 Apr   1809      32.8      6.9
 5 2013 May   1723      35.4      6.7
 6 2013 Jun   1863      33.2      7.1
 7 2013 Jul   1715      35.1      6  
 8 2013 Aug   1627      36.2      5.9
 9 2013 Sep   1682      33        7  
10 2013 Oct   1869      30.5      5.4
# ℹ 74 more rows

In der mathematischen Notation von FPP3 verwenden wir weiterhin den allgemeinen Zeitindex

\[ t = 1, \ldots, T. \]

Für unseren Datensatz gilt \(T = 84\).

Typische Fehlvorstellung: Chronologisch sortierte Zeichenketten sind noch kein geeigneter Zeitindex. Die Software muss die Frequenz und mögliche Lücken auf der Zeitachse erkennen können.

3. Ist die Zeitreihe vollständig?

Zunächst prüfen wir, ob Beobachtungszeitpunkte fehlen.

Code
shop |>
  scan_gaps()
# A tsibble: 0 x 1 [?]
# ℹ 1 variable: Month <mth>

Diskussion

Der Output ist leer.

Was können wir daraus schließen – und was noch nicht?

Zwischen Januar 2013 und Dezember 2019 fehlt kein Monat. Damit ist die Zeitachse vollständig.

Das bedeutet aber noch nicht, dass alle Variablen in jedem Monat beobachtet wurden.

\[ \text{fehlender Zeitpunkt} \neq \text{fehlender Wert}. \]

Typische Fehlvorstellung: scan_gaps() prüft nicht, ob einzelne Variablen NA enthalten. Es prüft Lücken im Zeitindex.

Nun kontrollieren wir fehlende Werte in den Variablen.

Code
shop |>
  summarise(
    missing_orders = sum(is.na(Orders)),
    missing_marketing = sum(is.na(Marketing)),
    missing_discount = sum(is.na(Discount))
  )
# A tsibble: 84 x 4 [1M]
      Month missing_orders missing_marketing missing_discount
      <mth>          <int>             <int>            <int>
 1 2013 Jan              0                 0                0
 2 2013 Feb              0                 0                0
 3 2013 Mar              0                 0                0
 4 2013 Apr              0                 0                0
 5 2013 May              0                 0                0
 6 2013 Jun              0                 0                0
 7 2013 Jul              0                 0                0
 8 2013 Aug              0                 0                0
 9 2013 Sep              0                 0                0
10 2013 Oct              0                 0                0
# ℹ 74 more rows

Für April 2016 fehlt der Wert von Marketing.

Diskussion

Wie würden Sie mit diesem fehlenden Wert umgehen?

Bevor wir einen fehlenden Wert statistisch ersetzen, sollten wir klären, warum er fehlt und ob die ursprüngliche Information wiederbeschafft werden kann.

In unserem Fall konnte die Finanzbuchhaltung den Marketingaufwand für April 2016 nachliefern: 39.8 Tsd. CHF.

Code
shop <- shop |>
  mutate(
    Marketing = if_else(
      Month == yearmonth("2016 Apr"),
      marketing_2016_04,
      Marketing
    )
  )

Typische Fehlvorstellung: Ein fehlender Wert sollte nicht reflexartig durch den Mittelwert oder eine Interpolation ersetzt werden. Wenn die Originalinformation rekonstruierbar ist, ist dies vorzuziehen.

Damit ist der Datensatz für die explorative Analyse vorbereitet.

4. Die wichtigste Darstellung zuerst

FPP3 empfiehlt für die explorative Zeitreihenanalyse, die Daten zunächst über die Zeit zu visualisieren. Viele Eigenschaften einer Zeitreihe sind in einer rein numerischen Zusammenfassung kaum zu erkennen.

Code
shop |>
  autoplot(Orders) +
  labs(
    title = "Monatliche Bestellungen des Onlinehändlers",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 1: Monatliche Bestellungen des Onlinehändlers, 2013–2019.

Diskussion

Was fällt Ihnen auf? Beschreiben Sie die Zeitreihe zunächst, ohne bereits ein Modell vorzuschlagen.

Der Zeitplot liefert Hinweise auf mehrere Strukturen:

  • Das Niveau der Bestellungen steigt langfristig an: Trend.
  • Innerhalb der Jahre scheint sich ein Muster regelmäßig zu wiederholen: Saisonalität.
  • Die absolute Größe der saisonalen Schwankungen nimmt mit dem Niveau der Reihe etwas zu.
  • Einzelne Monate erscheinen ungewöhnlich und sollten genauer untersucht werden.

Typische Fehlvorstellung: Ein positiver Trend bedeutet nicht, dass für jeden Zeitpunkt \(y_{t+1} > y_t\) gelten muss. Ein Trend beschreibt die langfristige Entwicklung des Niveaus der Reihe.

Der Zeitplot legt damit insbesondere ein saisonales Muster nahe. Aber noch haben wir nur einen visuellen Eindruck.

Wie können wir untersuchen, ob bestimmte Monate tatsächlich systematisch ähnliche Verhaltensweisen zeigen?

5. Gibt es tatsächlich ein saisonales Muster?

Bei monatlichen Daten können wir die einzelnen Jahre übereinanderlegen.

Code
shop |>
  gg_season(Orders, labels = "both") +
  labs(
    title = "Saisonaler Verlauf der Bestellungen",
    x = "Monat",
    y = "Bestellungen"
  )
Abbildung 2: Seasonal Plot der monatlichen Bestellungen.

Diskussion

Was lernen wir aus diesem Plot, was im ursprünglichen Zeitplot schwieriger zu erkennen war?

November und Dezember weisen über mehrere Jahre hinweg besonders hohe Bestellzahlen auf, während einige Sommermonate typischerweise schwächer sind. Das Muster wiederholt sich also systematisch innerhalb des Kalenderjahres.

Bei monatlichen Daten mit jährlicher Saisonalität beträgt die saisonale Periode

\[ m = 12. \]

Saisonalität bedeutet nicht, dass sich dieselben Zahlen exakt wiederholen, sondern dass sich ein systematisches Muster mit bekannter und fester Periode wiederholt.

Typische Fehlvorstellung: Ein einzelner hoher Dezember belegt noch keine Saisonalität. Entscheidend ist die wiederkehrende Struktur über mehrere Jahre.

Zur genaueren Betrachtung der einzelnen Monate verwenden wir einen Seasonal Subseries Plot.

Code
shop |>
  gg_subseries(Orders) +
  labs(
    title = "Bestellungen nach Kalendermonat",
    x = "Monat",
    y = "Bestellungen"
  )
Abbildung 3: Seasonal Subseries Plot der monatlichen Bestellungen.

Diskussion

Welche zusätzliche Information liefert diese Darstellung? Welche Beobachtungen würden Sie näher untersuchen?

Der Seasonal Subseries Plot macht die typischen Niveaus der einzelnen Kalendermonate besonders deutlich. Außerdem fallen zwei Beobachtungen gegenüber den übrigen Werten ihres jeweiligen Monats auf:

  • Juli 2016: ungewöhnlich niedrige Bestellzahl,
  • März 2018: ungewöhnlich hohe Bestellzahl.

Eine Rückfrage beim Unternehmen ergibt:

  • Im Juli 2016 führte ein Problem beim Wechsel des Logistikdienstleisters zu mehreren Tagen mit eingeschränktem Versand.
  • Im März 2018 erzeugte eine erfolgreiche Influencer-Kampagne ungewöhnlich viele Bestellungen.

Beide Werte sind damit reale Beobachtungen und keine Eingabefehler. Wir behalten sie im Datensatz.

Typische Fehlvorstellung: Eine statistisch ungewöhnliche Beobachtung ist nicht automatisch ein Datenfehler und sollte nicht ohne sachliche Prüfung entfernt werden.

6. Hängt die Gegenwart von der Vergangenheit ab?

Bis jetzt haben wir festgestellt, dass sich bestimmte Muster wiederholen. Nun stellen wir eine andere Frage:

Enthält eine frühere Beobachtung Information über eine spätere Beobachtung?

Beginnen wir mit Lag-Plots.

HinweisReminder: Was ist ein Lag-Plot?

Ein Lag-Plot vergleicht eine Zeitreihe \(y_t\) mit einer um \(k\) Zeitpunkte verschobenen Version derselben Zeitreihe.

Für einen Lag \(k\) wird jede Beobachtung als Wertepaar

\[ (y_{t-k}, y_t) \]

dargestellt:

  • auf der x-Achse steht \(y_{t-k}\),
  • auf der y-Achse steht \(y_t\).

Ein erkennbares Muster in der Punktwolke deutet darauf hin, dass zwischen Beobachtungen im Abstand von \(k\) Zeitpunkten ein Zusammenhang besteht.

Interpretation: Liegen die Punkte beispielsweise grob entlang einer steigenden Geraden, besteht ein positiver linearer Zusammenhang zwischen \(y_t\) und \(y_{t-k}\).

Bei monatlichen Daten ist insbesondere \(k=12\) interessant:

\[ (y_{t-12}, y_t), \]

also der Vergleich eines Monats mit demselben Monat des Vorjahres.

Der Lag-Plot zeigt damit grafisch, was die Autokorrelation \(r_k\) anschliessend numerisch zusammenfasst.

Code
shop |>
  gg_lag(Orders, lags = c(1, 12))
Abbildung 4: Lag-Plots der Bestellungen für Lag 1 und Lag 12.

Diskussion

Betrachten Sie zunächst Lag \(k=1\).

Was repräsentiert ein einzelner Punkt in diesem Plot?

Und anschließend Lag \(k=12\):

Warum ist gerade \(k=12\) für unsere monatliche Zeitreihe interessant?

Ein Punkt im Lag-1-Plot stellt das Wertepaar

\[ (y_{t-1}, y_t) \]

dar: Auf der horizontalen Achse steht die Bestellzahl des Vormonats, auf der vertikalen Achse die Bestellzahl des aktuellen Monats.

Für Lag \(k=12\) vergleichen wir

\[ y_{t-12} \quad \text{mit} \quad y_t. \]

Bei monatlichen Daten entspricht dies dem Vergleich eines Monats mit demselben Monat des Vorjahres. Damit erhalten wir eine weitere Sicht auf die bereits beobachtete jährliche Saisonalität.

Typische Fehlvorstellung: Lag \(12\) misst nicht die Veränderung der Bestellungen innerhalb von zwölf Monaten. Es bezeichnet lediglich den zeitlichen Abstand zwischen den verglichenen Beobachtungen.

7. Von den Lag-Plots zur Autokorrelation

Für jeden Lag \(k\) könnten wir einen eigenen Lag-Plot erzeugen. Praktischer ist es, den linearen Zusammenhang zwischen \(y_t\) und \(y_{t-k}\) jeweils durch einen Korrelationskoeffizienten zusammenzufassen.

HinweisReminder: Autokorrelation als Vergleich eines Vektors mit sich selbst

Eine Zeitreihe mit \(T\) Beobachtungen können wir zunächst als Vektor schreiben:

\[ \mathbf{y} = \begin{pmatrix} y_1\\ y_2\\ \vdots\\ y_T \end{pmatrix}. \]

Wie bei der gewöhnlichen Korrelation interessieren uns nicht die absoluten Werte, sondern ihre Abweichungen vom Mittelwert. Wir zentrieren daher die Zeitreihe:

\[ z_t = y_t-\bar y \]

und erhalten den zentrierten Vektor

\[ \mathbf{z} = \begin{pmatrix} z_1\\ z_2\\ \vdots\\ z_T \end{pmatrix}. \]

1. Wir duplizieren den Vektor und verschieben ihn

Für einen Lag \(k\) vergleichen wir die Zeitreihe mit einer um \(k\) Zeitpunkte verschobenen Kopie ihrer selbst.

Nehmen wir beispielsweise \(T=6\) und \(k=2\):

Zeitpunkt 1 2 3 4 5 6
ursprüngliche Reihe \(z_1\) \(z_2\) \(z_3\) \(z_4\) \(z_5\) \(z_6\)
um 2 verschobene Reihe \(z_1\) \(z_2\) \(z_3\) \(z_4\)

Damit stehen sich nur noch folgende Werte gegenüber:

\[ (z_3,z_1),\quad (z_4,z_2),\quad (z_5,z_3),\quad (z_6,z_4). \]

Die Werte ohne Gegenüber werden nicht für diesen Lag verwendet.

Allgemein bleiben bei Lag \(k\) also \(T-k\) Paare übrig.

2. Aus den überlappenden Werten werden zwei Vektoren

Für Lag \(k\) erhalten wir

\[ \mathbf{z}^{(1)}_k = \begin{pmatrix} z_{k+1}\\ z_{k+2}\\ \vdots\\ z_T \end{pmatrix}, \qquad \mathbf{z}^{(2)}_k = \begin{pmatrix} z_1\\ z_2\\ \vdots\\ z_{T-k} \end{pmatrix}. \]

Beide Vektoren besitzen die Dimension \(T-k\).

Jetzt können wir dieselbe geometrische Idee verwenden wie bei der gewöhnlichen Korrelation:

Zeigen die beiden Vektoren in eine ähnliche Richtung?

Das messen wir zunächst durch ihr Skalarprodukt:

\[ \left(\mathbf{z}^{(1)}_k\right)^\top \mathbf{z}^{(2)}_k. \]

Ausgeschrieben ist dies

\[ \sum_{t=k+1}^{T} (y_t-\bar y)(y_{t-k}-\bar y). \]

3. Was sagt das Skalarprodukt aus?

Zeigen beide Vektoren ungefähr in dieselbe Richtung, ist das Skalarprodukt positiv.

\[ \left(\mathbf{z}^{(1)}_k\right)^\top \mathbf{z}^{(2)}_k > 0 \]

Das bedeutet: Hohe Werte relativ zu \(\bar y\) treten häufig zusammen mit hohen Werten \(k\) Perioden zuvor auf – und niedrige mit niedrigen.

Zeigen sie eher in entgegengesetzte Richtungen, ist das Skalarprodukt negativ.

Besonders wichtig ist der Fall

\[ \left(\mathbf{z}^{(1)}_k\right)^\top \mathbf{z}^{(2)}_k = 0. \]

Dann stehen die beiden Vektoren orthogonal aufeinander:

\[ \mathbf{z}^{(1)}_k \perp \mathbf{z}^{(2)}_k. \]

Es gibt dann keinen linearen Zusammenhang bei Lag \(k\).

4. Vom Skalarprodukt zur Autokorrelation

Wie bei der Pearson-Korrelation müssen wir das Skalarprodukt noch normieren. Die in der Zeitreihenanalyse übliche Stichprobenautokorrelation lautet

\[ r_k = \frac{ \displaystyle \sum_{t=k+1}^{T} (y_t-\bar y)(y_{t-k}-\bar y) }{ \displaystyle \sum_{t=1}^{T} (y_t-\bar y)^2 }. \]

Der Nenner verwendet die gesamte quadrierte Länge des zentrierten Zeitreihenvektors:

\[ \|\mathbf z\|^2 = \sum_{t=1}^{T}(y_t-\bar y)^2. \]

Damit wird das Skalarprodukt auf eine gemeinsame Skala normiert und wir können \(r_k\) für verschiedene Lags \(k\) miteinander vergleichen.

Die Autocorrelation Function (ACF) stellt schließlich \(r_k\) für verschiedene Lags \(k\) dar.

Typische Fehlvorstellung:
\(r_k=0\) bedeutet nicht, dass die Beobachtungen vollständig unabhängig sind. Es bedeutet zunächst nur, dass für diesen Lag kein linearer Zusammenhang vorliegt. Nichtlineare Abhängigkeiten können trotzdem existieren.

Querreferenz: FPP3, Chapter 2, Abschnitt Autocorrelation.

Code
shop |>
  ACF(Orders, lag_max = 36) |>
  autoplot() +
  labs(title = "ACF der monatlichen Bestellungen")
Abbildung 5: Autokorrelationsfunktion (ACF) der monatlichen Bestellungen.

Diskussion

Versuchen Sie, die Form der ACF mit unseren bisherigen Beobachtungen zu verbinden. Was erkennen Sie wieder?

Die ACF bestätigt Strukturen, die wir bereits grafisch vermutet haben:

  • Für kleine Lags sind die Autokorrelationen positiv. Zeitlich benachbarte Beobachtungen ähneln sich also stärker, als es bei unabhängigen Beobachtungen zu erwarten wäre.
  • Bei den saisonalen Lags \(12\), \(24\) und \(36\) treten erneut erhöhte Autokorrelationen auf. Dies passt zu einer jährlichen Saisonalität mit

\[ m=12. \]

Ein hoher Wert von \(r_{12}\) bedeutet, dass \(y_t\) und \(y_{t-12}\) stark linear zusammenhängen.

Typische Fehlvorstellung: \(r_{12}\) misst nicht, wie stark sich die Bestellungen innerhalb eines Jahres verändert haben. Es handelt sich um eine Korrelation, nicht um eine Differenz.

Damit haben wir eine zentrale Besonderheit von Zeitreihendaten sichtbar gemacht:

\[ \boxed{\text{Beobachtungen einer Zeitreihe können zeitlich voneinander abhängig sein.}} \]

Diese zeitliche Abhängigkeit wird später insbesondere für ARIMA wichtig.

8. Ist eine additive Darstellung plausibel?

Im ursprünglichen Zeitplot war außerdem zu erkennen, dass die absolute Größe der saisonalen Schwankungen mit dem Niveau der Reihe zunimmt.

FPP3 unterscheidet eine additive Zerlegung

\[ y_t = S_t + T_t + R_t \]

von einer multiplikativen Zerlegung

\[ y_t = S_t \times T_t \times R_t, \]

wobei

  • \(S_t\) die seasonal component,
  • \(T_t\) die trend-cycle component und
  • \(R_t\) die remainder component

bezeichnet.

Querreferenz: FPP3, Chapter 3, Abschnitt Time series components.

Diskussion

Wann wäre eine additive Zerlegung plausibel? Welche Variante erscheint für unsere Bestellzahlen zunächst geeigneter?

Eine additive Struktur ist plausibel, wenn die saisonalen Schwankungen ungefähr gleich groß bleiben, unabhängig vom Niveau der Reihe.

Nimmt die absolute saisonale Schwankungsbreite dagegen mit dem Niveau zu, ist eine multiplikative Struktur häufig geeigneter. Für unsere Bestellzahlen erscheint deshalb die multiplikative Sicht zunächst plausibler.

Typische Fehlvorstellung: Eine multiplikative Zerlegung bedeutet nicht, dass die Zeitreihe exponentiell wachsen muss. Sie beschreibt hier vor allem saisonale Effekte, deren absolute Größe vom Niveau der Reihe abhängt.

Eine Möglichkeit, eine multiplikative Struktur additiv zu behandeln, ist die logarithmische Transformation. Wir definieren entsprechend der Notation in FPP3

\[ w_t = \log(y_t). \]

Code
shop |>
  autoplot(log(Orders)) +
  labs(
    title = "Logarithmierte monatliche Bestellungen",
    x = NULL,
    y = "log(Bestellungen)"
  )
Abbildung 6: Logarithmierte monatliche Bestellungen.

Diskussion

Vergleichen Sie diesen Plot mit der ursprünglichen Reihe. Was hat die Transformation bewirkt?

Die Log-Transformation komprimiert große Werte stärker als kleine Werte. Dadurch wirkt die saisonale Schwankungsbreite über die Zeit deutlich stabiler.

Die Transformation hat die Saisonalität nicht entfernt; sie verändert ihre Skalierung und erleichtert dadurch eine additive Beschreibung auf der transformierten Skala.

Typische Fehlvorstellung: Eine Log-Transformation entfernt weder Trend noch Saisonalität automatisch. Sie kann insbesondere eine vom Niveau abhängige Varianz bzw. saisonale Amplitude stabilisieren.

9. Die beobachtete Struktur zerlegen

Nachdem wir Trend und Saisonalität in mehreren Darstellungen erkannt haben, können wir die beobachtete Struktur mithilfe von STL in Komponenten zerlegen.

Für die transformierte Reihe

\[ w_t = \log(y_t) \]

verwenden wir die additive Darstellung

\[ w_t = S_t + T_t + R_t. \]

Code
shop_stl <- shop |>
  model(
    STL(
      log(Orders) ~ season(window = "periodic"),
      robust = TRUE
    )
  )

shop_stl |>
  components() |>
  autoplot()
Abbildung 7: STL-Zerlegung der logarithmierten Bestellzahlen.

Diskussion

Welche unserer bisherigen Vermutungen werden durch die Zerlegung bestätigt? Was sehen Sie jetzt deutlicher?

Die Zerlegung bestätigt die wesentlichen Befunde der EDA:

  • \(T_t\) zeigt einen langfristig steigenden trend-cycle.
  • \(S_t\) bildet das regelmäßig wiederkehrende Jahresmuster ab.
  • \(R_t\) enthält die Variation, die weder durch \(T_t\) noch durch \(S_t\) erklärt wird; dort treten insbesondere ungewöhnliche Monate deutlicher hervor.

Damit haben wir die beobachtete Reihe auf der transformierten Skala als

\[ w_t = S_t + T_t + R_t \]

beschrieben.

Typische Fehlvorstellung: Die remainder component \(R_t\) ist nicht automatisch White Noise. Ob darin noch systematische zeitliche Struktur vorhanden ist, muss diagnostisch geprüft werden.

10. Zwischenfazit der EDA

Bevor wir ein Prognosemodell auswählen, halten wir unsere Beobachtungen fest.

Frage Ergebnis
Gibt es einen Trend?
Gibt es Saisonalität?
Wie groß ist die saisonale Periode \(m\)?
Ist die saisonale Variation auf der Originalskala ungefähr konstant?
Gibt es Autokorrelation?
Gibt es ungewöhnliche Beobachtungen?
Gibt es möglicherweise relevante externe Variablen?

Diskussion

Füllen Sie die Tabelle gemeinsam anhand der bisherigen Analysen aus.

Frage Ergebnis
Gibt es einen Trend? Ja, langfristig steigendes Niveau
Gibt es Saisonalität? Ja, deutliches jährliches Muster
Wie groß ist die saisonale Periode \(m\)? \(m=12\)
Ist die saisonale Variation auf der Originalskala ungefähr konstant? Nein, sie nimmt mit dem Niveau zu
Gibt es Autokorrelation? Ja, insbesondere bei kleinen und saisonalen Lags
Gibt es ungewöhnliche Beobachtungen? Ja, u. a. Juli 2016 und März 2018
Gibt es möglicherweise relevante externe Variablen? Marketing und Discount sind plausible Kandidaten

Typische Fehlvorstellung: Ein Zusammenhang zwischen Marketing und Orders wäre noch kein Nachweis eines kausalen Marketingeffekts. Beide Variablen können beispielsweise gemeinsam saisonalen Mustern folgen.

Übergang: Von der Beschreibung zur Prognose

Unsere Forecastvariable \(y_t\) besitzt damit mehrere relevante Strukturen:

\[ \boxed{ \text{Trend} + \text{Saisonalität} + \text{Autokorrelation} + \text{mögliche externe Einflussgrößen} } \]

Die nächste Frage lautet deshalb:

Wie können wir diese unterschiedlichen Arten von Information nutzen, um zukünftige Werte zu prognostizieren?

In der Notation von FPP3 interessiert uns eine Prognose

\[ \hat y_{T+h\mid T}, \]

also die Prognose für den Zeitpunkt \(T+h\) auf Basis der Informationen, die bis zum Zeitpunkt \(T\) verfügbar sind.

Im nächsten Teil betrachten wir verschiedene Möglichkeiten, aus der bisher erkannten Struktur ein Prognosemodell zu entwickeln.

Teil 2: Von der Zeitreihe zur Prognose – Benchmark und Testdaten

In Teil 1 haben wir die Struktur unserer Bestellzahlen untersucht. Wir haben einen steigenden Trend, eine deutliche jährliche Saisonalität mit \(m=12\), zeitliche Abhängigkeiten und mögliche externe Einflussgrössen erkannt.

Jetzt wechseln wir die Perspektive. Wir wollen nicht mehr erklären, was in der Vergangenheit passiert ist, sondern prognostizieren, was als Nächstes passiert.

Die zentrale Grösse ist

\[ \hat y_{T+h\mid T}, \]

also die Prognose für den Zeitpunkt \(T+h\) auf Basis der Informationen, die bis zum Zeitpunkt \(T\) verfügbar sind.

1. Wie testen wir eine Prognose, ohne in die Zukunft zu schauen?

Unser Datensatz enthält 84 Monate von Januar 2013 bis Dezember 2019. Für die Modellentwicklung tun wir so, als befänden wir uns Ende 2018.

Die ersten 72 Monate verwenden wir als Trainingsdaten, die letzten 12 Monate halten wir als Testdaten zurück:

\[ \underbrace{y_1,\ldots,y_{72}}_{\text{Training}} \qquad \underbrace{y_{73},\ldots,y_{84}}_{\text{Test}}. \]

Damit liegt unser Forecast Origin bei \(T=72\) und der maximale Prognosehorizont beträgt \(h=12\).

Querreferenz: FPP3, Chapter 5, Abschnitt Evaluating point forecast accuracy (Training and test sets).

Code
shop_train <- shop |>
  filter(Month <= yearmonth("2018 Dec"))

shop_test <- shop |>
  filter(Month > yearmonth("2018 Dec"))
Code
shop |>
  autoplot(Orders) +
  geom_vline(
    xintercept = yearmonth("2019 Jan"),
    linetype = "dashed"
  ) +
  annotate(
    "text",
    x = yearmonth("2018 Jun"),
    y = max(shop$Orders) * 1.02,
    label = "Training",
    hjust = 1
  ) +
  annotate(
    "text",
    x = yearmonth("2019 Jun"),
    y = max(shop$Orders) * 1.02,
    label = "Test",
    hjust = 0.5
  ) +
  labs(
    title = "Wir simulieren eine echte Prognosesituation",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 8: Trainings- und Testzeitraum der Bestellzahlen.

Diskussion

Warum teilen wir eine Zeitreihe nicht einfach zufällig in 80 % Trainings- und 20 % Testdaten auf?

Bei einer echten Prognose kennen wir zum Zeitpunkt \(T\) nur die Vergangenheit. Ein zufälliger Split würde diese zeitliche Ordnung zerstören und könnte Beobachtungen aus der späteren Zukunft zur Modellschätzung verwenden.

Die Testdaten müssen deshalb zeitlich nach den Trainingsdaten liegen. Nur so simulieren wir die Situation

\[ \text{Vergangenheit} \longrightarrow \text{unbekannte Zukunft}. \]

Die Werte des Jahres 2019 werden bei der Modellschätzung zunächst nicht verwendet. Erst nachdem die Prognosen erstellt wurden, decken wir sie zur Beurteilung der Prognosegüte auf.

Typische Fehlvorstellung: Ein zufälliger Train/Test-Split ist bei Zeitreihen in der Regel ungeeignet, weil dadurch zukünftige Information in die Modellbildung gelangen kann.

2. Was wäre eine vernünftige Prognose ohne komplexes Modell?

Bevor wir ein aufwendigeres Modell fitten, brauchen wir einen Benchmark.

Schauen wir nochmals auf das Ende unserer Trainingsreihe.

Code
shop_train |>
  filter(Month >= yearmonth("2016 Jan")) |>
  autoplot(Orders) +
  labs(
    title = "Welche einfache Regel könnte bereits funktionieren?",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 9: Die letzten drei Jahre der Trainingsdaten.

Diskussion

Sie dürfen noch kein Modell fitten. Wie würden Sie die Bestellungen für Januar 2019 prognostizieren? Welcher vergangene Monat erscheint besonders informativ?

Unsere EDA hat eine ausgeprägte jährliche Saisonalität mit \(m=12\) gezeigt. Deshalb ist für Januar 2019 insbesondere der Januar 2018 ein naheliegender Vergleichswert.

Für die nächsten zwölf Monate ergibt sich die seasonal naïve forecast method:

\[ \hat y_{T+h\mid T}=y_{T+h-12}, \qquad h=1,\ldots,12. \]

Jeder Monat des Prognosejahres erhält also zunächst den beobachteten Wert desselben Monats im Vorjahr.

Querreferenz: FPP3, Chapter 5, Abschnitt Some simple forecasting methods (Naïve method und Seasonal naïve method).

Typische Fehlvorstellung: Die einfachste sinnvolle Prognose ist nicht zwingend der zuletzt beobachtete Wert \(y_T\). Bei saisonalen Daten kann derselbe Zeitraum der vorherigen Saison ein wesentlich besserer Benchmark sein.

3. Zwei einfache Benchmarks gegeneinander testen

Zum Vergleich fitten wir zwei sehr einfache Prognosemethoden:

  • Naïve: Jeder zukünftige Wert wird mit dem letzten beobachteten Wert prognostiziert.
  • Seasonal naïve: Jeder zukünftige Monat wird mit demselben Monat des Vorjahres prognostiziert.

Für die naïve Methode gilt

\[ \hat y_{T+h\mid T}=y_T. \]

Für unsere saisonale Reihe mit \(m=12\) und \(h\leq 12\) gilt

\[ \hat y_{T+h\mid T}=y_{T+h-12}. \]

Code
benchmark_fit <- shop_train |>
  model(
    `Naïve` = NAIVE(Orders),
    `Seasonal naïve` = SNAIVE(Orders ~ lag("year"))
  )

benchmark_fc <- benchmark_fit |>
  forecast(h = "1 year")
Code
benchmark_fc |>
  autoplot(shop, level = NULL) +
  labs(
    title = "Wie gut funktionieren sehr einfache Prognosen?",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 10: Naïve und seasonal naïve Prognosen für das zurückgehaltene Jahr 2019.

Diskussion

Welche der beiden Methoden bildet die tatsächliche Entwicklung im Testjahr plausibler ab? Warum war dieses Ergebnis nach Teil 1 zu erwarten?

Die naïve Prognose übernimmt für alle zwölf Monate den Wert von Dezember 2018. Sie ignoriert damit die ausgeprägte Saisonalität der Reihe.

Die seasonal naïve Methode übernimmt dagegen das monatliche Muster des Vorjahres und passt deshalb deutlich besser zur Struktur, die wir in Teil 1 erkannt haben.

Sie ist trotzdem kein vollständiges Modell unserer Reihe: Insbesondere ein längerfristiger Trend wird nicht explizit fortgeschrieben.

Typische Fehlvorstellung: Ein guter Benchmark muss nicht möglichst komplex sein. Seine Aufgabe ist gerade, eine einfache, aber schwer zu schlagende Referenz für komplexere Modelle bereitzustellen.

4. Prognosefehler: Jetzt dürfen wir in die Testdaten schauen

Nachdem die Prognosen erstellt wurden, können wir sie mit den tatsächlich beobachteten Bestellungen des Jahres 2019 vergleichen.

Für einen zukünftigen Zeitpunkt \(T+h\) definieren wir den Prognosefehler als

\[ e_{T+h}=y_{T+h}-\hat y_{T+h\mid T}. \]

Ein positiver Fehler bedeutet also, dass die tatsächliche Bestellzahl höher war als prognostiziert; ein negativer Fehler bedeutet eine Überschätzung.

Zwei häufig verwendete Kennzahlen sind der Mean Absolute Error (MAE)

\[ \operatorname{MAE} = \frac{1}{H} \sum_{h=1}^{H}|e_{T+h}| \]

und der Root Mean Squared Error (RMSE)

\[ \operatorname{RMSE} = \sqrt{ \frac{1}{H} \sum_{h=1}^{H}e_{T+h}^2 }. \]

Der RMSE gewichtet grosse Fehler stärker, weil die Fehler vor dem Mitteln quadriert werden.

Querreferenz: FPP3, Chapter 5, Abschnitt Evaluating point forecast accuracy (Forecast errors und Scale-dependent errors).

Code
benchmark_accuracy <- benchmark_fc |>
  accuracy(shop) |>
  select(.model, RMSE, MAE)

benchmark_accuracy
# A tibble: 2 × 3
  .model          RMSE   MAE
  <chr>          <dbl> <dbl>
1 Naïve          1297. 1232.
2 Seasonal naïve  181.  143.

Diskussion

Welche Methode würden Sie aufgrund der Testdaten als Benchmark für die nächsten Modellschritte verwenden?

Für unsere stark saisonale Zeitreihe ist die seasonal naïve Methode der sinnvollere Benchmark. Sie nutzt bereits eine zentrale Struktur der Daten, ohne ein komplexes Modell zu benötigen.

Alle folgenden Modelle sollten deshalb zeigen, ob sie gegenüber

\[ \hat y_{T+h\mid T}=y_{T+h-12} \]

einen erkennbaren zusätzlichen Nutzen liefern.

MAE und RMSE beantworten dabei leicht unterschiedliche Fragen. Der MAE beschreibt die durchschnittliche absolute Abweichung in Bestellungen, während der RMSE grössere Prognosefehler stärker gewichtet.

Typische Fehlvorstellung: Der kleinste Fehler in einem einzigen Testjahr beweist nicht, dass ein Modell generell überlegen ist. Der Testzeitraum liefert eine empirische Beurteilung für genau diese bisher ungesehenen Beobachtungen.

5. Forecast Error ist nicht dasselbe wie Residuum

Für die späteren Modellvergleiche ist eine Unterscheidung wichtig.

Ein Forecast Error entsteht für eine Beobachtung, die bei der Modellschätzung noch nicht bekannt war:

\[ e_{T+h}=y_{T+h}-\hat y_{T+h\mid T}. \]

Ein Residuum entsteht dagegen innerhalb der Daten, auf denen ein Modell geschätzt wurde. Residuen verwenden wir später vor allem zur Modelldiagnostik: Sie sollen uns zeigen, ob im Modell noch systematische Struktur übrig geblieben ist.

Querreferenz: FPP3, Chapter 5, Abschnitt Fitted values and residuals. Zur späteren Diagnose siehe auch Residual diagnostics.

Diskussion

Warum eignet sich ein kleiner Residuenfehler allein nicht als Nachweis für gute Prognosen?

Ein Modell wurde gerade so gewählt und geschätzt, dass es die Trainingsdaten möglichst gut beschreibt. Kleine Residuen zeigen daher zunächst nur eine gute Anpassung an bereits bekannte Daten.

Für eine Prognose interessiert uns dagegen, wie gut das Modell mit noch unbekannten Beobachtungen zurechtkommt. Deshalb beurteilen wir Prognosegüte an zurückgehaltenen Testdaten.

Typische Fehlvorstellung: Gute Anpassung an die Vergangenheit und gute Prognoseleistung sind nicht dasselbe. Ein Modell kann Trainingsdaten sehr genau beschreiben und trotzdem zukünftige Werte schlecht prognostizieren.

Zwischenfazit: Unser Referenzpunkt für die Modellierung

Wir haben nun eine echte Prognosesituation nachgebildet:

\[ \boxed{ \text{Training} \rightarrow \text{Forecast} \rightarrow \text{Testdaten aufdecken} \rightarrow \text{Forecast Error} } \]

Aus der EDA wussten wir bereits, dass die Bestellzahlen stark saisonal sind. Deshalb verwenden wir ab jetzt die seasonal naïve Methode als Benchmark.

Die nächste Frage ist nicht mehr, ob wir überhaupt prognostizieren können, sondern:

Welche zusätzliche Information können komplexere Modelle gegenüber diesem einfachen Benchmark nutzen?

Dabei werden wir drei unterschiedliche Modellideen vergleichen:

\[ \boxed{ \text{Regression} \qquad \text{ETS} \qquad \text{ARIMA} } \]

Sie nutzen unterschiedliche Arten von Information aus derselben Zeitreihe – und müssen sich am Ende alle an unserem Benchmark messen lassen.

Teil 3: Drei Modellideen – und was der Output wirklich bedeutet

In Teil 2 haben wir mit der seasonal naïve Methode einen Benchmark festgelegt. Jetzt fitten wir drei Modellklassen, die dieselbe Prognoseaufgabe mit unterschiedlichen Informationsquellen lösen.

Modellidee Welche Information wird genutzt?
Regression Trend, Saison und bekannte externe Einflussgrössen
ETS Niveau, Trend und Saisonalität der Zeitreihe selbst
ARIMA zeitliche Abhängigkeit zwischen Beobachtungen bzw. Fehlern

Für alle drei Modelle verwenden wir dieselben Trainingsdaten bis Dezember 2018. Das Jahr 2019 bleibt weiterhin unangetastet und dient erst später zur Evaluation.

Code
# Für die Regression nehmen wir an, dass Marketingbudget und Rabattplanung
# für das Prognosejahr bereits bekannt sind.
forecast_plan <- shop_test |>
  select(Month, Marketing, Discount)
TippSo lesen wir jeden Modell-Output

Für jedes Modell gehen wir in derselben Reihenfolge vor:

  1. Modellstruktur: Was wird überhaupt modelliert?
  2. Transformation: Auf welcher Skala arbeitet das Modell und was bedeutet das mathematisch?
  3. Parameter: Welche Grössen wurden aus den Trainingsdaten geschätzt?
  4. Modellgüte: Welche Kennzahlen beziehen sich auf den Fit im Training?
  5. Forecasting: Welche Information kann das Modell in die Zukunft fortschreiben – und welche nicht?

Die zurückgehaltenen Testdaten spielen dabei noch keine Rolle.

1. Zeitreihenregression: bekannte Struktur und externe Information

TippGrundidee: Zeitreihenregression

Bei der Regression erklären wir die Zielgrösse durch bekannte oder beobachtbare Einflussgrössen. Für eine Zeitreihe können dazu neben externen Prädiktoren auch Trend und Saison gehören.

\[ y_t = \beta_0 + \beta_1 x_{1,t} + \cdots + \beta_k x_{k,t} + \varepsilon_t. \]

Für zukünftige Prognosen müssen die zukünftigen Werte externer Prädiktoren bekannt, geplant oder separat prognostiziert werden.

Merksatz: Regression nutzt systematische und externe Information.

Querreferenz: FPP3, Chapter 7, Time series regression models; zur Transformation zusätzlich Chapter 3.1, Transformations and adjustments.

Warum modellieren wir \(\log(\text{Orders})\)?

Unsere EDA hat gezeigt, dass die absolute saisonale Schwankung mit dem Niveau der Bestellzahlen zunimmt. Das spricht eher für eine proportionale bzw. multiplikative Struktur auf der Originalskala.

Wir definieren deshalb

\[ w_t = \log(y_t). \]

Diskussion

Was bewirkt diese Transformation mathematisch? Warum kann sie für unsere Daten sinnvoll sein?

Eine multiplikative Struktur

\[ y_t = T_t \cdot S_t \cdot R_t \]

wird durch Logarithmieren additiv:

\[ \log(y_t) = \log(T_t) + \log(S_t) + \log(R_t). \]

Damit können proportionale Effekte mit einem linearen Modell beschrieben werden. Zudem entspricht eine Differenz auf der Log-Skala einer relativen Änderung auf der Originalskala.

Ist beispielsweise

\[ \log(y_t) = \ldots + \beta x_t + \ldots, \]

dann verändert eine Erhöhung von \(x_t\) um eine Einheit den erwarteten Wert von \(y_t\) um den Faktor

\[ e^{\beta}. \]

Die exakte prozentuale Änderung beträgt daher

\[ 100\left(e^{\beta}-1\right)\%. \]

Für kleine \(\beta\) gilt näherungsweise \(100\beta\%\).

Typische Fehlvorstellung: Die Logarithmierung wird hier nicht primär eingesetzt, um die Daten “normalzuverteilen”. Sie hilft uns vor allem, eine mit dem Niveau zunehmende Variation und proportionale Effekte einfacher zu modellieren.

Ein mögliches Modell lautet

\[ w_t = \beta_0 +\beta_1 t +\text{Saisoneffekt}_t +\beta_2\,\text{Marketing}_t +\beta_3\,\text{Discount}_t +\varepsilon_t. \]

Wir fitten es mit TSLM().

Code
reg_fit <- shop_train |>
  model(
    Regression = TSLM(
      log(Orders) ~ trend() + season() + Marketing + Discount
    )
  )

reg_fit |>
  report()
Series: Orders 
Model: TSLM 
Transformation: log(Orders) 

Residuals:
     Min       1Q   Median       3Q      Max 
-0.16952 -0.03057  0.00309  0.03433  0.12211 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     7.0813419  0.0839648  84.337  < 2e-16 ***
trend()         0.0037001  0.0004266   8.674 5.28e-12 ***
season()year2   0.0243213  0.0354078   0.687 0.494937    
season()year3   0.1244109  0.0357320   3.482 0.000963 ***
season()year4   0.1962660  0.0353816   5.547 7.83e-07 ***
season()year5   0.1986419  0.0360862   5.505 9.17e-07 ***
season()year6   0.2069762  0.0355265   5.826 2.77e-07 ***
season()year7   0.1011099  0.0360421   2.805 0.006864 ** 
season()year8   0.1083441  0.0354428   3.057 0.003402 ** 
season()year9   0.1824920  0.0358796   5.086 4.25e-06 ***
season()year10  0.2901304  0.0365660   7.934 8.83e-11 ***
season()year11  0.4860960  0.0533538   9.111 1.02e-12 ***
season()year12  0.5754087  0.0589720   9.757 9.18e-14 ***
Marketing       0.0049911  0.0023457   2.128 0.037697 *  
Discount       -0.0046177  0.0083412  -0.554 0.582018    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.06075 on 57 degrees of freedom
Multiple R-squared: 0.9371, Adjusted R-squared: 0.9216
F-statistic: 60.63 on 14 and 57 DF, p-value: < 2.22e-16

Diskussion 1: Modellgleichung und Saison-Dummies lesen

Welche Teile unseres Modells finden Sie im Output wieder? Warum erscheinen bei zwölf Monaten nur elf Saisonkoeffizienten?

Im Output finden wir den Intercept, den Trend, elf Saisonkoeffizienten sowie die Koeffizienten von Marketing und Discount.

Bei zwölf saisonalen Kategorien werden mit einem Intercept nur elf Dummyvariablen benötigt. Die erste saisonale Position ist die Referenzkategorie. Alle Koeffizienten season()year2 bis season()year12 beschreiben Unterschiede relativ zu dieser Referenz.

Da unsere Reihe im Januar beginnt, entspricht year1 hier dem Januar.

Typische Fehlvorstellung: Ein fehlender Koeffizient für den ersten Monat bedeutet nicht, dass Januar “keinen Effekt” hat. Er bildet die Referenz, relativ zu der die anderen Monatseffekte gemessen werden.

Diskussion 2: Trend und Saisoneffekte auf der Originalskala

Wie interpretieren wir den geschätzten Trendkoeffizienten \(0.0037001\)? Und was bedeutet beispielsweise season()year12 = 0.5754?

Der Trendkoeffizient ist auf der Log-Skala additiv. Auf der Originalskala wirkt er multiplikativ:

\[ e^{0.0037001} \approx 1.00371. \]

Ein zusätzlicher Monat entspricht damit unter sonst gleichen Bedingungen ungefähr 0.37 % mehr Bestellungen.

Über zwölf Monate ergibt sich

\[ e^{12\cdot0.0037001}-1 \approx 0.0454, \]

also ungefähr 4.5 % Wachstum pro Jahr.

Für den zwölften saisonalen Zustand erhalten wir

\[ e^{0.5754}-1 \approx 0.778. \]

Der erwartete Wert liegt damit im zwölften Monat bei sonst gleichen Bedingungen ungefähr 77.8 % über dem Referenzmonat.

Typische Fehlvorstellung: Ein linearer Trend in \(\log(y_t)\) bedeutet keinen konstanten absoluten Zuwachs von Bestellungen. Auf der Originalskala entspricht er einem näherungsweise konstanten prozentualen Wachstum.

Diskussion 3: Externe Prädiktoren interpretieren

Was sagen die Koeffizienten von Marketing und Discount? Welche Rolle spielen ihre p-Werte?

Für Marketing wird

\[ \hat\beta_{\text{Marketing}}=0.0049911 \]

geschätzt. Da Marketing in Tsd. CHF gemessen wird, entspricht eine zusätzliche Einheit ungefähr

\[ 100\left(e^{0.0049911}-1\right)\% \approx 0.50\% \]

mehr erwarteten Bestellungen, wenn die übrigen Variablen konstant gehalten werden. Der p-Wert von etwa \(0.038\) liefert im Modell Evidenz dafür, dass dieser bedingte Zusammenhang von null verschieden ist.

Für Discount erhalten wir dagegen

\[ \hat\beta_{\text{Discount}}=-0.0046177 \]

mit einem p-Wert von etwa \(0.58\). Nach Berücksichtigung von Trend, Saison und Marketing liefert Discount in diesen Trainingsdaten damit keine klare zusätzliche lineare Information.

Typische Fehlvorstellung: Ein signifikanter Regressionskoeffizient beweist keine Kausalität. Das Modell beschreibt zunächst bedingte statistische Zusammenhänge.

Diskussion 4: \(R^2\), F-Test und die Zeitreihen-Besonderheit

Das Modell hat \(R^2\approx0.94\). Ist damit bereits gezeigt, dass es gut prognostiziert?

Nein. Das \(R^2\) von ungefähr \(0.94\) beschreibt, wie viel Variation von \(\log(\text{Orders})\) innerhalb der Trainingsdaten durch das Modell erklärt wird.

Ob das Modell zukünftige Monate gut prognostiziert, können wir erst mit den zurückgehaltenen Testdaten beurteilen.

Zusätzlich müssen wir bei einer Zeitreihenregression prüfen, ob in den Residuen noch zeitliche Abhängigkeit steckt. Ist dies der Fall, sind nicht nur Prognosen potenziell verbesserbar; auch die üblichen Standardfehler und Tests der Regression müssen vorsichtig interpretiert werden.

Typische Fehlvorstellung: Ein sehr hohes \(R^2\) ist kein Beweis für gute Out-of-sample-Prognosen.

Forecasting-Besonderheit der Regression

Welche Informationen müssen wir für 2019 kennen, die ETS oder ARIMA nicht zwingend benötigen?

Trend und Saison können aus dem zukünftigen Zeitindex erzeugt werden. Die Werte von Marketing und Discount müssen für 2019 dagegen bekannt, geplant oder separat prognostiziert werden.

In unserer Fallstudie interpretieren wir sie als bereits bekannte Planwerte.

Typische Fehlvorstellung: Ein Regressionsmodell prognostiziert seine zukünftigen Prädiktoren nicht automatisch mit.

Code
reg_fc <- reg_fit |>
  forecast(new_data = forecast_plan)
Code
reg_fc |>
  autoplot(shop_train, level = NULL) +
  labs(
    title = "Regression: Trend, Saison und geplante Einflussgrössen",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 11: Prognose des Zeitreihen-Regressionsmodells für 2019.

2. ETS: Zustände der Zeitreihe fortschreiben

TippGrundidee: Exponential Smoothing / ETS

ETS beschreibt eine Zeitreihe durch wenige Zustände, beispielsweise

\[ \text{Niveau},\qquad \text{Trend},\qquad \text{Saison}. \]

Die Zustände werden rekursiv mit jeder neuen Beobachtung aktualisiert. Schon beim Simple Exponential Smoothing gilt

\[ \ell_t = \alpha y_t + (1-\alpha)\ell_{t-1}. \]

Durch wiederholtes Einsetzen entstehen Gewichte der Form

\[ \alpha(1-\alpha)^j. \]

Das exponentielle Abklingen ist damit eine Folge der rekursiven Update-Regel. Im vollständigen ETS-Framework können Level, Trend und Saison eigene Glättungsparameter besitzen.

Merksatz: ETS nutzt die interne Zustandsdynamik der Reihe. Externe Variablen wie Marketing oder Rabatt gehören nicht zum klassischen ETS-Modell.

Querreferenz: FPP3, Chapter 8, insbesondere Sections 8.5–8.6.

Auch ETS fitten wir auf der logarithmierten Reihe:

Code
ets_fit <- shop_train |>
  model(
    ETS = ETS(log(Orders))
  )

ets_fit |>
  report()
Series: Orders 
Model: ETS(A,N,A) 
Transformation: log(Orders) 
  Smoothing parameters:
    alpha = 0.3836365 
    gamma = 0.0001000735 

  Initial states:
     l[0]      s[0]     s[-1]      s[-2]       s[-3]      s[-4]      s[-5]
 7.465499 0.4035382 0.3087902 0.09956319 -0.02716161 -0.1036476 -0.1279992
       s[-6]       s[-7]       s[-8]       s[-9]     s[-10]     s[-11]
 -0.01478926 -0.03055995 -0.02282179 -0.07456067 -0.1940483 -0.2163033

  sigma^2:  0.0043

      AIC      AICc       BIC 
-70.57818 -62.00675 -36.42819 

Diskussion 1: ETS(A,N,A) entschlüsseln

Was bedeuten die drei Buchstaben im ausgewählten Modell? Welche Zustände besitzt unser konkretes Modell?

ETS(A,N,A) steht für

\[ \operatorname{ETS}(\text{Error},\text{Trend},\text{Seasonal}). \]

In unserem Fall bedeutet das:

  • A: additive Fehler,
  • N: kein eigener Trendzustand,
  • A: additive Saisonkomponente.

Da wir \(w_t=\log(y_t)\) modellieren, gilt diese additive Struktur zunächst auf der Log-Skala.

Für monatliche Daten mit \(m=12\) lässt sich das ausgewählte Modell schematisch schreiben als

\[ w_t = \ell_{t-1}+s_{t-12}+\varepsilon_t, \]

\[ \ell_t = \ell_{t-1}+\alpha\varepsilon_t, \]

\[ s_t = s_{t-12}+\gamma\varepsilon_t. \]

Typische Fehlvorstellung: Das N bedeutet nicht, dass sich das Niveau der Reihe nicht verändern kann. Es bedeutet nur, dass kein separater Trendzustand extrapoliert wird.

Diskussion 2: Was bewirkt die Logarithmierung bei ETS?

Wenn Saison und Fehler auf der Log-Skala additiv sind: Was bedeutet das auf der Originalskala?

Auf der Log-Skala gilt für die systematische Komponente

\[ w_t \approx \ell_{t-1}+s_{t-12}. \]

Nach Rücktransformation folgt

\[ y_t \approx e^{\ell_{t-1}}\cdot e^{s_{t-12}}. \]

Die additive Saisonkomponente \(s_t\) auf der Log-Skala wird damit auf der Originalskala zu einem multiplikativen saisonalen Faktor \(e^{s_t}\).

Genau deshalb passt die Logarithmierung zu unserer EDA: Die absolute saisonale Schwankung kann mit dem Niveau wachsen, während die relative saisonale Struktur stabil bleibt.

fable führt die Rücktransformation der Forecast-Verteilung automatisch durch.

Typische Fehlvorstellung: A in ETS(A,N,A) bedeutet hier nicht automatisch additive Schwankungen in der ursprünglichen Anzahl Bestellungen. Das Modell ist additiv auf der transformierten Log-Skala.

Diskussion 3: \(\alpha\) und \(\gamma\) als Lernraten

Im Output finden wir \(\alpha=0.3836\) und \(\gamma\approx0.0001\). Was lernen wir daraus über Level und Saisonalität?

Für das Level gilt

\[ \ell_t=\ell_{t-1}+\alpha\varepsilon_t. \]

Mit

\[ \alpha=0.3836 \]

werden rund \(38\%\) des aktuellen Fehlers zur Korrektur des Level-Zustands verwendet. Beim einfachen Level-Update entspricht

\[ 1-\alpha\approx0.6164 \]

dem Faktor, mit dem ältere Level-Information von einem Schritt zum nächsten weiterwirkt.

Für die Saison gilt

\[ s_t=s_{t-12}+\gamma\varepsilon_t. \]

Mit

\[ \gamma\approx0.0001 \]

wird die Saisonkomponente praktisch nicht aktualisiert. Das Modell sieht das jährliche saisonale Muster also als sehr stabil an.

Ein \(\beta\) erscheint nicht, weil ETS(A,N,A) keinen Trendzustand besitzt.

Typische Fehlvorstellung: \(\gamma\) beschreibt nicht die Stärke der Saisonalität. Es beschreibt, wie schnell die saisonalen Zustände auf neue Information reagieren.

Diskussion 4: Initial states lesen

Was bedeuten \(\ell_0\) und die zwölf saisonalen Anfangszustände?

ETS benötigt einen Ausgangspunkt für seine rekursive Zustandsentwicklung. Im Output ist

\[ \ell_0=7.465499. \]

Auf der Originalskala entspricht das ungefähr

\[ e^{7.465499}\approx1747 \]

Bestellungen.

Die zwölf Werte \(s_0,s_{-1},\ldots,s_{-11}\) sind die geschätzten saisonalen Anfangszustände auf der Log-Skala. Ein Wert \(s\) entspricht auf der Originalskala dem saisonalen Faktor

\[ e^s. \]

Die Anfangszustände werden zusammen mit den Glättungsparametern aus den Trainingsdaten geschätzt.

Typische Fehlvorstellung: Die Initial States sind keine zusätzlichen beobachteten Datenpunkte. Sie sind geschätzte Startwerte des dynamischen Modells.

Diskussion 5: Wie wurden Parameter und Modellstruktur gewählt?

Verwendet Maximum Likelihood dafür unsere Testdaten? Und welche Rolle spielt der AICc?

Nein. ETS() sieht nur die Trainingsdaten.

Innerhalb eines vorgegebenen ETS-Modells werden Glättungsparameter und Anfangszustände so gewählt, dass die Likelihood der Trainingsdaten maximal wird. Bei additiven normalverteilten Fehlern entspricht dies der Minimierung der quadrierten One-step-ahead-Fehler im Training.

Anschliessend werden konkurrierende ETS-Strukturen mit Informationskriterien verglichen. ETS() verwendet dafür standardmässig den AICc.

Vereinfacht:

\[ \boxed{\text{Likelihood} \rightarrow \text{Parameter innerhalb eines Modells}} \]

\[ \boxed{\text{AICc} \rightarrow \text{Auswahl zwischen ETS-Modellen}} \]

Die Testdaten bleiben für die spätere unabhängige Evaluation unangetastet.

Typische Fehlvorstellung: Die zurückgehaltenen Testdaten werden nicht zur Optimierung von \(\alpha\), \(\gamma\) oder der ETS-Struktur verwendet.

Diskussion 6: Was bedeutet N für den Forecast?

Wir haben in Teil 1 einen langfristigen Anstieg gesehen. Trotzdem wurde ETS(A,N,A) gewählt. Was bedeutet das für die Prognose?

Das Level \(\ell_t\) kann sich während der Trainingsperiode laufend verändern. N bedeutet aber, dass das Modell keinen separaten Trendzustand besitzt, der über den Forecast Origin hinaus weiter extrapoliert wird.

Für die Zukunft wird daher im Wesentlichen das zuletzt geschätzte Niveau mit dem saisonalen Muster kombiniert.

Das ist eine konkrete Modellentscheidung, die wir später an den Testdaten überprüfen müssen.

Typische Fehlvorstellung: Ein Modell ohne expliziten Trend kann in den Trainingsdaten trotzdem ein steigendes Level zeigen. Entscheidend ist, dass dieser Anstieg nicht als eigener Trendzustand in die Zukunft fortgeschrieben wird.

Code
ets_fc <- ets_fit |>
  forecast(h = "1 year")
Code
ets_fc |>
  autoplot(shop_train, level = NULL) +
  labs(
    title = "ETS: die interne Struktur der Reihe fortschreiben",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 12: ETS-Prognose für 2019.

3. ARIMA: Abhängigkeiten nach Transformation und Differenzierung modellieren

TippGrundidee: ARIMA

ARIMA modelliert die zeitliche Abhängigkeit einer Zeitreihe. Ein nicht-saisonales Modell wird durch

\[ \operatorname{ARIMA}(p,d,q) \]

beschrieben:

  • AR(\(p\)): Abhängigkeit von vergangenen Werten,
  • I(\(d\)): Differenzierung,
  • MA(\(q\)): Abhängigkeit von vergangenen Innovationsfehlern.

Bei saisonalen Daten kann zusätzlich ein saisonaler Teil

\[ (P,D,Q)_m \]

auftreten.

Merksatz: ARIMA versucht, die nach Transformation und gegebenenfalls Differenzierung verbleibende zeitliche Abhängigkeit zu erklären.

Querreferenz: FPP3, Chapter 9, insbesondere Sections 9.6–9.7.

Wir lassen ARIMA() ein Modell für die logarithmierten Bestellzahlen auswählen.

Code
arima_fit <- shop_train |>
  model(
    ARIMA = ARIMA(log(Orders))
  )

arima_fit |>
  report()
Series: Orders 
Model: ARIMA(0,0,1)(0,1,1)[12] w/ drift 
Transformation: log(Orders) 

Coefficients:
         ma1     sma1  constant
      0.4961  -0.7402    0.0509
s.e.  0.1376   0.2135    0.0062

sigma^2 estimated as 0.003989:  log likelihood=77.48
AIC=-146.96   AICc=-146.23   BIC=-138.58

Diskussion 1: Die Modellbezeichnung lesen

Welche Werte für \(p\), \(d\) und \(q\) wurden gewählt? Gibt es zusätzlich einen saisonalen ARIMA-Teil?

Lesen Sie die Modellbezeichnung im Output von links nach rechts.

Für

\[ \operatorname{ARIMA}(p,d,q) \]

bedeutet

  • \(p\): Anzahl der nicht-saisonalen AR-Terme,
  • \(d\): Anzahl der nicht-saisonalen Differenzen,
  • \(q\): Anzahl der nicht-saisonalen MA-Terme.

Falls zusätzlich ein saisonaler Ausdruck \((P,D,Q)_{12}\) erscheint, beziehen sich \(P\), \(D\) und \(Q\) auf Abhängigkeiten im saisonalen Abstand von zwölf Monaten.

ARIMA() bestimmt die Differenzierungsordnung nicht einfach durch Vergleich aller AICc-Werte. Im automatischen Verfahren wird \(d\) über Unit-Root-Tests bestimmt; für die Auswahl von \(p\) und \(q\) wird anschliessend unter anderem der AICc verwendet.

Typische Fehlvorstellung: \(d\) ist kein Regressionskoeffizient. Es gibt an, wie oft die Reihe differenziert wird.

Diskussion 2: Was bewirkt die Logarithmierung zusammen mit Differenzierung?

Warum ist \(\Delta\log(y_t)\) inhaltlich besonders gut interpretierbar?

Bei einer Differenz erster Ordnung auf der Log-Skala gilt

\[ \Delta w_t = \log(y_t)-\log(y_{t-1}) = \log\left(\frac{y_t}{y_{t-1}}\right). \]

ARIMA modelliert dann nicht mehr primär absolute Änderungen, sondern relative Veränderungen. Für kleine Änderungen gilt näherungsweise

\[ \Delta\log(y_t) \approx \frac{y_t-y_{t-1}}{y_{t-1}}. \]

Eine saisonale Differenz auf der Log-Skala besitzt entsprechend die Interpretation

\[ \log(y_t)-\log(y_{t-12}) = \log\left(\frac{y_t}{y_{t-12}}\right). \]

Typische Fehlvorstellung: Logarithmieren und Differenzieren sind nicht dasselbe. Die Logarithmierung verändert die Skala; die Differenzierung entfernt bestimmte zeitliche Veränderungen des Niveaus bzw. der Saison.

Diskussion 3: AR- und MA-Koeffizienten interpretieren

Welche Koeffizienten erscheinen im Output? Was bedeutet beispielsweise ein ar1- oder ma1-Term?

Ein AR-Koeffizient beschreibt den linearen Einfluss vergangener Werte der bereits transformierten und gegebenenfalls differenzierten Reihe. Ein ar1-Term bezieht sich beispielsweise auf den Lag 1.

Ein MA-Koeffizient beschreibt dagegen den Einfluss vergangener Innovationen bzw. Prognosefehler. Ein ma1-Term bezieht sich auf den Fehler der unmittelbar vorhergehenden Periode.

Saisonale Terme wie sar1 oder sma1 wirken analog im saisonalen Abstand \(m=12\).

Die Koeffizienten sind keine Autokorrelationskoeffizienten. Sie sind Parameter eines gemeinsamen dynamischen Modells.

Typische Fehlvorstellung: Ein MA-Term verwendet nicht direkt den vergangenen beobachteten Wert \(y_{t-1}\), sondern einen vergangenen Modellfehler.

Diskussion 4: Wie wird das ARIMA-Modell ausgewählt?

Welche Rolle spielen Maximum Likelihood und AICc? Werden dafür die Testdaten verwendet?

Auch hier werden nur die Trainingsdaten verwendet.

Für eine gegebene ARIMA-Struktur werden die Modellparameter per Maximum Likelihood geschätzt.

Im automatischen Verfahren von ARIMA() wird die notwendige Differenzierungsordnung über Unit-Root-Tests bestimmt. Danach sucht der Algorithmus nach geeigneten AR- und MA-Ordnungen und bevorzugt Modelle mit kleinem AICc.

Damit sind zwei Aufgaben zu unterscheiden:

\[ \boxed{\text{MLE} \rightarrow \text{Koeffizienten eines gegebenen ARIMA-Modells}} \]

\[ \boxed{\text{AICc} \rightarrow \text{Auswahl geeigneter AR-/MA-Ordnungen}} \]

Die Testperiode wird erst später zur unabhängigen Prognoseevaluation verwendet.

Typische Fehlvorstellung: Der AICc ist keine Out-of-sample-Fehlermetrik und wird nicht auf unserem Testjahr berechnet.

Diskussion 5: Was fehlt trotz gutem ARIMA-Fit noch?

Wann wären wir mit einem ARIMA-Modell noch nicht zufrieden?

Ein ARIMA-Modell soll die systematische zeitliche Abhängigkeit so weit erklären, dass in den Residuen keine relevante Autokorrelation mehr übrig bleibt.

Deshalb müssen wir später insbesondere prüfen:

\[ \text{ACF der Residuen} \]

und gegebenenfalls einen Portmanteau-Test wie den Ljung-Box-Test verwenden.

Ausserdem kennt ein reines ARIMA-Modell unsere geplanten Marketing- oder Rabattwerte nicht. Solche externen Prädiktoren würden eine dynamische Regression bzw. Regression mit ARIMA-Fehlern erfordern.

Typische Fehlvorstellung: Ein automatisch ausgewähltes ARIMA-Modell ist nicht automatisch ein gutes Modell. Die Residualdiagnostik bleibt notwendig.

Code
arima_fc <- arima_fit |>
  forecast(h = "1 year")
Code
arima_fc |>
  autoplot(shop_train, level = NULL) +
  labs(
    title = "ARIMA: zeitliche Abhängigkeiten fortschreiben",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 13: ARIMA-Prognose für 2019.

4. Vier Modelle, dieselbe Prognoseaufgabe

Nach der Output-Analyse können wir die vier Modellideen nochmals nebeneinanderstellen.

Code
shop_models <- shop_train |>
  model(
    `Seasonal naïve` = SNAIVE(Orders ~ lag("year")),
    Regression = TSLM(
      log(Orders) ~ trend() + season() + Marketing + Discount
    ),
    ETS = ETS(log(Orders)),
    ARIMA = ARIMA(log(Orders))
  )

shop_fc <- shop_models |>
  forecast(new_data = forecast_plan)
Code
shop_fc |>
  autoplot(shop_train, level = NULL) +
  labs(
    title = "Gleiche Daten – unterschiedliche Modelllogik",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 14: Vier unterschiedliche Prognosemodelle für denselben Zeitraum.

Abschlussdiskussion

Erklären Sie die sichtbaren Unterschiede der Forecasts allein aus der Modelllogik. Noch ohne die Testdaten: Welche Prognose würden Sie aus welchem Grund für besonders plausibel halten?

Die Modelle lösen dieselbe Aufgabe mit unterschiedlichen Informationsquellen:

  • Seasonal naïve: übernimmt die jeweilige Saisonposition des Vorjahres.
  • Regression: kombiniert Trend, Saison und geplante externe Prädiktoren.
  • ETS: schreibt geschätzte Zustände wie Level und Saison fort.
  • ARIMA: schreibt die geschätzte zeitliche Abhängigkeitsstruktur fort.

Noch wissen wir nicht, welches Modell tatsächlich am besten prognostiziert. Die Modelloutputs beschreiben zunächst nur den Fit auf den Trainingsdaten.

Erst im nächsten Teil decken wir die Testdaten auf und beurteilen die Modelle anhand derselben zukünftigen Beobachtungen.

Typische Fehlvorstellung: Die visuell plausibelste oder im Training am besten passende Prognose ist nicht automatisch die beste Out-of-sample-Prognose.

Zwischenfazit: Was müssen wir aus einem Modell-Output mitnehmen?

\[ \boxed{ \begin{array}{lll} \text{Regression} & \rightarrow & \text{Effekte und externe Prädiktoren interpretieren}\\[4pt] \text{ETS} & \rightarrow & \text{Zustände und Glättungsparameter interpretieren}\\[4pt] \text{ARIMA} & \rightarrow & \text{Differenzierung und zeitliche Abhängigkeitsparameter interpretieren} \end{array} } \]

Für alle drei gilt:

\[ \text{Training} \rightarrow \text{Modell schätzen} \]

\[ \text{Test} \rightarrow \text{Prognoseleistung unabhängig beurteilen}. \]

Im nächsten Teil prüfen wir deshalb nicht mehr, wie gut ein Modell die Vergangenheit beschreibt, sondern wie gut es die zurückgehaltene Zukunft prognostiziert und ob seine Residuen noch Struktur enthalten.

Teil 4: Welches Modell überzeugt? Forecast Accuracy und Residualdiagnostik

In Teil 3 haben wir vier Modelle auf denselben Trainingsdaten geschätzt und für dasselbe Jahr 2019 Prognosen erzeugt:

\[ \text{Seasonal naïve} \qquad \text{Regression} \qquad \text{ETS} \qquad \text{ARIMA}. \]

Jetzt dürfen wir die bisher zurückgehaltenen Testdaten aufdecken. Dabei beantworten wir zwei verschiedene Fragen:

\[ \boxed{ \begin{array}{ll} \text{Forecast Accuracy:} & \text{Wie gut prognostiziert das Modell neue Daten?}\\[4pt] \text{Residualdiagnostik:} & \text{Ist in den Modellfehlern noch Struktur übrig?} \end{array} } \]

Beide Perspektiven sind wichtig — aber sie beantworten nicht dieselbe Frage.

Querreferenz: FPP3, Chapter 5, Abschnitte Evaluating point forecast accuracy und Residual diagnostics.

1. Testdaten aufdecken: Wie sehen die Prognosen aus?

Wir legen nun die tatsächlichen Bestellzahlen des Jahres 2019 über die vier Prognosen.

Code
shop_fc |>
  autoplot(shop, level = NULL) +
  labs(
    title = "Prognosen treffen auf die bisher unbekannte Zukunft",
    x = NULL,
    y = "Bestellungen"
  )
Abbildung 15: Prognosen der vier Modelle und tatsächlich beobachtete Bestellungen im Testjahr 2019.

Diskussion

Welches Modell scheint die tatsächlichen Werte des Testjahres am besten zu treffen? Wo erkennen Sie grössere Abweichungen?

Der Plot liefert einen ersten Eindruck, aber noch keine eindeutige Entscheidung. Einzelne grosse Abweichungen können die visuelle Wahrnehmung stark prägen, und verschiedene Modelle können in unterschiedlichen Monaten näher an den Beobachtungen liegen.

Deshalb vergleichen wir die Prognosen als Nächstes mit denselben quantitativen Fehlermassen.

Typische Fehlvorstellung: Die visuell plausibelste Forecast-Linie muss nicht das Modell mit der besten Prognosegüte sein.

2. Alle Modelle mit denselben Fehlermassen vergleichen

Aus Teil 2 kennen wir den Forecast Error

\[ e_{T+h}=y_{T+h}-\hat y_{T+h\mid T}. \]

Wir vergleichen nun für alle vier Modelle MAE und RMSE auf den zwölf Testmonaten.

Code
shop_accuracy <- shop_fc |>
  accuracy(shop) |>
  select(.model, RMSE, MAE) |>
  arrange(RMSE)

shop_accuracy
# A tibble: 4 × 3
  .model          RMSE   MAE
  <chr>          <dbl> <dbl>
1 ETS             147.  126.
2 Seasonal naïve  181.  143.
3 ARIMA           204.  163.
4 Regression      224.  177.

Für die spätere Diskussion bestimmen wir zusätzlich automatisch die jeweils beste Methode.

Diskussion

Welches Modell erzielt den kleinsten RMSE? Welches den kleinsten MAE? Stimmen beide Kriterien überein?

Für diesen Testzeitraum hat ETS den kleinsten RMSE. Den kleinsten MAE erzielt ETS.

MAE und RMSE müssen nicht zwingend dieselbe Rangfolge liefern: Der RMSE reagiert stärker auf einzelne grosse Fehler, während der MAE die absolute Abweichung gleichmässiger gewichtet.

Gegenüber unserem Seasonal-naïve-Benchmark verbessert das nach RMSE beste Modell den RMSE in diesem Testjahr um rund 18.7 %.

Typische Fehlvorstellung: Das Modell mit dem kleinsten Fehler in einem einzigen Testzeitraum ist nicht automatisch für jede zukünftige Situation das beste Modell.

3. Ist ein komplexeres Modell den zusätzlichen Aufwand wert?

Forecast Accuracy ist nicht die einzige praktische Entscheidungskomponente. Ein komplexeres Modell kann beispielsweise zusätzliche Daten oder Planwerte benötigen.

Diskussion

Angenommen, zwei Modelle unterscheiden sich nur wenig in MAE und RMSE. Welche weiteren Kriterien würden Sie für die betriebliche Modellwahl berücksichtigen?

Neben der Prognosegüte sind unter anderem Datenverfügbarkeit, Interpretierbarkeit, Robustheit und Wartungsaufwand relevant.

Ein Regressionsmodell kann beispielsweise geplante Marketingaktionen explizit berücksichtigen, benötigt dafür aber verlässliche zukünftige Werte der Prädiktoren. Ein ETS- oder ARIMA-Modell kommt ohne solche externen Planwerte aus.

Typische Fehlvorstellung: Ein geringfügig kleinerer RMSE rechtfertigt unabhängig von Datenbedarf und Anwendungskontext immer das komplexere Modell.

4. Eine zweite Frage: Was ist in den Residuen übrig geblieben?

Die Testfehler sagen uns, wie gut das Modell die zurückgehaltenen Beobachtungen prognostiziert hat.

Für die Modelldiagnostik betrachten wir dagegen die Residuen innerhalb der Trainingsdaten. Ein Residuum ist

\[ e_t=y_t-\hat y_t. \]

Wurde eine Transformation modelliert, betrachten wir für die Diagnose insbesondere die Innovation Residuals auf der Modellskala.

Ein gutes Forecasting-Modell sollte nach FPP3 insbesondere Residuen erzeugen, die

  1. ungefähr einen Mittelwert von null besitzen und
  2. keine verbleibende Autokorrelation zeigen.

Konstante Varianz und eine annähernd normale Verteilung sind zusätzlich nützlich, insbesondere für die Konstruktion von Prognoseintervallen, aber nicht dieselbe zentrale Forderung wie fehlende Autokorrelation.

Querreferenz: FPP3, Chapter 5, Abschnitt Residual diagnostics.

Warum schauen wir wieder auf die ACF?

In Teil 1 haben wir die ACF verwendet, um zu fragen:

Welche zeitliche Struktur steckt in der ursprünglichen Zeitreihe?

Nach der Modellierung stellen wir dieselbe Frage erneut — jetzt für die Residuen:

Welche zeitliche Struktur hat das Modell noch nicht erklärt?

Idealerweise gilt für Lags \(k>0\) näherungsweise

\[ r_k \approx 0. \]

Dann enthalten die Residuen keine klar erkennbare lineare Information mehr, die aus früheren Residuen gewonnen werden könnte.

5. Residuen des nach RMSE besten Modells untersuchen

Wir wählen nun das Modell mit dem kleinsten Test-RMSE aus und untersuchen seine Residuen auf den Trainingsdaten.

Code
best_model_fit |>
  gg_tsresiduals()
Abbildung 16: Residualdiagnostik des Modells mit dem kleinsten Test-RMSE.

Diskussion

Welche Eigenschaften prüfen Sie in den drei Diagnosegrafiken? Finden Sie Hinweise darauf, dass noch systematische Struktur im Modell fehlt?

Bei der Residualdiagnostik interessieren uns vor allem zwei Fragen:

  • Schwanken die Residuen ungefähr um null?
  • Zeigt ihre ACF noch ein systematisches Muster?

Eine weitgehend strukturlose ACF spricht dafür, dass das Modell die lineare zeitliche Abhängigkeit der Trainingsdaten weitgehend aufgenommen hat. Auffällige einzelne Residuen können dagegen auf ungewöhnliche Monate oder nicht modellierte externe Ereignisse hinweisen.

Typische Fehlvorstellung: Residuen müssen nicht exakt normalverteilt sein, damit ein Modell brauchbare Punktprognosen erzeugen kann. Entscheidend ist hier insbesondere, dass keine systematisch nutzbare zeitliche Abhängigkeit zurückbleibt.

6. Forecast Accuracy und Residualdiagnostik beantworten unterschiedliche Fragen

Damit haben wir zwei Ebenen der Modellbeurteilung:

Perspektive Datenbasis Zentrale Frage
Forecast Accuracy bisher unbekannte Testdaten Wie gut prognostiziert das Modell neue Beobachtungen?
Residualdiagnostik Trainingsdaten Hat das Modell noch systematische Struktur übrig gelassen?

Diskussion

Kann ein Modell gute Testprognosen liefern und trotzdem Autokorrelation in seinen Residuen zeigen? Was würde das bedeuten?

Ja. Ein Modell kann in einem bestimmten Testzeitraum geringe Forecast Errors liefern und trotzdem zeitliche Struktur in seinen Trainingsresiduen zurücklassen.

Das würde bedeuten: Die Prognosen waren für diese Testdaten gut, aber im Modell steckt möglicherweise noch ungenutzte Information, die für eine weitere Verbesserung verwendet werden könnte.

Umgekehrt garantiert eine vollkommen unauffällige Residuen-ACF nicht, dass ein Modell im Testzeitraum den kleinsten MAE oder RMSE besitzt.

Typische Fehlvorstellung: Residualdiagnostik ist kein Ersatz für die Beurteilung auf ungesehenen Daten. Beide Perspektiven ergänzen sich.

7. Abschluss: Vom Rohdatensatz zur Modellentscheidung

Unsere Fallstudie begann mit einer einfachen Geschäftsfrage:

Wie viele Bestellungen erwarten wir in den kommenden Monaten?

Der Weg zur Prognose war jedoch nicht einfach nur „Modell auswählen und forecast() ausführen“:

\[ \boxed{ \begin{array}{c} \text{Zeitreihe verstehen}\\ \downarrow\\ \text{Trend, Saison und Autokorrelation erkennen}\\ \downarrow\\ \text{Benchmark festlegen}\\ \downarrow\\ \text{unterschiedliche Informationsquellen modellieren}\\ \downarrow\\ \text{Forecast Accuracy auf Testdaten vergleichen}\\ \downarrow\\ \text{Residuen auf verbliebene Struktur prüfen} \end{array} } \]

Die drei Modellklassen aus Teil 3 lassen sich dabei über ihre Informationsquelle unterscheiden:

\[ \boxed{ \begin{array}{lll} \text{Regression} & \rightarrow & \text{systematische und externe Information}\\[4pt] \text{ETS} & \rightarrow & \text{Niveau, Trend und Saisonalität}\\[4pt] \text{ARIMA} & \rightarrow & \text{zeitliche Abhängigkeit} \end{array} } \]

Abschlussfrage

Welches Modell würden Sie dem Onlinehändler für die operative Planung empfehlen — und mit welchen zwei Argumenten würden Sie Ihre Entscheidung begründen?

Für den vorliegenden Testzeitraum liefert ETS den kleinsten RMSE. Das ist ein wichtiges Argument für dieses Modell, aber noch keine vollständige betriebliche Entscheidung.

Zusätzlich sollten wir prüfen, ob seine Residuen noch erkennbare zeitliche Struktur enthalten und welche Informationen das Modell für zukünftige Prognosen benötigt. Besonders bei der Regression ist entscheidend, ob zukünftige Marketing- und Rabattwerte zum Forecast Origin tatsächlich verfügbar sind.

Eine begründete Empfehlung verbindet daher Out-of-sample-Prognosegüte, Residualdiagnostik und praktische Einsetzbarkeit.

Typische Fehlvorstellung: Modellwahl bedeutet nicht, einfach die kleinste Zahl in einer Accuracy-Tabelle zu markieren. Prognosegüte ist zentral, muss aber im Anwendungskontext interpretiert werden.

Weiterführend

Ein einzelnes Testjahr ist nur eine mögliche Realisierung der Zukunft. Für eine robustere Beurteilung kann man mehrere historische Forecast Origins verwenden und die Modelle wiederholt auf tatsächlich späteren Beobachtungen prüfen (Time Series Cross-Validation).

Für diese PVA genügt jedoch unser Train/Test-Vergleich, um die zentrale Logik des Forecastings sichtbar zu machen.

Querreferenz: FPP3, Chapter 5, Abschnitt Time series cross-validation.