如何检测时间序列中的翻转?

4

针对一个在不同操作模式下运行的系统,我希望减少模式之间的切换。因此需要检测切换并进行纠正。

假设我们有一个频繁切换模式的序列:

before = [0,0,0,(1,0),1,1,1,2,2,(1,2),1,1,1,(0,1),0]   # parenthesis indicate flipping

我只想在(变化点)处进行交换,以获得:

after  = [0,0,0,(0,1),1,1,1,2,2,(2,1),1,1,1,(1,0),0]   # parenthesis indicate corrections

当我如何实现这一目标?

1
你的问题非常有趣。我认为你自己的努力应该成为问题的一部分。起初,我以为这个问题已经得到了合适的回答。 - Michael Szczesny
1
模式更改像 0,1,20,1,1,2 可能吗?甚至是 0,2 - Wups
实际上,答案反映了我的解决方案,因为我到目前为止没有得到外部支持。我的最初问题在3天后被关闭。 - Oliver Prislan
@Wups 迄今为止,它只考虑了单步操作。通过卷积方法,可以通过添加一个额外的if语句轻松添加两个步骤。重要的是要确保没有引入歧义。这就是为什么我选择了[1,2,5,10]作为我的过滤器值的原因。 - Oliver Prislan
2个回答

3

有一种“简单”的方法可以找到范围为1的翻转,但对于连续重复的翻转不起作用。

before = np.array([0,0,1,0,0,1,0,1,1,1,2,2,1,2,1,1,1,0,1,0,0])
goal = np.array(  [0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,1,0,0,0])

diff = np.diff(before)          # find 'jumps' with range 1
diff[:-1][(diff == 0)[1:]] = 0  # correct 'right' side of 'jumps'
after = before - np.r_[0,diff]  # correct flipping

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')
plt.legend();

输出

平滑信号

可以使用更大的步长和负“跳跃”。

before = np.array([0,0,-1,0,0,1,0,1,1,1,4,4,1,4,1,1,1,0,1,0,0])
goal = np.array(  [0,0, 0,0,0,0,1,1,1,1,4,4,4,1,1,1,1,1,0,0,0])

diff = np.diff(before)          # find flipping with range 1
diff[:-1][(diff == 0)[1:]] = 0  # correct 'right' side of signal
after = before - np.r_[0,diff]  # correct flipping

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')
plt.legend();

输出

更大的步长


解决方案的限制

  • 连续重复翻转
    before = [0,1,0,1,0,1,1,1,1]
    goal   = [0,0,0,0,1,1,1,1,1]

wrong result


这是一个非常好的观点。当系统不断翻转时,您无法将其分配给一个状态或另一个状态。但是您仍然可以使用卷积来检测它。[0,1,0,1,0]会卷积到-6,而[1,0,1,0,1]则会根据我下面的答案给出6。 - Oliver Prislan

2

我通过开发一个小型卷积滤波器来解决这个问题,目的是检测翻转。 目前它可以检测单个翻转(on-off-on或off-on-off)

构建差分信号可以支持不同的单个交换,即使在超过2个操作模式之间也是如此。

import numpy as np
import matplotlib.pyplot as plt

before = np.array([0,0,1,0,0,1,0,1,1,1,2,2,1,2,1,1,1,0,1,0,0])
goal = np.array(  [0,0,0,0,0,0,1,1,1,1,2,2,2,1,1,1,1,1,0,0,0])
after  = before.copy()
fltr = np.array([1,2,5,10])        # convolution filter

for i in range(0,len(before)-4):
    dif = np.diff(after)
    conv = (fltr*dif[i:i+4]).sum() # conv-filter applied on diff()
    if abs(conv) == 3:       # 00100 = 00000 or 11011 = 11111
        after[i+2] = after[i+1]  
    if abs(conv) == 7:
        b = after[i+2]       # 00101 = 00011 or 11010 = 11100
        after[i+2] = after[i+3]
        after[i+3] = b

plt.plot(before, linestyle='--',label='before')
plt.plot(goal,   linestyle='-.',label='goal')
plt.plot(after,  linestyle=':', label='after')

plt.legend()
plt.show

注意:也许这个解决方案是不完整的,不能涵盖所有可能的情况。请推荐更高级/替代方案。


1
你能解释一下为什么要使用过滤器,而不是只比较每个样本与相邻的样本来查看翻转吗? - Gulzar
使用卷积滤波器的优点在于,它不仅考虑当前和之前的样本。由于卷积集成了5个样本(4个差分),因此它可以向未来2个样本和过去2个样本进行查看。如果您使用if语句实现这一点,代码会变得非常混乱。 - Oliver Prislan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接