Come trovare una buona misura per il modello semi-sinusoidale in R?


37

Voglio presumere che la temperatura della superficie del mare del Mar Baltico sia la stessa anno dopo anno, e quindi descriverlo con un modello funzione / lineare. L'idea che ho avuto è stata quella di inserire solo l'anno come un numero decimale (o num_months / 12) e capire quale dovrebbe essere la temperatura in quel momento. Lanciandolo nella funzione lm () in R, non riconosce i dati sinusoidali, quindi produce solo una linea retta. Quindi ho inserito la funzione sin () all'interno di una parentesi I () e ho provato alcuni valori per adattare manualmente la funzione, e questo si avvicina a quello che voglio. Ma il mare si sta riscaldando più velocemente in estate e poi si raffredda più lentamente in autunno ... Quindi il modello si sbaglia nel primo anno, quindi diventa più corretto dopo un paio d'anni, e poi in futuro credo che diventi più e ancora di più sbagliato.

Come posso ottenere R per stimare il modello per me, quindi non devo indovinare i numeri da solo? La chiave qui è che voglio che produca gli stessi valori anno dopo anno, non solo per un anno. Se avessi saputo di più sulla matematica, forse avrei potuto indovinarlo come qualcosa di simile a un Poisson o gaussiano invece di sin (), ma non so nemmeno come farlo. Qualsiasi aiuto per avvicinarsi a una buona risposta sarebbe molto apprezzato.

Ecco i dati che utilizzo e il codice per mostrare i risultati finora:

# 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))

Risposte:


44

Può essere fatto con regressione lineare -

Hai solo bisogno di un termine e un ad ogni frequenza.cossincos

Il motivo per cui è possibile utilizzare un termine e in una regressione lineare per gestire la stagionalità con qualsiasi ampiezza e fase è a causa della seguente identità trigonometrica :cossincos

Un 'generale' onda sinusoidale di ampiezza e la fase , , può essere scritto come combinazione lineare dove e sono tali che e . Vediamo che i due sono equivalenti:φ A sin ( x + φ ) a sin x + b cos x a b A = AφUNpeccato(X+φ)un'peccatoX+BcosXun'B sinφ=bUN=un'2+B2peccatoφ=Bun'2+B2

asin(x)+bcos(x)=a2+b2(aa2+b2sin(x)+ba2+b2cos(x))=A[sin(x)cos(φ)+cos(x)sin(φ)]=Asin(x+φ).

Ecco il modello "base":

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

[Omissis]

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)

peccato in forma

Modifica: Nota importante: il termine funziona perché il periodo della funzione è stato impostato in modo che un periodo = 1 unità di . Se il periodo è diverso da 1, supponiamo che il periodo sia , quindi è necessario .2πttω(2π/ω)t

Ecco il modello con la seconda armonica:

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

[Omissis]

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

... e così via, con 6*pi*ToYecc. Se ci fosse un po 'di rumore nei dati, probabilmente mi fermerei con questo secondo modello.

Con abbastanza termini puoi adattarti esattamente a sequenze periodiche asimmetriche e persino frastagliate, ma gli adattamenti risultanti possono "oscillare". Ecco una funzione asimmetrica (è un dente di sega - dente di sega) aggiunta a una versione ridimensionata della tua funzione periodica), con la terza (rossa) e la quarta (verde) armonica. La misura verde è in media un po 'più vicina ma "sinuosa" (anche quando la misura passa attraverso ogni punto, la misura può essere molto mossa tra i punti).

peccato in forma 3 e 4

La periodicità qui significa che ci sono solo 12 df disponibili per un modello stagionale nei dati. Con l'intercettazione nel modello, hai solo sufficienti gradi di libertà per 11 parametri stagionali aggiuntivi. Poiché stai aggiungendo due termini con ciascuna armonica, l'ultima armonica che puoi inserire ti consentirà solo una di esse per l'ultimo termine, la sesta armonica (e quella deve essere un ; il termine sarà tutto- zero, mentre il cos si alterna tra 1 e -1).cospeccato

Se si desidera adattamenti più fluidi di quanto questo approccio produca su serie non uniformi, è possibile esaminare adattamenti periodici della spline .

Ancora un altro approccio è quello di usare i manichini stagionali, ma l'approccio sin / cos è spesso migliore se si tratta di una regolare funzione periodica.

