2013-11-20 11 views
7

Sono un principiante nell'adattamento di curve e diversi messaggi su Stackoverflow mi hanno davvero aiutato.La curva sinusoidale si adatta a lm e nls in R

Ho provato ad adattare una curva sinusoidale ai miei dati utilizzando lm e nls ma entrambi i metodi mostrano uno strano adattamento come mostrato di seguito. Qualcuno potrebbe indicare dove ho sbagliato. Sospetto che qualcosa abbia a che fare con il tempo ma non riesco a farlo bene. I miei dati sono accessibili da here. plot

data <- read.table(file="900days.txt", header=TRUE, sep="") 
time<-data$time 
temperature<-data$temperature 

#lm fitting 
xc<-cos(2*pi*time/366) 
xs<-sin(2*pi*time/366) 
fit.lm<-lm(temperature~xc+xs) 
summary(fit.lm) 
plot(temp~time, data=data, xlim=c(1, 900)) 
par(new=TRUE) 
plot(fit.lm$fitted, type="l", col="red", xlim=c(1, 900), pch=19, ann=FALSE, xaxt="n", 
yaxt="n") 

#nls fitting 
fit.nls<-nls(temp~C+alpha*sin(W*time+phi), 
    start=list(C=27.63415, alpha=27.886, W=0.0652, phi=14.9286)) 
summary(fit.nls) 
plot(fit.nls$fitted, type="l", col="red", xlim=c(1, 900), pch=19, ann=FALSE, xaxt="n", 
axt="n") 
+0

'fit.lm' è di classe" lm ", quindi esiste un metodo di stampa. 'plot (fit.lm, type .....)' potrebbe essere più quello che vuoi. –

+0

Qual è il significato/dov'è il "366" proveniente dalla formula 2 * pi * tempo/366? – Vinterwoo

risposta

9

Questo perché i valori NA vengono rimossi dai dati per essere adattati (e i tuoi dati ne hanno parecchi); quindi, quando si calcola il valore fit.lm$fitted, il metodo plot interpreta l'indice di quella serie come i valori "x" per tracciarlo.

Prova questo [notare come ho cambiato i nomi delle variabili per prevenire i conflitti con le funzioni time e data (leggi this post)]:

Data <- read.table(file="900days.txt", header=TRUE, sep="") 
Time <- Data$time 
temperature <- Data$temperature 

xc<-cos(2*pi*Time/366) 
xs<-sin(2*pi*Time/366) 
fit.lm <- lm(temperature~xc+xs) 

# access the fitted series (for plotting) 
fit <- fitted(fit.lm) 

# find predictions for original time series 
pred <- predict(fit.lm, newdata=data.frame(Time=Time))  

plot(temperature ~ Time, data= Data, xlim=c(1, 900)) 
lines(fit, col="red") 
lines(Time, pred, col="blue") 

Questo mi dà:

enter image description here

Che probabilmente è quello che speravi.

+0

Mi chiedo come perfezionare in modo che la curva corrisponda effettivamente ai valori massimi di temperatura. – Eddie

+0

@Eddie Non sono sicuro di cosa intendi. Puoi chiarire? –

+1

Grazie ancora @Andy Barbour, speravo che la curva blu stia attraversando alcuni dei valori massimi (ad esempio a 29,5 gradi Celsius al primo picco). Al momento, il picco più alto per la previsione (curva blu) è di circa 28,8 gradi Celsius.Non sono sicuro di come affinare questo in lm. Per nls, penso di poterlo fare cambiando il valore dei miei parametri iniziali (che è anche una parte delicata). :) – Eddie

4

Come sulla scelta di una X e una Y, mentre facendo vostro diagramma linea invece di scegliere il Y.

plot(time,predict(fit.nls),type="l", col="red", xlim=c(1, 900), pch=19, ann=FALSE, xaxt="n", 
yaxt="n") 

anche sia lm e nls solo dare i punti a muro. Quindi è necessario stimare il resto dei punti per creare una curva, un grafico a linee. Dato che sei con nls e lm, forse la funzione predict potrebbe essere utile.

1

Non sono sicuro se questo potrebbe aiutare - ho una simile forma utilizzando solo sine:

y = amplitude * sin(pi * (x - center)/width) + Offset 

amplitude = 2.0009690806953033E+00 
center = -2.5813588834888215E+01 
width = 1.8077550471975817E+02 
Offset = 2.6872265116104828E+01 

Fitting target of lowest sum of squared absolute error = 3.6755174406241423E+01 

Degrees of freedom (error): 90 
Degrees of freedom (regression): 3 
Chi-squared: 36.7551744062 
R-squared: 0.816419142696 
R-squared adjusted: 0.810299780786 
Model F-statistic: 133.415731033 
Model F-statistic p-value: 1.11022302463e-16 
Model log-likelihood: -89.2464811027 
AIC: 1.98396768304 
BIC: 2.09219299292 
Root Mean Squared Error (RMSE): 0.625309918107 

amplitude = 2.0009690806953033E+00 
     std err squared: 1.03828E-02 
     t-stat: 1.96374E+01 
     p-stat: 0.00000E+00 
     95% confidence intervals: [1.79853E+00, 2.20340E+00] 
center = -2.5813588834888215E+01 
     std err squared: 2.98349E+01 
     t-stat: -4.72592E+00 
     p-stat: 8.41245E-06 
     95% confidence intervals: [-3.66651E+01, -1.49621E+01] 
width = 1.8077550471975817E+02 
     std err squared: 3.54835E+00 
     t-stat: 9.59680E+01 
     p-stat: 0.00000E+00 
     95% confidence intervals: [1.77033E+02, 1.84518E+02] 
Offset = 2.6872265116104828E+01 
     std err squared: 5.15458E-03 
     t-stat: 3.74289E+02 
     p-stat: 0.00000E+00 
     95% confidence intervals: [2.67296E+01, 2.70149E+01] 

Coefficient Covariance Matrix 
[ 0.02542366 0.01786683 -0.05016085 -0.00652111] 
[ 1.78668314e-02 7.30548346e+01 -2.18160818e+01 1.24965136e-01] 
[ -5.01608451e-02 -2.18160818e+01 8.68860810e+00 -1.27401806e-02] 
[-0.00652111 0.12496514 -0.01274018 0.0126217 ] 

James Phillips [email protected]

+1

Grazie a @James Phillips. È vero. Potresti voler controllare questo post http://stats.stackexchange.com/questions/60500/how-to-find-a-good-fit-for-semi-sinusoidal-model-in-r – Eddie

0

In alternativa, si potrebbe avere eliminato le AN dai dati dopo aver letto in:

data <- subset(data, !is.na(temperature)) 

Poi, durante la stampa, è possibile impostare l'asse x per i punti di tempo dal ridotto insieme di dati:

plot(temp~time, data=data, xlim=c(1, 900)) 
lines(x=time, y=fit.lm$fitted, col="red") 

Questa curva non sarà liscio come quello prodotto da @ andy-barbour ma funzionerà in una presa.

Problemi correlati