检测时间序列中的政权变化

时间:2019-06-26 12:19:50

标签: python

我想检测时间序列状态变化(或异常)。 所谓政权变更,是指线性趋势已改变/破坏(请参见下图)。

import numpy as np
import matplotlib.pyplot as plt

x = range(50)
y = [1.28, 1.28, 1.26, 1.32, 1.34, 1.33, 1.38, 1.39, 1.37, 1.42, 
1.42, 1.41, 1.39, 1.41, 1.45, 1.45, 1.46, 1.5, 1.49, 1.53, 1.53, 
1.54, 1.61, 1.59, 1.62, 1.66, 1.63, 1.66, 1.66, 1.7, 1.76, 1.84, 
1.88, 1.97, 1.94, 1.98, 2.01, 2.02, 0.73, 0.72, 0.76, 0.87, 0.97, 
1.01, 0.98, 1.16, 1.22, 1.3, 1.27, 1.33]

plt.scatter(x, y)
plt.show()

enter image description here 我已经搜索了一段时间,但是找不到一种方法来检测此时间序列中的重大变化。

检测差异对我来说还不够,因为我需要能够检测到大致的线性趋势已更改。数据从一个观察值到下一个观察值的差异可能很大,但趋势(线性趋势)仍然正确。

解释为什么我放弃diff方法:

在x轴上大约45-46处观察到的值显示出跳跃,但实际上处于线性趋势,因此对我而言不是“区域变化”。这就是为什么我放弃了diff方法而正在寻找“趋势”方法的原因。 我一直在考虑循环观察,拟合线性回归并预测下一个点,计算误差等。但是,如果存在的话,我宁愿为此使用一个库。

1 个答案:

答案 0 :(得分:1)

让我绘制数据的差异(橙色)和二阶(绿色):

Data, differences and second-order differences

据我所知,这两种方法对于检测跳跃均具有相当大的歧视性,在这种情况下,将简单的阈值作为分类器即可。

二阶差异应该特别说明跳转,因为您描述任务的方式是:对于线性变化,必然为(大约)零非跳跃的部分。

完整的代码可以重现情节:

import numpy as np                                                                                                                                                                                                                           
import matplotlib.pyplot as plt                                                                                                                                                                                                              


x = range(50)                                                                                                                                                                                                                                
y = [1.28, 1.28, 1.26, 1.32, 1.34, 1.33, 1.38, 1.39, 1.37, 1.42,                                                                                                                                                                             
1.42, 1.41, 1.39, 1.41, 1.45, 1.45, 1.46, 1.5, 1.49, 1.53, 1.53,                                                                                                                                                                             
1.54, 1.61, 1.59, 1.62, 1.66, 1.63, 1.66, 1.66, 1.7, 1.76, 1.84,                                                                                                                                                                             
1.88, 1.97, 1.94, 1.98, 2.01, 2.02, 0.73, 0.72, 0.76, 0.87, 0.97,                                                                                                                                                                            
1.01, 0.98, 1.16, 1.22, 1.3, 1.27, 1.33]                                                                                                                                                                                                     


def get_deltas(series):                                                                                                                                                                                                                      
    return [series[i+1] - series[i] for i in range(len(series)-1)]                                                                                                                                                                           


y_delta = get_deltas(y)                                                                                                                                                                                                                      
y_delta_delta = get_deltas(y_delta)                                                                                                                                                                                                          

plt.scatter(x, y)                                                                                                                                                                                                                            
plt.scatter(x[:-1], y_delta)                                                                                                                                                                                                                 
plt.scatter(x[:-2], y_delta_delta)                                                                                                                                                                                                           
plt.show()