如何根据每个区间的特定条件将数据标记为异常
How to mark data as anomalies based on specific condition in each interval
我尝试在很多地方搜索这个问题,但找不到合适的工具。
我有一个简单的时间序列数据,
print(anom)
0 0
1 0
2 0
3 0
4 0
..
52777 1
52778 1
52779 0
52780 1
对于 = 1 且跨越(例如 1000 个时间实例)的任何数据序列。我想将它们标记为异常(正确)。否则他们应该被忽略(为假)。
如何使用 pandas 或 numpy 实现此目的?
我也想绘制那些异常,例如红色,我们如何实现?
如何将这些异常(值 = 1,范围为大约 1000 个时间实例)标记为红色?
不完全清楚您期望的输出。
然而,让我们考虑以下类似于您的数据集:
s = pd.Series(np.random.choice([0,1], size=100, p=[0.7, 0.3]), name='anom')
0 1
1 0
2 0
3 0
4 0
..
95 0
96 1
97 1
98 0
99 1
Name: anom, Length: 100, dtype: int64
看起来像:
根据连续值过滤
首先我们计算1s的长度
length = s.groupby(((s-s.shift().fillna(0)).eq(1).cumsum()*s)).transform(len)*s
这通过识别延伸的第一个元素来工作 (s-s.shift().fillna(0)).eq(1)
(一个元素和先例之间的差异仅在 1 前面有 0 的情况下为 1,请参见下图 #2)。然后它使递增的组(图#3)对每段 1 和连续的 0 段进行分组。通过乘以 s
,只有 1 保留在组中(图 #4)。现在我们可以对每个拉伸的数据进行分组并计算每个数据的长度(图 #5)。 0 将全部属于一组,所以最后,我们通过再次乘以 s
(图 #6)来删除零。
这是连续步骤的直观表示,其中 (…)
表示每个图中的前一步:
s_valid = s.loc[length<10]
s_anom = s.drop(s_valid.index)
ax = s_valid.plot(marker='o', ls='')
s_anom.plot(marker='o', ls='', ax=ax, color='r')
ax = s.plot()
s_anom.plot(marker='o', ls='', ax=ax, color='r')
另一个以7为阈值的例子:
原回答
您可以轻松转换为 bool
以获得异常值
>>> s.astype(bool)
0 True
1 False
2 False
3 False
4 False
...
95 False
96 True
97 True
98 False
99 True
Name: anom, Length: 100, dtype: bool
关于剧情,看你的期待你可以做什么:
s_valid = s.loc[~s.astype(bool)]
s_anom = s.loc[s.astype(bool)]
ax = s_valid.plot(marker='o', ls='')
s_anom.plot(marker='o', ls='', ax=ax, color='r')
输出:
s_anom = s.loc[s.astype(bool)]
ax = s.plot()
s_anom.plot(marker='o', ls='', ax=ax, color='r')
设置
np.random.seed(1)
anom = pd.Series(np.random.choice([0, 1], p=[0.2, 0.8], size=10000))
print(anom)
0 1
1 1
2 0
3 1
4 0
..
9995 1
9996 1
9997 0
9998 0
9999 1
Length: 10000, dtype: int64
解决方案
检测异常
m = anom == 1
c = anom[m].groupby((~m).cumsum()).transform('count')
a = c[c > 25].clip(upper=1) # Detection threshold=25
绘制检测到的异常
fig, ax = plt.subplots(figsize=(12, 8))
bars = ax.bar(a.index, a, facecolor='red', edgecolor='red')
结果
我尝试在很多地方搜索这个问题,但找不到合适的工具。
我有一个简单的时间序列数据,
print(anom)
0 0
1 0
2 0
3 0
4 0
..
52777 1
52778 1
52779 0
52780 1
对于 = 1 且跨越(例如 1000 个时间实例)的任何数据序列。我想将它们标记为异常(正确)。否则他们应该被忽略(为假)。
如何使用 pandas 或 numpy 实现此目的?
我也想绘制那些异常,例如红色,我们如何实现?
如何将这些异常(值 = 1,范围为大约 1000 个时间实例)标记为红色?
不完全清楚您期望的输出。 然而,让我们考虑以下类似于您的数据集:
s = pd.Series(np.random.choice([0,1], size=100, p=[0.7, 0.3]), name='anom')
0 1
1 0
2 0
3 0
4 0
..
95 0
96 1
97 1
98 0
99 1
Name: anom, Length: 100, dtype: int64
看起来像:
根据连续值过滤
首先我们计算1s的长度
length = s.groupby(((s-s.shift().fillna(0)).eq(1).cumsum()*s)).transform(len)*s
这通过识别延伸的第一个元素来工作 (s-s.shift().fillna(0)).eq(1)
(一个元素和先例之间的差异仅在 1 前面有 0 的情况下为 1,请参见下图 #2)。然后它使递增的组(图#3)对每段 1 和连续的 0 段进行分组。通过乘以 s
,只有 1 保留在组中(图 #4)。现在我们可以对每个拉伸的数据进行分组并计算每个数据的长度(图 #5)。 0 将全部属于一组,所以最后,我们通过再次乘以 s
(图 #6)来删除零。
这是连续步骤的直观表示,其中 (…)
表示每个图中的前一步:
s_valid = s.loc[length<10]
s_anom = s.drop(s_valid.index)
ax = s_valid.plot(marker='o', ls='')
s_anom.plot(marker='o', ls='', ax=ax, color='r')
ax = s.plot()
s_anom.plot(marker='o', ls='', ax=ax, color='r')
另一个以7为阈值的例子:
原回答
您可以轻松转换为 bool
以获得异常值
>>> s.astype(bool)
0 True
1 False
2 False
3 False
4 False
...
95 False
96 True
97 True
98 False
99 True
Name: anom, Length: 100, dtype: bool
关于剧情,看你的期待你可以做什么:
s_valid = s.loc[~s.astype(bool)]
s_anom = s.loc[s.astype(bool)]
ax = s_valid.plot(marker='o', ls='')
s_anom.plot(marker='o', ls='', ax=ax, color='r')
输出:
s_anom = s.loc[s.astype(bool)]
ax = s.plot()
s_anom.plot(marker='o', ls='', ax=ax, color='r')
设置
np.random.seed(1)
anom = pd.Series(np.random.choice([0, 1], p=[0.2, 0.8], size=10000))
print(anom)
0 1
1 1
2 0
3 1
4 0
..
9995 1
9996 1
9997 0
9998 0
9999 1
Length: 10000, dtype: int64
解决方案
检测异常
m = anom == 1
c = anom[m].groupby((~m).cumsum()).transform('count')
a = c[c > 25].clip(upper=1) # Detection threshold=25
绘制检测到的异常
fig, ax = plt.subplots(figsize=(12, 8))
bars = ax.bar(a.index, a, facecolor='red', edgecolor='red')