计算时间序列穿过熊猫上下限的次数

时间:2020-03-04 18:51:15

标签: pandas

假设我有一个df,看起来像这样:

df = pd.DataFrame({'Upper': [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 
                   'Lower': [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],
                   'X': [0,1,1.5,1,0.5,1,1.5,1,0,-0.5,-1,-1.5,-1,-0.5,-1,-1.5,-1,0]})

这给了我们结果图表: enter image description here

我需要做的是计算红线X越过UpperLower行然后再越过另一行的次数。在上面的示例中,计数仅为1。

我在想的可能是创建一个列,该列记录最近违反的行是什么,然后计算行切换的时间序列中的次数。

这看起来像这样:

    Upper  Lower    X Breach
0       1     -1  0.0    NaN
1       1     -1  1.0    NaN
2       1     -1  1.5  Upper
3       1     -1  1.0  Upper
4       1     -1  0.5  Upper
5       1     -1  1.0  Upper
6       1     -1  1.5  Upper
7       1     -1  1.0  Upper
8       1     -1  0.0  Upper
9       1     -1 -0.5  Upper
10      1     -1 -1.0  Upper
11      1     -1 -1.5  Lower
12      1     -1 -1.0  Lower
13      1     -1 -0.5  Lower
14      1     -1 -1.0  Lower
15      1     -1 -1.5  Lower
16      1     -1 -1.0  Lower
17      1     -1  0.0  Lower

正如您在索引位置10和11看到的那样,我们从Upper更改为Lower,然后将其计为1。

我真的不知道如何实现这一目标?我的实时时间序列很大,因此我需要对这些时间序列进行大量计算。

任何帮助将不胜感激。干杯。

1 个答案:

答案 0 :(得分:2)

创建两个Series,一个检查我们是否在上限之上,另一个检查您是否在下限之下。然后,通过将较高的部分与较低的部分分组,可以确定您在较高的边界上方/下方的位置,然后切换到相对的边界上方或下方。

我们需要手动清理边缘。由于shift给它一个NaN,所以最后一点总是被错误地标记,因此我们将其删除。对于左边缘,我们检查它是否超过下限,然后再越过上限,并相应地保留或删除第一个索引。

(我添加了几行内容来说明在多种不同情况下如何工作)。

样本

import pandas as pd
df = pd.DataFrame({'X': [0,1,1.5,1,0.5,1,1.5,1,0,-0.5,-1,-1.5,-1,
                         -0.5,-1,-1.5,-1,0,0.75,1.5, 2, 2, 2, 1, -1,-1.5, -0.5, 
                         0, -1.5, 0, 0.25, -1.5, -1, 0.25,0.75, 1.25, 0.75, 
                         0.5, 1.7, 0.5, 1.1, 0.25, -0.5, -1.1, -0.9, -1.4]})
df['Upper'] = 1
df['Lower'] = -1

代码

up = df['X'].gt(df['Upper'])
low = df['X'].lt(df['Lower'])
up = up.groupby(low.cumsum()).cummax()

# Determine where switches occur, last is always dropped
indices = up[up.ne(up.shift(-1))].index[:-1]  
#Int64Index([1, 10, 18, 24, 34, 42], dtype='int64')

# Check if we need to remove the first point
init = df[~up.cummax()]
if not any(init['X'].lt(init['Lower'])):
    indices = indices[1:]

# This correctly flags the last index before the switch
print(indices)
#Int64Index([10, 18, 24, 34, 42], dtype='int64')

结果说明

垂直线绘制在我上面标记的索引值上。

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
df['X'].plot(ax=ax, marker='o')
ax.axhline(1, 0, 1, color='red')
ax.axhline(-1, 0, 1, color='red')

for index in indices:
    ax.axvline(index, 0, 1, color='grey', linestyle='--')

enter image description here