Wie finde ich eine gute Passform für ein halbsinusförmiges Modell in R?

37

Ich möchte annehmen, dass die Meeresoberflächentemperatur der Ostsee Jahr für Jahr gleich ist, und dies dann mit einem Funktions- / Linearmodell beschreiben. Die Idee, die ich hatte, war, einfach das Jahr als Dezimalzahl (oder num_months / 12) einzugeben und herauszufinden, wie hoch die Temperatur zu dieser Zeit sein sollte. Wenn es in R in die Funktion lm () geworfen wird, erkennt es keine sinusförmigen Daten und erzeugt nur eine gerade Linie. Also habe ich die sin () - Funktion in eine I () - Klammer gesetzt und ein paar Werte ausprobiert, um die Funktion manuell anzupassen, und das kommt meinem Wunsch sehr nahe. Aber das Meer erwärmt sich im Sommer schneller und kühlt sich dann im Herbst langsamer ab ... Das Modell ist also im ersten Jahr falsch, wird dann nach ein paar Jahren korrekter, und in Zukunft wird es wahrscheinlich auch mehr und wieder mehr falsch.

Wie kann ich R veranlassen, das Modell für mich zu schätzen, damit ich selbst keine Zahlen erraten muss? Der Schlüssel hier ist, dass ich möchte, dass es Jahr für Jahr die gleichen Werte liefert und nicht nur für ein Jahr korrekt ist. Wenn ich mehr über Mathematik wüsste, könnte ich es vielleicht als etwas wie Poisson oder Gaußsches statt Sünde () ansehen, aber ich weiß auch nicht, wie ich das machen soll. Jede Hilfe, um einer guten Antwort näher zu kommen, wäre sehr dankbar.

Hier sind die Daten, die ich verwende, und der Code, um die bisherigen Ergebnisse anzuzeigen:

# SST from Bradtke et al 2010
ToY <- c(1/12,2/12,3/12,4/12,5/12,6/12,7/12,8/12,9/12,10/12,11/12,12/12,13/12,14/12,15/12,16/12,17/12,18/12,19/12,20/12,21/12,22/12,23/12,24/12,25/12,26/12,27/12,28/12,29/12,30/12,31/12,32/12,33/12,34/12,35/12,36/12,37/12,38/12,39/12,40/12,41/12,42/12,43/12,44/12,45/12,46/12,47/12,48/12)
Degrees <- c(3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5)
SST <- data.frame(ToY, Degrees)
SSTlm <- lm(SST$Degrees ~ I(sin(pi*2.07*SST$ToY)))
summary(SSTlm)
plot(SST,xlim=c(0,4),ylim=c(0,17))
par(new=T)
plot(data.frame(ToY=SST$ToY,Degrees=8.4418-6.9431*sin(2.07*pi*SST$ToY)),type="l",xlim=c(0,4),ylim=c(0,17))
GaRyu
quelle

Antworten:

44

Es kann mit linearer Regression erfolgen -

Sie brauchen nur einen und einen Cosinus- Term für jede Frequenz.Sündecos

Der Grund, warum Sie in einer linearen Regression einen and cos- Term verwenden können, um die Saisonalität mit jeder Amplitude und Phase zu behandeln, liegt in der folgenden trigonometrischen Identität :Sündecos

Eine 'allgemeine' Sinuswelle mit mit Amplitude und der Phase φ , A sin ( x + φ ) , kann als Linearkombination a sin x + b cos x geschrieben werden, wobei a und b so sind, dass A = EINφEINSünde(x+φ)einSündex+bcosxeinb undsinφ=bEIN=ein2+b2 . Mal sehen, dass die beiden gleichwertig sind:Sündeφ=bein2+b2

einSünde(x)+bcos(x)=ein2+b2(einein2+b2Sünde(x)+bein2+b2cos(x))=EIN[Sünde(x)cos(φ)+cos(x)Sünde(φ)]=EINSünde(x+φ).

Hier ist das "Grundmodell":

 SSTlm <- lm(Degrees ~ sin(2*pi*ToY)+cos(2*pi*ToY),data=SST)
 summary(SSTlm)

[snip]

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)              8.292      0.135   61.41   <2e-16 *** 
sin(2 * pi * ToY)       -5.916      0.191  -30.98   <2e-16 ***  
cos(2 * pi * ToY)       -4.046      0.191  -21.19   <2e-16 *** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1   1 

Residual standard error: 0.9355 on 45 degrees of freedom
Multiple R-squared: 0.969,      Adjusted R-squared: 0.9677 
F-statistic: 704.3 on 2 and 45 DF,  p-value: < 2.2e-16 

 plot(Degrees~ToY,ylim=c(1.5,16.5),data=SST)
 lines(SST$ToY,SSTlm$fitted,col=2)

Sünde fit

Edit: Wichtiger Hinweis - die term funktioniert, weil die Periode der Funktion so eingestellt wurde, dass eine Periode = 1 Einheit von t ist . Wenn sich die Periode von 1 unterscheidet, sagen wir, die Periode ist ω , dann brauchen Sie ( 2 π / ω )2πttω statt.(2π/ω)t

