检测时间序列的变化(R示例)


18

我想检测通常具有相同形状的时间序列数据的变化。到目前为止,我已经使用changepointR和cpt.mean(), cpt.var()and cpt.meanvar()函数的软件包。cpt.mean()当数据通常保持在一个级别时,使用PELT方法的效果很好。但是,我也想检测下降期间的变化。我要检测的一个变化示例是黑色曲线突然下降而实际上应遵循示例性红色虚线的部分。我已经尝试过cpt.var()函数,但是无法获得良好的结果。您是否有任何建议(不必使用R)?

改变曲线

这是具有更改的数据(作为R对象):

dat.change <- c(12.013995263488, 11.8460207231808, 11.2845153487846, 11.7884417180764, 
11.6865425802022, 11.4703118125303, 11.4677576899063, 11.0227199625084, 
11.274775836817, 11.03073498338, 10.7771805591742, 10.7383206158923, 
10.5847230134625, 10.2479315651441, 10.4196381241735, 10.467607842288, 
10.3682422713283, 9.7834431752935, 9.76649842404295, 9.78257968297228, 
9.87817694914062, 9.3449034905713, 9.56400153361727, 9.78120084558148, 
9.3445162813738, 9.36767436354887, 9.12070987223648, 9.21909859069157, 
8.85136359917466, 8.8814423003979, 8.61830163359642, 8.44796977628488, 
8.06957847272046, 8.37999165387824, 7.98213210294954, 8.21977468333673, 
7.683960439316, 7.73213584532496, 7.98956476021092, 7.83036046746187, 
7.64496198988985, 4.49693528397253, 6.3459274845112, 5.86993447552116, 
4.58301192892403, 5.63419551523625, 6.67847511602895, 7.2005344054883, 
5.54970477623895, 6.00011922569104, 6.882667104467, 4.74057284230894, 
6.2140437333397, 6.18511450451019, 5.83973575417525, 6.57271194428385, 
5.36261938326723, 5.48948831338016, 4.93968645996861, 4.52598133247377, 
4.56372558828803, 5.74515428123725, 5.45931581984165, 5.58701112949141, 
6.00585679276365, 5.41639695946931, 4.55361875158434, 6.23720558202826, 
6.19433060301002, 5.82989415940829, 5.69321394985076, 5.53585871082265, 
5.42684812413063, 5.80887522466946, 5.56660158483312, 5.7284521523444, 
5.25425775891636, 5.4227645808924, 5.34778016248718, 5.07084809927736, 
5.324066161355, 5.03526881241705, 5.17387528516352, 5.29864121433813, 
5.36894461582415, 5.07436929444317, 4.80619983525015, 4.42858947882894, 
4.33623051506001, 4.33481791951228, 4.38041031792294, 3.90012900415342, 
4.04262777674943, 4.34383842876647, 4.36984816425014, 4.11641092254315, 
3.83985887104645, 3.81813419810962, 3.85174630901311, 3.66434598962311, 
3.4281724860426, 2.99726515704766, 2.96694634792395, 2.94003031547181, 
3.20892607367132, 3.03980832743458, 2.85952185077593, 2.70595278908964, 
2.50931109659839, 2.1912274016859)

请注意,如果您仅要求提供R代码,则此处将不合时宜。如果您需要一般的方法学建议,那很好。它可能带有一些R代码,但随后可能没有。
gung-恢复莫妮卡

1
好的说,我对通用解决方案感兴趣,使用R会很方便。
mlee

Answers:


17

您可以使用时间序列离群值检测来检测时间序列的变化。 TsayChen和Liu的程序是流行的时间序列离群值检测方法。请参阅我在此站点上的先前问题

R的tsoutlier软件包使用Chen和Liu的方法检测异常值。SAS / SPSS / Autobox也可以执行此操作。有关检测时间序列变化的R代码,请参见下文。

library("tsoutliers")
dat.ts<- ts(dat.change,frequency=1)
data.ts.outliers <- tso(dat.ts)
data.ts.outliers
plot(data.ts.outliers)

tsoultlier软件包中的tso函数可识别以下异常值。您可以阅读文档以找出异常值的类型。

Outliers:
  type ind time coefhat   tstat