Questo tipo di approccio alla stagionalità può anche adattarsi a situazioni in cui la stagionalità sta cambiando, come l'uso della stagionalità trigonometrica o fittizia con i modelli dello spazio degli stati.


Mentre l'approccio del modello lineare discusso qui è semplice da usare, un vantaggio dell'approccio di regressione non lineare di @ COOLSerdash è che può gestire una gamma molto più ampia di situazioni - non devi cambiare molto prima di trovarti in una situazione in cui lineare la regressione non è più adatta, ma possono comunque essere utilizzati minimi quadrati non lineari (un periodo sconosciuto sarebbe uno di questi casi).


Eccezionale! Grazie, dovrei davvero cercare di saperne di più sui metodi per gestire le frequenze. Non capisco bene perché sia ​​necessaria la parte cos, ma conoscere il principio ne semplifica l'implementazione.
GaRyu,

@COOLSerdash - in realtà, vorrei che tu non avessi cancellato la tua risposta (anzi l'ho votata); ha il vantaggio di lavorare in una gamma molto più ampia di circostanze; modifica alcune cose sul problema e puoi perdere la linearità - e quindi il mio approccio è inutile, ma il tuo funziona ancora. Penso che ci sia molto da dire per poterlo fare in quel modo.
Glen_b

@Glen_b Ah scusa, ho pensato che il tuo post avesse reso il mio ridondante perché non ho usato il modo standard di affrontare il problema. L'ho cancellato.
COOLSerdash

cos

1
Non sono stato io ... Dici sfasamento come se quello che dava quel che stava succedendo, e lo fa matematicamente. Ma per te il punto chiave è più probabile che il 31 dicembre / 1 gennaio sia un'origine arbitraria per il periodo dell'anno dato ritardi nella risposta della temperatura alle variazioni nella ricezione delle radiazioni. Quindi l'offset di fase è un nome anche qui per qualcosa di climatologico, i tempi di temperatura minima e massima relativi al sistema di registrazione. (È un dettaglio minore ma preferisco quantificare il periodo dell'anno per 12 mesi come 1/24, 3/24, ..., 23/24.)
Nick Cox,

10

La temperatura che fornisci nella tua domanda si ripete esattamente ogni anno. Ho il sospetto che non siano misurate le temperature per quattro anni. Nel tuo esempio, non avresti bisogno di un modello, perché le temperature si ripetono esattamente. Ma altrimenti potresti usare la nlsfunzione per adattarsi a una curva sinusoidale:

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")

Vestibilità NLS

Ma la vestibilità non è molto buona, specialmente all'inizio. Sembra che i tuoi dati non possano essere adeguatamente modellati da una semplice curva sinusoidale. Forse una funzione trigonometrica più complessa farà il trucco?

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

La curva rossa si adatta meglio ai dati. Con la nlsfunzione, puoi inserire il modello che ritieni appropriato.

O forse potresti usare il forecastpacchetto. Nell'esempio seguente, ho ipotizzato che le serie temporali siano iniziate nel gennaio 2010:

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

Poiché i dati sono deterministici, non vengono mostrate bande di confidenza.


4
Non c'è motivo per i minimi quadrati non lineari qui, non che non funzionerà abbastanza bene. Calcola in anticipo sin (2 * pi * ToY), cos (2 * pi * ToY) e nutrili lm()come qualsiasi altro predittore. In altre parole, lm()non è necessario vedere alcuna trigonometria. Tuttavia, potrebbe essere necessario un altro modello per catturare bene l'asimmetria contrassegnata. Non sono un normale utente R ma ho spesso usato questo approccio altrove (vedi stata-journal.com/sjpdf.html?articlenum=st0116 ).
Nick Cox,

@NickCox Grazie Nick, questo è un consiglio molto utile. Aggiornerò la mia risposta tra poco.
COOLSerdash

Glen è stato più veloce :)
COOLSerdash

1
@COOLserdash Non ho nemmeno visto il commento di Nick Cox lì; è successo mentre stavo generando la mia risposta. (Questo approccio è abbastanza ovvio se hai visto qualche serie di Fourier.)
Glen_b -Reinstate Monica,

2
Come suggerisce @Glen_b, questo è un approccio standard, non universalmente noto.
Nick Cox,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.