数据框的复杂掩码

Complex mask for dataframe

我有一个数据框,其中一个列包含一个时间序列。数据看起来像这个图表

我想创建一个每次数据等于或小于 -0.20 时都为 TRUE 的掩码。它也应该是 TRUE before 达到 -0.20 而为负。 after 达到 -0.20 也应该是 true 为负。 本版图

是我手动尝试显示(红色)掩码为 TRUE 的值。我开始创建掩码,但我只能在数据小于 -0.20 mask = (df['data'] < -0.2) 时使其等于 TRUE。我不能做得更好了,有人知道如何实现我的目标吗?

想法

按相同符号的连续值分组,然后检查这样一组的最小值是否小于定义的阈值。

实施

首先,我们要将负值与正值分开。

negative_mask = (df['data']<0)

然后我们可以为每个连续的正序列或负序列创建 classes(以整数排序)。每次数据改变符号时,class 加一。

consecutives = negative_mask.diff().ne(0).cumsum()

然后我们select只取连续元素组中最小值小于0.2的数据

df.groupby(consecutives).filter(lambda df : df[0].min() < -0.2)

随机数据示例

我们可以用随机数据试试我们的例子:

import numpy as np
import pandas as pd

np.random.seed(42)
data = np.random.randint(-300, 300, size=1000)/1000
df = pd.DataFrame(data, columns=["data"])

输出

    data
2   -0.030
3   -0.194
4   -0.229
5   -0.280
6   -0.179
... ...
991 -0.293
995 -0.247
996 -0.062
997 -0.072
999 -0.250

363 rows × 1 columns

一种方法是将完全低于零的段分组,然后针对每个组验证是否有任何值低于 -0.2

请参阅下面的完整可重现示例脚本:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


np.random.seed(167)

df = pd.DataFrame(
    {"y": np.cumsum([np.random.uniform(-0.01, 0.01) for _ in range(10 ** 5)])}
)
plt.plot(df)

gt_zero = df["y"] < 0
regions = (gt_zero != gt_zero.shift()).cumsum()

# here's your interesting DataFrame with the specified mask
df_interesting = df.groupby(regions).filter(lambda s: s.min() < -0.2)

# plot individual regions
for i, grp in df.groupby(regions):
    if grp["y"].min() < -0.2:
        plt.plot(grp, color="tab:red", linewidth=5, alpha=0.6)

plt.axhline(0, linestyle="--", color="tab:gray")
plt.axhline(-0.2, linestyle="--", color="tab:gray")
plt.show()