1   TC  42   42 -2.9462 -10.068
2   AO  43   43  1.0733   4.322
3   AO  45   45 -1.2113  -4.849
4   TC  47   47  1.0143   3.387
5   AO  51   51  0.9002   3.433
6   AO  52   52 -1.3455  -5.165
7   AO  56   56  0.9074   3.710
8   LS  62   62  1.1284   3.717
9   AO  67   67 -1.3503  -5.502

该软件包还提供了不错的情节。见下文。该图显示了异常值在哪里,如果没有异常值,将会发生什么情况。

在此处输入图片说明

我还使用了称为strucchange的 R包来检测电平变化。以您的数据为例

library("strucchange")
breakpoints(dat.ts~1)

该程序可以正确识别断点或结构更改。

Optimal 4-segment partition: 

Call:
breakpoints.formula(formula = dat.ts ~ 1)

Breakpoints at observation number:
17 41 87 

Corresponding to breakdates:
17 41 87 

希望这可以帮助


1
谢谢,tso效果很好,但是对于较大的数据集来说有点慢。struccchange的断点位置似乎有些随意(位置41除外)。
mlee

7

我将从以下角度解决这个问题。这些只是我脑海中的一些想法-请带上一粒盐。不过,我希望这会有所帮助。

  • 时间序列聚类。例如,通过使用流行的动态时间规整(DTW)或替代方法。请参阅我的相关答案:在DTW上进行分类/聚类在DTW上或在时间序列不均匀的替代方法上。这个想法是将时间序列分为“正常”和“异常”(或类似)类别。

  • 熵测度。请参阅我有关时间序列熵测度的相关答案。该想法是确定“正常”时间序列的熵,然后将其与其他时间序列进行比较(此想法假设在偏离“正常”的情况下存在熵偏差)。

  • 异常检测。请参阅我有关异常检测的相关答案(包括R资源)。这个想法是通过各种方法直接检测异常(请参阅参考资料)。预警信号(EWS)工具箱R软件包earlywarnings似乎特别有希望。


6

我使用AUTOBOX的响应与@forecaster十分相似,但模型更简单。Box和Einstein等人都在思考如何使解决方案保持简单而不是太简单。自动开发的模型为在此处输入图片说明。实际情况与清洗后的情节非常相似在此处输入图片说明。残差图(应始终显示)在此处输入图片说明以及残差的强制性acf 在此处在此处输入图片说明。在“决斗模型”之间进行比较时,残差的统计总是有用的在此处输入图片说明。实际/适合/预测图在这里在此处输入图片说明


1

如果您对数据进行去趋势处理,似乎可以大大简化您的问题。它似乎线性下降。一旦消除了数据的趋势,就可以应用各种非平稳性测试。


3
这种方法将失败,因为历史上存在明显不同的斜率。除非您合并多个“趋势/斜率”,否则该方法将不会产生有意义的结果。简单直接的解决方案通常太简单了。
IrishStat

1

很好的答案,但这是@MrMeritology建议的一个简单答案,它似乎对于所讨论的时间序列以及其他许多“相似”数据集都适用。

这是一个R片段,产生了下面的自说明图。

outl = rep( NA, length(dat.change))
detr = c( 0, diff( dat.change))

ix = abs(detr) > 2*IQR( detr)
outl[ix] = dat.change[ix]

plot( dat.change, t='l', lwd=2, main="dat.change TS")
points( outl, col=2, pch=18)

plot( detr, col=4, main="detrended TS", t='l', lwd=2 )
acf( detr, main="ACF of detrended TS")

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明


可能存在多个趋势变化和多个截距变化(水平移动)...因此,需要找到一种可以对数据进行实际诊断的解决方案,以确定这些结果...
IrishStat

是的,确实,我已经阅读了您之前的评论。但是,诊断时间序列以检测多个趋势/水平本身就是一个问题。我的意思是表明上述简单方法有时会起作用,特别是对于给定的数据。相反,没有任何一种方法会始终有效。我否则建议使用R.Hyndman(R函数tsoutliers)的方法。
dnqxt

AUTOBOX是一种始终有效的单一方法(至少对于我们已经看到的无数时间序列而言),并且有R版本。如果您希望离线聊天,因为我不想在这里聊天,那么我可以解释一下完全可以理解/透明但不容易重复的过程。
IrishStat
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.