Zeitreihenanalyseverfahren und -methoden unter Verwendung von R


13

Ich arbeite an einem kleinen Projekt, bei dem wir versuchen, die Rohstoffpreise (Öl, Aluminium, Zinn usw.) für die nächsten 6 Monate vorherzusagen. Ich muss 12 solche Variablen vorhersagen und habe Daten von April 2008 bis Mai 2013.

Wie gehe ich bei der Vorhersage vor? Ich habe folgendes gemacht:

  • Importierte Daten als Timeseries-Dataset
  • Die Saisonalität aller Variablen variiert tendenziell mit dem Trend, daher gehe ich zum multiplikativen Modell.
  • Ich habe die Variable protokolliert, um sie in ein additives Modell umzuwandeln
  • Für jede Variable werden die Daten mit AWL zerlegt

Ich plane, die exponentielle Glättung von Holt Winters, ARIMA und das neuronale Netz für die Vorhersage zu verwenden. Ich habe die Daten als Training und Test aufgeteilt (80, 20). Planen, das Modell mit weniger MAE, MPE, MAPE und MASE auszuwählen.

Mache ich das richtig?

Ich hatte auch eine Frage: Soll ich die Daten glätten, bevor ich sie an ARIMA oder ein neuronales Netz weitergebe? Wenn ja, mit was? Die Daten zeigen sowohl Saisonalität als auch Trend.

BEARBEITEN:

Anhängen des Zeitreihenplots und der Daten Bildbeschreibung hier eingeben

Year  <- c(2008, 2008, 2008, 2008, 2008, 2008, 2008, 2008, 2008, 2009, 2009, 
           2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2010, 
           2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 
           2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 
           2011, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 
           2012, 2012, 2013, 2013)
Month <- c(4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
           12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 
           8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2) 
Coil  <- c(44000, 44500, 42000, 45000, 42500, 41000, 39000, 35000, 34000, 
           29700, 29700, 29000, 30000, 30000, 31000, 31000, 33500, 33500, 
           33000, 31500, 34000, 35000, 35000, 36000, 38500, 38500, 35500, 
           33500, 34500, 36000, 35500, 34500, 35500, 38500, 44500, 40700, 
           40500, 39100, 39100, 39100, 38600, 39500, 39500, 38500, 39500, 
           40000, 40000, 40500, 41000, 41000, 41000, 40500, 40000, 39300, 
           39300, 39300, 39300, 39300, 39800)
coil <- data.frame(Year = Year, Month = Month, Coil = Coil)

EDIT 2: Eine Frage, können Sie mir bitte sagen, ob meine Daten Saisonalität oder Trend haben? Und bitte geben Sie mir auch einige Tipps, wie Sie sie identifizieren können. Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben


2
Wenn Sie versuchen, Warengruppen wie verschiedene Metallsorten (Stahl A, Stahl B, Stahl C usw.) vorherzusagen, ist es möglicherweise sinnvoll, das Vorhandensein einer Kointegration zu prüfen. Beispiel: Bewegen sich die Stahlpreise zusammen? . Dies liefert möglicherweise bessere Prognosen für 6 Monate (mittel- / langfristig) als univariate Methoden, aber dies ist in der Tat ein schwieriges Spiel, das Sie versuchen zu spielen. ;-)
Graeme Walsh

1
AS @GraemeWalsh weist darauf hin, dass eine univariate Trendextrapolation für diese Art von Daten möglicherweise nicht ideal ist. In der Literatur gibt es gut etablierte Methoden zur Vorhersage der Öl- und Stahlpreise, die es wert sein könnten, untersucht zu werden.
Prognose

1
Können Sie neue Bearbeitungen als separate Frage posten? Da Sie bereits eine Antwort akzeptiert haben, erhalten die neuen Fragen möglicherweise nicht die erforderliche Aufmerksamkeit. Wenn ich die Daten betrachte, kann ich sagen, dass keine Trends oder saisonale Muster aufweist. Wie in meinem Post unten erwähnt, scheint der Abwärtstrend vor 2009 ein makroökonomisches Phänomen wie eine Rezession zu sein?
Prognose

