使用R的时间序列的STL趋势

机器算法验证 r 时间序列 趋势
2022-02-05 07:52:24

我是 R 和时间序列分析的新手。我试图找到长期(40 年)每日温度时间序列的趋势,并尝试不同的近似值。第一个只是一个简单的线性回归,第二个是 Loess 对时间序列的季节分解。

在后者中,似乎季节性成分大于趋势。但是,如何量化趋势?我想要一个数字来说明这种趋势有多强。

     Call:  stl(x = tsdata, s.window = "periodic")
     Time.series components:
        seasonal                trend            remainder               
Min.   :-8.482470191   Min.   :20.76670   Min.   :-11.863290365      
1st Qu.:-5.799037090   1st Qu.:22.17939   1st Qu.: -1.661246674 
Median :-0.756729578   Median :22.56694   Median :  0.026579468      
Mean   :-0.005442784   Mean   :22.53063   Mean   : -0.003716813 
3rd Qu.:5.695720249    3rd Qu.:22.91756   3rd Qu.:  1.700826647    
Max.   :9.919315613    Max.   :24.98834   Max.   : 12.305103891   

 IQR:
         STL.seasonal STL.trend STL.remainder data   
         11.4948       0.7382    3.3621       10.8051
       % 106.4          6.8      31.1         100.0  
     Weights: all == 1
     Other components: List of 5   
$ win  : Named num [1:3] 153411 549 365  
$ deg  : Named int [1:3] 0 1 1   
$ jump : Named num [1:3] 15342 55 37  
$ inner: int 2  
$ outer: int 0

在此处输入图像描述

2个回答

我不会stl()为此烦恼 - 用于提取趋势的最低平滑器的带宽非常非常小,导致您看到的小规模波动。我会使用加法模型。这是一个使用 Simon Wood 的 GAM 书中的数据和模型代码的示例:

require(mgcv)
require(gamair)
data(cairo)
cairo2 <- within(cairo, Date <- as.Date(paste(year, month, day.of.month, 
                                              sep = "-")))
plot(temp ~ Date, data = cairo2, type = "l")

开罗温度数据

拟合具有趋势和季节性成分的模型 ---警告这很慢:

mod <- gamm(temp ~ s(day.of.year, bs = "cc") + s(time, bs = "cr"),
            data = cairo2, method = "REML",
            correlation = corAR1(form = ~ 1 | year),
            knots = list(day.of.year = c(0, 366)))

拟合模型如下所示:

> summary(mod$gam)

Family: gaussian 
Link function: identity 

Formula:
temp ~ s(day.of.year, bs = "cc") + s(time, bs = "cr")

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  71.6603     0.1523   470.7   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

Approximate significance of smooth terms:
                 edf Ref.df       F p-value    
s(day.of.year) 7.092  7.092 555.407 < 2e-16 ***
s(time)        1.383  1.383   7.035 0.00345 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

R-sq.(adj) =  0.848  Scale est. = 16.572    n = 3780

我们可以通过以下方式可视化趋势和季节性术语

plot(mod$gam, pages = 1)

开罗适合趋势和季节性

如果我们想在观察到的数据上绘制趋势,我们可以通过以下方式进行预测:

pred <- predict(mod$gam, newdata = cairo2, type = "terms")
ptemp <- attr(pred, "constant") + pred[,2]
plot(temp ~ Date, data = cairo2, type = "l",
     xlab = "year",
     ylab = expression(Temperature ~ (degree*F)))
lines(ptemp ~ Date, data = cairo2, col = "red", lwd = 2)

开罗合身趋势

或与实际模型相同:

pred2 <- predict(mod$gam, newdata = cairo2)
plot(temp ~ Date, data = cairo2, type = "l",
     xlab = "year",
     ylab = expression(Temperature ~ (degree*F)))
lines(pred2 ~ Date, data = cairo2, col = "red", lwd = 2)

开罗合身模型

这只是一个例子,更深入的分析可能需要处理缺少数据的事实,但以上应该是一个很好的起点。

至于你关于如何量化趋势的观点 - 这是一个问题,因为趋势不是线性的,无论是在你的stl()版本还是我展示的 GAM 版本中。如果是,您可以给出变化率(斜率)。如果您想知道在采样期间估计的趋势变化了多少,那么我们可以使用其中包含的数据并仅计算趋势分量pred中序列的开始和结束之间的差异:

> tail(pred[,2], 1) - head(pred[,2], 1)
    3794 
1.756163

因此,平均温度比记录开始时高 1.76 度。

Gavin 提供了一个非常彻底的答案,但是为了更简单和更快的解决方案,我建议将stl函数t.window参数设置为ts数据频率倍数的值。我会使用推断出的感兴趣的周期性(例如,对于具有日分辨率数据的年代际趋势,值为 3660)。您可能还对作者论文中描述的stl2包感兴趣。我已经将 Gavin 的方法应用于我自己的数据,它也非常有效。