如何在R中找到一个适合半正弦模型的模型?


37

我想假设波罗的海的海面温度年复一年,然后用函数/线性模型对其进行描述。我的想法是只将年输入为十进制数字(或num_months / 12),然后得出当时的温度。将其扔到R中的lm()函数中,它无法识别正弦数据,因此只能产生一条直线。因此,我将sin()函数放在I()括号内,并尝试了一些值以手动适合该函数,这接近我想要的值。但是海洋在夏天变暖得更快,而在秋天变慢了……所以第一年的模型是错误的,几年后变得更正确,然后在将来我猜想它会变得更多再犯错。

如何获得R来为我估算模型,所以我不必自己猜测数字?这里的关键是我希望它年复一年地产生相同的值,而不仅仅是一年正确。如果我对数学了解更多,也许我可以将其估计为类似于Poisson或Gaussian之类的东西,而不是sin(),但我也不知道该怎么做。任何帮助您接近一个好的答案将不胜感激。

这是我使用的数据,以及到目前为止显示结果的代码:

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

Answers:


44

可以通过线性回归完成-

每个频率只需要和项即可。sincos

之所以可以在线性回归中使用和项来处理任何振幅和相位的季节性,是因为以下三角身份sincos

具有幅度和相位,的“一般”正弦波可以写成线性组合 ,其中和使得和。让我们看看两者是等效的:AφAsin(x+φ)asinx+bcosxabA=a2+b2sinφ=ba2+b2

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

这是“基本”模型:

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

[片段]

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)

罪恶适合

编辑:重要说明项之所以有效,是因为函数的周期已设置为1周期= 1单位。如果周期不同于1,则说周期为,则需要代替。ω 2 π / ω 2πttω(2π/ω)t

这是具有二次谐波的模型:

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

[片段]

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)

罪恶适合2

...等等,依此类推6*pi*ToY。如果数据中有一点点噪音,我可能会停止使用第二个模型。

有了足够的条件,您就可以完全拟合不对称甚至锯齿状的周期序列,但是拟合结果可能会“摆动”。这是一个不对称函数(它是锯齿形- 锯齿),已添加到周期函数的缩放版本中,具有三次谐波(红色)和三次谐波(绿色)。平均而言,绿色拟合更接近但“摇摆”(即使当拟合遍及每个点时,各点之间的拟合也可能非常摇摆)。

罪恶适合3&4

这里的周期性意味着数据中的季节性模型只有12 df可用。使用模型中的截距,您只能为11个其他季节性参数提供足够的自由度。由于您要为每个谐波添加两个项,因此您可以拟合的最后一个谐波将只允许您使用其中一个作为最后一个项,即第六个谐波(并且那个谐波必须为;项将全部为-零,而cos在1和-1之间交替)。cossin

如果您想要的拟合比此方法在非平滑序列上生成的平滑,则可能需要研究周期性的样条拟合。

还有一种方法是使用季节性假人,但如果它是平滑的周期性函数,则sin / cos方法通常更好。

这种季节性方法也可以适应季节性变化的情况,例如对状态空间模型使用三角函数或伪季节性。


尽管此处讨论的线性模型方法易于使用,但@COOLSerdash的非线性回归方法的一个优点是它可以处理更广泛的情况-在处于线性情况下,您无需进行太多更改回归不再适用,但是仍然可以使用非线性最小二乘法(有一个未知的周期就是这种情况)。


太棒了!谢谢,我真的应该尝试更多地了解处理频率的方法。我不太了解为什么需要cos部分,但是了解该原理使其易于实现。
留美

@COOLSerdash-实际上,我希望您没有删除答案(实际上我赞成)。它具有在更广泛的环境中工作的优势;对问题进行一些调整,您可能会失去线性-然后我的方法没有用,但您的方法仍然有效。我认为能够以这种方式做很多事情。
2013年

@Glen_b抱歉,我以为您的帖子使我的职位多余了,因为我没有使用处理问题的标准方法。我不删除它。
COOLSerdash

@GaRyu在答案的顶部附近看到我的编辑内容,其中概述了为什么添加可以达到目的。cos
2013年

1
那不是我。。。。您说的是相位偏移,就好像那是正在发生的事情一样,它在数学上是可行的。但是对于您来说,关键点很可能是12月31日/ 1月1日是一年中任意时间的起点,因为温度对辐射接收变化的响应会有所滞后。因此,相位偏移在这里也是气候学的名称,相对于您的记录系统的最低和最高温度的计时。(这是一个较小的细节,但我希望将12个月的时间量化为1 / 24、3 / 24,...,23/24。)
尼克·考克斯

10

您在问题中提供的温度每年都会重复。我怀疑这不是四年来的实际测量温度。在您的示例中,您不需要模型,因为温度只是精确地重复。但是否则,您可以使用该nls函数拟合正弦曲线:

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适合

但是拟合度不是很好,尤其是在一开始的时候。看来您的数据无法通过简单的正弦曲线进行充分建模。也许更复杂的三角函数可以解决问题?

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适合2

红色曲线更适合数据。使用该nls功能,可以放入您认为合适的模型。

或者,您可以使用该forecast包装。在下面的示例中,我假设时间序列从2010年1月开始:

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

有马

因为数据是确定性的,所以没有显示置信带。


4
这里没有理由使用非线性最小二乘,也不是说它不能很好地工作。提前计算sin(2 * pi * ToY),cos(2 * pi * ToY)并将它们lm()像其他任何预测变量一样输入。换句话说,lm()根本不需要看到任何三角函数。但是,您可能需要另一个模型才能很好地捕获标记的不对称性。我不是普通的R用户,但我经常在其他地方使用此方法(请参阅stata-journal.com/sjpdf.html?articlenum=st0116)。
尼克·考克斯

@NickCox感谢尼克,这是非常有用的建议。我将稍后更新我的答案。
COOLSerdash

Glen更快了:)
COOLSerdash

1
@COOLserdash我什至没有看到尼克·考克斯的评论;它是在我生成答案时出现的。(如果您已经看过任何傅立叶级数,则这种方法非常明显。)
Glen_b

2
就像@Glen_b所暗示的那样,这是一种标准方法,只是尚未广为人知。
尼克·考克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.