@ Prognostiker, @ GraemeWalsh: Danke. Ich plane, eine Kointegrationsmethode mit ADF-Tests zu verwenden.
Niranjan Sonachalam

1
Sie haben in Ihrer neuen Frage den Kontext angegeben, und es ist jetzt absolut sinnvoll. Der Rückgang vor 2009 war in der Tat ein makroökonomisches Phänomen. In diesem Fall verwenden Sie bitte die Zufallsmethode mit Drift oder (arima (0,1,0) + drift
forecaster

Antworten:


21

Sie sollten das Vorhersagepaket verwenden , das alle diese Modelle (und mehr) unterstützt und deren Anpassung zum Kinderspiel macht:

library(forecast)
x <- AirPassengers
mod_arima <- auto.arima(x, ic='aicc', stepwise=FALSE)
mod_exponential <- ets(x, ic='aicc', restrict=FALSE)
mod_neural <- nnetar(x, p=12, size=25)
mod_tbats <- tbats(x, ic='aicc', seasonal.periods=12)
par(mfrow=c(4, 1))
plot(forecast(mod_arima, 12), include=36)
plot(forecast(mod_exponential, 12), include=36)
plot(forecast(mod_neural, 12), include=36)
plot(forecast(mod_tbats, 12), include=36)

Ich würde davon abraten, die Daten vor dem Anpassen Ihres Modells zu glätten. Ihr Modell wird von Natur aus versuchen, die Daten zu glätten, sodass das Vorglätten die Sache nur kompliziert macht.

Bildbeschreibung hier eingeben

Bearbeiten basierend auf neuen Daten:

Es sieht tatsächlich so aus, als ob Arima eines der schlechtesten Modelle ist, die Sie für dieses Trainings- und Test-Set ausgewählt haben.

Ich habe Ihre Daten in einem Dateiaufruf gespeichert coil.csv, in R geladen und in ein Trainings- und Test-Set aufgeteilt:

library(forecast)
dat <- read.csv('~/coil.csv')
x <- ts(dat$Coil, start=c(dat$Year[1], dat$Month[1]), frequency=12)
test_x <- window(x, start=c(2012, 3))
x <- window(x, end=c(2012, 2))

Als nächstes passe ich eine Reihe von Zeitreihenmodellen an: Arima, exponentielle Glättung, neuronales Netzwerk, TBats, Fledermäuse, saisonale Zerlegung und strukturelle Zeitreihen:

models <- list(
  mod_arima = auto.arima(x, ic='aicc', stepwise=FALSE),
  mod_exp = ets(x, ic='aicc', restrict=FALSE),
  mod_neural = nnetar(x, p=12, size=25),
  mod_tbats = tbats(x, ic='aicc', seasonal.periods=12),
  mod_bats = bats(x, ic='aicc', seasonal.periods=12),
  mod_stl = stlm(x, s.window=12, ic='aicc', robust=TRUE, method='ets'),
  mod_sts = StructTS(x)
  )

Dann habe ich einige Vorhersagen gemacht und mit dem Testset verglichen. Ich habe eine naive Vorhersage eingefügt, die immer eine flache, horizontale Linie vorhersagt:

forecasts <- lapply(models, forecast, 12)
forecasts$naive <- naive(x, 12)
par(mfrow=c(4, 2))
for(f in forecasts){
  plot(f)
  lines(test_x, col='red')
}

Bildbeschreibung hier eingeben

Wie Sie sehen, ist das Arima-Modell im Trend verkehrt, aber ich mag das Aussehen des "Basic Structural Model".

Schließlich habe ich die Genauigkeit jedes Modells am Testgerät gemessen:

acc <- lapply(forecasts, function(f){
  accuracy(f, test_x)[2,,drop=FALSE]
})
acc <- Reduce(rbind, acc)
row.names(acc) <- names(forecasts)
acc <- acc[order(acc[,'MASE']),]
round(acc, 2)
                ME    RMSE     MAE   MPE MAPE MASE ACF1 Theil's U
mod_sts     283.15  609.04  514.46  0.69 1.27 0.10 0.77      1.65
mod_bats     65.36  706.93  638.31  0.13 1.59 0.12 0.85      1.96
mod_tbats    65.22  706.92  638.32  0.13 1.59 0.12 0.85      1.96
mod_exp      25.00  706.52  641.67  0.03 1.60 0.12 0.85      1.96
naive        25.00  706.52  641.67  0.03 1.60 0.12 0.85      1.96
mod_neural   81.14  853.86  754.61  0.18 1.89 0.14 0.14      2.39
mod_arima   766.51  904.06  766.51  1.90 1.90 0.14 0.73      2.48
mod_stl    -208.74 1166.84 1005.81 -0.52 2.50 0.19 0.32      3.02

Die verwendeten Metriken sind in Hyndman, RJ und Athanasopoulos, G. (2014) "Forecasting: Principles and Practice" beschrieben , die zufällig auch die Autoren des Forecast-Pakets sind. Ich empfehle Ihnen nachdrücklich, ihren Text zu lesen: Er ist kostenlos online verfügbar. Die strukturelle Zeitreihe ist das beste Modell nach mehreren Metriken, einschließlich MASE, der Metrik, die ich für die Modellauswahl am meisten bevorzuge.

Eine letzte Frage ist: Hat das Strukturmodell bei diesem Testsatz Glück gehabt? Eine Möglichkeit, dies zu beurteilen, ist die Betrachtung von Trainingssatzfehlern. Trainingssatzfehler sind weniger zuverlässig als Testsatzfehler (da sie überanpassbar sein können), aber in diesem Fall hat das Strukturmodell immer noch die Nase vorn:

acc <- lapply(forecasts, function(f){
  accuracy(f, test_x)[1,,drop=FALSE]
})
acc <- Reduce(rbind, acc)
row.names(acc) <- names(forecasts)
acc <- acc[order(acc[,'MASE']),]
round(acc, 2)
                ME    RMSE     MAE   MPE MAPE MASE  ACF1 Theil's U
mod_sts      -0.03    0.99    0.71  0.00 0.00 0.00  0.08        NA
mod_neural    3.00 1145.91  839.15 -0.09 2.25 0.16  0.00        NA
mod_exp     -82.74 1915.75 1359.87 -0.33 3.68 0.25  0.06        NA
naive       -86.96 1936.38 1386.96 -0.34 3.75 0.26  0.06        NA
mod_arima  -180.32 1889.56 1393.94 -0.74 3.79 0.26  0.09        NA
mod_stl     -38.12 2158.25 1471.63 -0.22 4.00 0.28 -0.09        NA
mod_bats     57.07 2184.16 1525.28  0.00 4.07 0.29 -0.03        NA
mod_tbats    62.30 2203.54 1531.48  0.01 4.08 0.29 -0.03        NA

(Beachten Sie, dass das neuronale Netzwerk übermäßig gut funktioniert, wenn das Trainingsset und das Testset schlecht sind.)

Schließlich wäre es eine gute Idee, alle diese Modelle gegenseitig zu validieren, beispielsweise durch Schulung von 2008 bis 2009 / Testen von 2010, Training von 2008 bis 2010 / Testen von 2011, Training von 2008 bis 2011 / Testen von 2012, Training am 2008-2012 / Testen am 2013 und Mitteln von Fehlern über alle diese Zeiträume. Wenn Sie diesen Weg beschreiten möchten, habe ich ein teilweise vollständiges Paket für die Validierung von Zeitreihenmodellen auf github , das Sie gerne ausprobieren und mir Feedback / Pull-Anfragen zu folgenden Themen geben können:

devtools::install_github('zachmayer/cv.ts')
library(cv.ts)

Edit 2: Mal sehen, ob ich mich erinnere, wie ich mein eigenes Paket benutze!

Installieren und laden Sie zunächst das Paket von github (siehe oben). Überprüfen Sie dann einige Modelle (unter Verwendung des vollständigen Datensatzes):

library(cv.ts)
x <- ts(dat$Coil, start=c(dat$Year[1], dat$Month[1]), frequency=12)
ctrl <- tseriesControl(stepSize=1, maxHorizon=12, minObs=36, fixedWindow=TRUE)
models <- list()

models$arima = cv.ts(
  x, auto.arimaForecast, tsControl=ctrl,
  ic='aicc', stepwise=FALSE)

models$exp = cv.ts(
  x, etsForecast, tsControl=ctrl,
  ic='aicc', restrict=FALSE)

models$neural = cv.ts(
  x, nnetarForecast, tsControl=ctrl,
  nn_p=6, size=5)

models$tbats = cv.ts(
  x, tbatsForecast, tsControl=ctrl,
  seasonal.periods=12)

models$bats = cv.ts(
  x, batsForecast, tsControl=ctrl,
  seasonal.periods=12)

models$stl = cv.ts(
  x, stl.Forecast, tsControl=ctrl,
  s.window=12, ic='aicc', robust=TRUE, method='ets')

models$sts = cv.ts(x, stsForecast, tsControl=ctrl)

models$naive = cv.ts(x, naiveForecast, tsControl=ctrl)

models$theta = cv.ts(x, thetaForecast, tsControl=ctrl)

(Beachten Sie, dass ich die Flexibilität des neuronalen Netzwerkmodells reduziert habe, um eine Überanpassung zu verhindern.)

Sobald wir die Modelle angepasst haben, können wir sie mit MAPE vergleichen (cv.ts unterstützt MASE noch nicht):

res_overall <- lapply(models, function(x) x$results[13,-1])
res_overall <- Reduce(rbind, res_overall)
row.names(res_overall) <- names(models)
res_overall <- res_overall[order(res_overall[,'MAPE']),]
round(res_overall, 2)
                 ME    RMSE     MAE   MPE MAPE
naive     91.40 1126.83  961.18  0.19 2.40
ets       91.56 1127.09  961.35  0.19 2.40
stl     -114.59 1661.73 1332.73 -0.29 3.36
neural     5.26 1979.83 1521.83  0.00 3.83
bats     294.01 2087.99 1725.14  0.70 4.32
sts     -698.90 3680.71 1901.78 -1.81 4.77
arima  -1687.27 2750.49 2199.53 -4.23 5.53
tbats   -476.67 2761.44 2428.34 -1.23 6.10

Autsch. Es scheint, dass unsere strukturelle Prognose Glück hatte. Langfristig liefert die naive Prognose die besten Prognosen, gemittelt über einen Zeitraum von 12 Monaten (das Arima-Modell ist immer noch eines der schlechtesten Modelle). Vergleichen wir die Modelle an jedem der 12 Prognosehorizonte und sehen wir, ob eines davon jemals das naive Modell übertrifft:

library(reshape2)
library(ggplot2)
res <- lapply(models, function(x) x$results$MAPE[1:12])
res <- data.frame(do.call(cbind, res))
res$horizon <- 1:nrow(res)
res <- melt(res, id.var='horizon', variable.name='model', value.name='MAPE')
res$model <- factor(res$model, levels=row.names(res_overall))
ggplot(res, aes(x=horizon, y=MAPE, col=model)) +
  geom_line(size=2) + theme_bw() +
  theme(legend.position="top") +
  scale_color_manual(values=c(
    "#1f78b4", "#ff7f00", "#33a02c", "#6a3d9a",
    "#e31a1c", "#b15928", "#a6cee3", "#fdbf6f",
    "#b2df8a")
    )

Modell vergleichen

Bezeichnenderweise wählt das exponentielle Glättungsmodell immer das naive Modell (die orange Linie und die blaue Linie überlappen sich zu 100%). Mit anderen Worten, die naive Prognose der Coil-Preise für den nächsten Monat entspricht den Coil-Preisen für diesen Monat und ist genauer (an fast jedem Prognosehorizont) als 7 äußerst ausgefeilte Zeitreihenmodelle. Wenn Sie keine geheimen Informationen haben, die der Spulenmarkt noch nicht kennt, wird es äußerst schwierig sein , die naive Spulenpreisprognose zu übertreffen .

Es ist nie die Antwort, die irgendjemand hören möchte, aber wenn die Genauigkeit der Vorhersage Ihr Ziel ist, sollten Sie das genaueste Modell verwenden. Verwenden Sie das naive Modell.


Es ist interessant, die Unterschiede zwischen diesen Modellen zu betrachten. Insbesondere NNAR sieht anders aus. Wenn man davon ausgeht, dass dies ein berühmter Datensatz ist (und historisch gesehen, glaube ich), ist dann bekannt, welcher richtig ist und ob ein Modelltyp eine Outperformance aufweist? (Nb, ich weiß relativ wenig über TS.)
gung - Reinstate Monica

@gung Der beste Weg, dies zu tun, wäre, ein Holdout-Set abzuspalten und das Modell zu testen. Beachten Sie, dass das Modell, das die besten kurzfristigen Vorhersagen macht, möglicherweise nicht das Modell ist, das die besten langfristigen Vorhersagen macht ....
Zach

Vielen Dank, aber ich erhalte keine guten Vorhersagen für den obigen Datensatz (ich glaube, ich vermisse hier einen wichtigen Schritt). Können Sie mich bitte informieren, wenn mir etwas fehlt
Niranjan Sonachalam

@Niranjan Kannst du uns sagen / zeigen, wie du zu dem Schluss kommst, dass du keine guten Prognosen bekommst?
Prognose

@forecaster: Bitte überprüfen Sie hier pbrd.co/1DRPRsq . Ich bin neu in der Vorhersage. Lassen Sie mich wissen, wenn Sie spezielle Informationen benötigen. Ich habe es mit Arima Modell versucht.
Niranjan Sonachalam

12

Der Ansatz, den Sie gewählt haben, ist vernünftig. Wenn Sie mit Prognosen noch nicht vertraut sind, empfehle ich folgende Bücher:

  1. Prognosemethoden und -anwendungen von Makridakis, Wheelright und Hyndman
  2. Prognose: Prinzipien und Praxis von Hyndman und Athanasopoulos.

Das erste Buch ist ein Klassiker, den ich sehr empfehlen kann. Das zweite Buch ist ein Open-Source-Buch, auf das Sie für Prognosemethoden und deren Anwendung unter Verwendung der ROpen-Source-Softwarepaket- Prognose verweisen können . Beide Bücher bieten einen guten Hintergrund zu den Methoden, die ich verwendet habe. Wenn Sie es ernst meinen mit Prognosen, dann würde ich Principles of Forecasting von Armstrong empfehlen , eine Sammlung von enormen Forschungsergebnissen in Bezug auf Prognosen, die ein Praktiker für sehr hilfreich halten könnte.

Wenn ich zu Ihrem konkreten Beispiel für die Spule komme, erinnere ich mich an ein Konzept der Vorhersagbarkeit, das in den meisten Lehrbüchern häufig ignoriert wird. Einige Serien wie Ihre Serien können einfach nicht vorhergesagt werden, da sie weniger Muster aufweisen, da sie keine Trend- oder saisonalen Muster oder systematische Variationen aufweisen. In diesem Fall würde ich eine Serie als weniger vorhersehbar einstufen. Bevor Sie sich in Extrapolationsmethoden, ich auf den Daten aussehen würde und die Frage stellen, ist meine Serie vorhersagbaren? In diesem speziellen Beispiel eine einfache Extrapolation wie Irrfahrt Prognose , die den letzten Wert der Prognose verwendet wird gefunden, genaueste sein .

Ein weiterer Kommentar zum neuronalen Netz: Neuronale Netze scheitern bekanntermaßen an empirischen Wettbewerben . Ich würde traditionelle statistische Methoden für Zeitreihen ausprobieren, bevor ich versuche, neuronale Netze für Zeitreihen-Prognoseaufgaben zu verwenden.

Ich habe versucht, Ihre Daten zu modellieren R's forecast package, hoffentlich sind die Kommentare selbsterklärend.

coil <- c(44000, 44500, 42000, 45000, 42500, 41000, 39000, 35000, 34000, 
          29700, 29700, 29000, 30000, 30000, 31000, 31000, 33500, 33500, 
          33000, 31500, 34000, 35000, 35000, 36000, 38500, 38500, 35500, 
          33500, 34500, 36000, 35500, 34500, 35500, 38500, 44500, 40700, 
          40500, 39100, 39100, 39100, 38600, 39500, 39500, 38500, 39500, 
          40000, 40000, 40500, 41000, 41000, 41000, 40500, 40000, 39300, 
          39300, 39300, 39300, 39300, 39800)


coilts <- ts(coil,start=c(2008,4),frequency=12)

library("forecast")

# Data for modeling
coilts.mod <- window(coilts,end = c(2012,3))

#Data for testing
coil.test <- window(coilts,start=c(2012,4))

# Model using multiple methods - arima, expo smooth, theta, random walk, structural time series

#arima
coil.arima <- forecast(auto.arima(coilts.mod),h=11)

#exponential smoothing
coil.ets <- forecast(ets(coilts.mod),h=11)

#theta
coil.tht <- thetaf(coilts.mod, h=11)

#random walk
coil.rwf <- rwf(coilts.mod, h=11)

#structts
coil.struc <- forecast(StructTS(coilts.mod),h=11)


##accuracy 

arm.acc <- accuracy(coil.arima,coil.test)
ets.acc <- accuracy(coil.ets,coil.test)
tht.acc <- accuracy(coil.tht,coil.test)
rwf.acc <- accuracy(coil.rwf,coil.test)
str.acc <- accuracy(coil.struc,coil.test)

Unter Verwendung von MAE für die Hold-out-Daten würde ich ARIMA für die kurzfristige Vorhersage (1 - 12 Monate) auswählen. Langfristig würde ich mich auf eine zufällige Wandervorhersage verlassen. Bitte beachten Sie, dass ARIMA ein Zufallsmodell mit Drift (0,1,0) + Drift ausgewählt hat, das bei dieser Art von Problemen in der Regel sehr viel genauer ist als ein reines Zufallsmodell. Siehe nachstehende Tabelle. Dies basiert auf der Genauigkeitsfunktion wie im obigen Code gezeigt.

Bildbeschreibung hier eingeben

Spezifische Antworten auf Ihre spezifischen Fragen: Auch eine Frage, die ich hatte, war, bevor ich zu ARIMA oder zum neuronalen Netz überging, sollte ich die Daten glätten? Wenn ja, mit was?

  • Nein, Prognosemethoden glätten Ihre Daten auf natürliche Weise, um sie an das Modell anzupassen.

Die Daten zeigen sowohl Saisonalität als auch Trend.

  • Die obigen Daten zeigen keinen Trend oder Saisonalität. Wenn Sie feststellen, dass die Daten Saisonalität und Trend aufweisen, wählen Sie eine geeignete Methode.

Praktische Tipps zur Verbesserung der Genauigkeit:

Kombinieren Sie verschiedene Prognosemethoden: - Sie können versuchen, nicht extrapolierte Methoden wie analoge Prognosen , Urteilsprognosen oder andere Techniken zu verwenden und diese mit statistischen Methoden zu kombinieren, um genaue Prognosen zu erhalten. In diesem Artikel finden Sie Informationen zu den Vorteilen des Kombinierens. Ich habe versucht, die obigen 5 Methoden zu kombinieren, aber die Vorhersage war als einzelne Methoden nicht genau. Ein möglicher Grund ist, dass die einzelnen Vorhersagen ähnlich sind. Sie profitieren von der Kombination von Prognosen, wenn Sie verschiedene Methoden wie statistische und wertende Prognosen kombinieren.

Erkennen und Verstehen von Ausreißern: - Daten aus der realen Welt sind mit Ausreißern gefüllt. Identifizieren und behandeln Sie Ausreißer in Zeitreihen. Empfehlen Sie diesen Beitrag zu lesen . Wenn Sie sich Ihre Spulendaten ansehen, ist der Rückgang vor 2009 ein Ausreißer?

Bearbeiten

Die Daten scheinen einigen makroökonomischen Trends zu folgen. Ich vermute, dass der Abwärtstrend, der vor 2009 zu verzeichnen war, auf einen Konjunktureinbruch zwischen 2008 und 2009 folgt und nach 2009 wieder anzieht. Wenn dies der Fall ist, würde ich alle zusammen Extrapolationsmethoden vermeiden und mich stattdessen auf eine solide Theorie stützen diese wirtschaftlichen Trends verhalten sich wie die referenzierte von @GraemeWalsh.

Hoffe das hilft

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.