我想检测时间序列状态变化(或异常)。 所谓政权变更,是指线性趋势已改变/破坏(请参见下图)。
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()
我已经搜索了一段时间,但是找不到一种方法来检测此时间序列中的重大变化。
检测差异对我来说还不够,因为我需要能够检测到大致的线性趋势已更改。数据从一个观察值到下一个观察值的差异可能很大,但趋势(线性趋势)仍然正确。
解释为什么我放弃diff方法:
在x轴上大约45-46处观察到的值显示出跳跃,但实际上处于线性趋势,因此对我而言不是“区域变化”。这就是为什么我放弃了diff方法而正在寻找“趋势”方法的原因。 我一直在考虑循环观察,拟合线性回归并预测下一个点,计算误差等。但是,如果存在的话,我宁愿为此使用一个库。
答案 0 :(得分:1)
让我绘制数据的差异(橙色)和二阶(绿色):
据我所知,这两种方法对于检测跳跃均具有相当大的歧视性,在这种情况下,将简单的阈值作为分类器即可。
二阶差异应该特别说明跳转,因为您描述任务的方式是:对于线性变化,必然为(大约)零非跳跃的部分。
完整的代码可以重现情节:
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()