假设我有一个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]})
我需要做的是计算红线X
越过Upper
或Lower
行然后再越过另一行的次数。在上面的示例中,计数仅为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。
我真的不知道如何实现这一目标?我的实时时间序列很大,因此我需要对这些时间序列进行大量计算。
任何帮助将不胜感激。干杯。
答案 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='--')