Hier ist das Modell mit der zweiten Harmonischen:

 SSTlm2 <- lm(Degrees ~ sin(2*pi*ToY)+cos(2*pi*ToY)
                        +sin(4*pi*ToY)+cos(4*pi*ToY),data=SST)
 summary(SSTlm2)

[snip]

Coefficients:
                  Estimate Std. Error  t value Pr(>|t|)    
(Intercept)        8.29167    0.02637  314.450  < 2e-16 ***  
sin(2 * pi * ToY) -5.91562    0.03729 -158.634  < 2e-16 ***  
cos(2 * pi * ToY) -4.04632    0.03729 -108.506  < 2e-16 ***  
sin(4 * pi * ToY)  1.21244    0.03729   32.513  < 2e-16 ***  
cos(4 * pi * ToY)  0.33333    0.03729    8.939 2.32e-11 ***  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1   1 

Residual standard error: 0.1827 on 43 degrees of freedom
Multiple R-squared: 0.9989,     Adjusted R-squared: 0.9988 
F-statistic:  9519 on 4 and 43 DF,  p-value: < 2.2e-16 

 plot(Degrees~ToY,ylab="Degrees",xlab="ToY",ylim=c(1.5,16.5),data=SST)
 lines(SSTlm2$fitted~ToY,col=2,data=SST)

sin fit 2

... und so weiter, mit 6*pi*ToYusw. Wenn die Daten ein kleines bisschen Rauschen enthalten, würde ich wahrscheinlich mit diesem zweiten Modell aufhören.

Mit genügend Begriffen können Sie asymmetrische und sogar gezackte periodische Sequenzen genau anpassen, aber die resultierenden Anpassungen können "wackeln". Hier ist eine asymmetrische Funktion (es ist ein Sägezahn - Sägezahn), die zu einer skalierten Version Ihrer periodischen Funktion hinzugefügt wurde, mit einer dritten (roten) und einer vierten (grünen) Harmonischen. Die grüne Anpassung ist im Durchschnitt etwas enger aber "wackelig" (selbst wenn die Anpassung jeden Punkt durchläuft, kann die Anpassung zwischen den Punkten sehr wackelig sein).

sin fit 3 & 4

cosSünde

Wenn Sie Anpassungen wünschen, die glatter sind, als dies bei nicht glatten Serien der Fall ist, sollten Sie sich mit periodischen Spline- Anpassungen befassen .

Ein weiterer Ansatz besteht darin, saisonale Dummies zu verwenden, aber der Sin / Cos-Ansatz ist häufig besser, wenn es sich um eine reibungslose periodische Funktion handelt.

Ein derartiger Ansatz zur Saisonalität kann sich auch an Situationen anpassen, in denen sich die Saisonalität ändert, z.


Der hier beschriebene lineare Modellansatz ist zwar einfach anzuwenden, ein Vorteil des nichtlinearen Regressionsansatzes von @ COOLSerdash besteht jedoch darin, dass er eine viel größere Bandbreite von Situationen abdeckt - Sie müssen nicht viel ändern, bevor Sie sich in einer linearen Situation befinden Eine Regression ist nicht mehr geeignet, aber es können immer noch nichtlineare kleinste Quadrate verwendet werden (ein unbekannter Zeitraum wäre ein solcher Fall).

Glen_b
quelle
Genial! Vielen Dank, ich sollte wirklich versuchen, mehr über Methoden zum Umgang mit Frequenzen zu lernen. Ich verstehe nicht ganz, warum der cos-Teil benötigt wird, aber das Prinzip zu kennen, macht die Implementierung einfach.
GaRyu
@COOLSerdash - eigentlich wünschte ich, Sie hätten Ihre Antwort nicht gelöscht (in der Tat habe ich sie positiv bewertet); es hat den Vorteil, dass es in einer viel größeren Bandbreite von Umständen arbeiten kann; Wenn Sie ein paar Dinge an dem Problem ändern, können Sie die Linearität verlieren - und dann ist mein Ansatz nutzlos, aber Ihr Ansatz funktioniert immer noch. Ich denke, es gibt viel zu sagen, wenn man es so machen kann.
Glen_b
@Glen_b Ah sorry, ich dachte, dass dein Beitrag meinen überflüssig gemacht hat, weil ich nicht die Standardmethode verwendet habe, um mit dem Problem umzugehen. Ich habe es wieder hergestellt.
COOLSerdash
@GaRyu siehe meine Bearbeitung, am oberen Rand meiner Antwort, wo ich einen Überblick gebe, warum ich sie in den hinzufügecos den Trick macht.
Glen_b
1
Das war nicht ich ... Du sagst Phasenversatz, als würde das heißen, was los ist, und das funktioniert mathematisch. Für Sie ist es jedoch wahrscheinlicher, dass der 31. Dezember / 1. Januar ein willkürlicher Ursprung für die Jahreszeit ist, da das Temperaturverhalten aufgrund von Schwankungen des Strahlungsempfangs verzögert ist. Der Phasenversatz ist hier eine Bezeichnung für etwas Klimatologisches, das Timing der minimalen und maximalen Temperatur in Bezug auf Ihr Aufzeichnungssystem. (Es ist ein kleines Detail, aber ich ziehe es vor, die Zeit des Jahres für 12 Monate als 1/24, 3/24, ..., 23/24 zu quantifizieren.)
Nick Cox
10

Die Temperatur, die Sie in Ihrer Frage angeben, wiederholt sich genau jedes Jahr. Ich vermute, das sind keine wirklich gemessenen Temperaturen über vier Jahre. In Ihrem Beispiel benötigen Sie kein Modell, da sich die Temperaturen genau wiederholen. Ansonsten könnten Sie die nlsFunktion verwenden, um eine Sinuskurve anzupassen:

ToY <- c(1/12,2/12,3/12,4/12,5/12,6/12,7/12,8/12,9/12,10/12,11/12,12/12,13/12,14/12,15/12,16/12,17/12,18/12,19/12,20/12,21/12,22/12,23/12,24/12,25/12,26/12,27/12,28/12,29/12,30/12,31/12,32/12,33/12,34/12,35/12,36/12,37/12,38/12,39/12,40/12,41/12,42/12,43/12,44/12,45/12,46/12,47/12,48/12)
Degrees <- c(3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5)
SST <- data.frame(ToY, Degrees)

par(cex=1.5, bg="white")
plot(Degrees~ToY,xlim=c(0,4),ylim=c(0,17), pch=16, las=1)

nls.mod <-nls(Degrees ~ a + b*sin(2*pi*c*ToY), start=list(a = 1, b = 1, c=1))

co <- coef(nls.mod) 
f <- function(x, a, b, c) {a + b*sin(2*pi*c*x) }

curve(f(x, a=co["a"], b=co["b"], c=co["c"]), add=TRUE ,lwd=2, col="steelblue")

NLS fit

Die Passform ist aber vor allem zu Beginn nicht sehr gut. Es scheint, dass Ihre Daten durch eine einfache Sinuskurve nicht angemessen modelliert werden können. Vielleicht reicht eine komplexere trigonometrische Funktion aus?

nls.mod2 <-nls(Degrees ~ a + b*sin(2*pi*c*ToY)+d*cos(2*pi*e*ToY), start=list(a = 1, b = 1, c=1, d=1, e=1))

co2 <- coef(nls.mod2) 
f <- function(x, a, b, c, d, e) {a + b*sin(2*pi*c*x)+d*cos(2*pi*e*x) }

curve(f(x, a=co2["a"], b=co2["b"], c=co2["c"], d=co2["d"], e=co2["e"]), add=TRUE ,lwd=2, col="red")

NLS fit 2

Die rote Kurve passt besser zu den Daten. Mit der nlsFunktion können Sie das Modell eingeben, das Sie für angemessen halten.

Oder vielleicht könnten Sie das forecastPaket nutzen. Im folgenden Beispiel habe ich angenommen, dass die Zeitreihe im Januar 2010 gestartet wurde:

library(forecast)

Degrees.ts <- ts(Degrees, start=c(2010,1), frequency=12)

Degree.trend <- auto.arima(Degrees.ts)

degrees.forecast <- forecast(Degree.trend, h=12, level=c(80,95), fan=F)

plot(degrees.forecast, las=1, main="", xlab="Time", ylab="Degrees")

ARIMA

Da die Daten deterministisch sind, werden keine Vertrauensbereiche angezeigt.

COOLSerdash
quelle
4
Hier gibt es keinen Grund für nichtlineare kleinste Quadrate, nicht, dass es nicht einigermaßen gut funktioniert. Berechnen Sie sin (2 * pi * ToY), cos (2 * pi * ToY) im Voraus und geben Sie sie lm()wie alle anderen Prädiktoren weiter. Mit anderen Worten, lm()muss überhaupt keine Trigonometrie sehen. Möglicherweise benötigen Sie jedoch ein anderes Modell, um die ausgeprägte Asymmetrie gut zu erfassen. Ich bin kein regulärer R-Benutzer, habe diesen Ansatz jedoch an anderer Stelle häufig verwendet (siehe stata-journal.com/sjpdf.html?articlenum=st0116 ).
Nick Cox
@ NickCox Danke Nick, das ist ein sehr hilfreicher Rat. Ich werde meine Antwort in Kürze aktualisieren.
COOLSerdash
Glen war schneller :)
COOLSerdash
1
@COOLserdash Ich habe dort nicht einmal den Kommentar von Nick Cox gesehen. es kam, während ich meine Antwort erzeugte. (Dieser Ansatz ist ziemlich offensichtlich, wenn Sie eine Fourier-Serie gesehen haben.)
Glen_b
2
Wie @ Glen_b impliziert, ist dies ein Standardansatz, der nicht allgemein bekannt ist.
Nick Cox