我有一个数据框,有两列A和B,A和B的值可以是0.0或1.0(二进制状态)。
信号大部分时间都是0.0,偶尔有1.00。 我想检测每个事件,其中A和B都是1.00,并且是重叠的(内部连接)。
下面是一个示例代码。
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
%matplotlib inline
np.random.seed(101)
data = np.zeros((1200,2),dtype=float)
df = pd.DataFrame(data=data,
index=pd.date_range('2020-05-19',
freq='50ms', periods=1200),
columns=['A','B'])
#event1
df.loc[pd.to_datetime('2020-05-19 00:00:01.000'):pd.to_datetime('2020-05-19 00:00:02.500'),'A'] =1.00
df.loc[pd.to_datetime('2020-05-19 00:00:01.500'):pd.to_datetime('2020-05-19 00:00:03.000'),'B'] =1.00
#event2
df.loc[pd.to_datetime('2020-05-19 00:00:12.000'):pd.to_datetime('2020-05-19 00:00:15.000'),'A'] =1.00
df.loc[pd.to_datetime('2020-05-19 00:00:13.000'):pd.to_datetime('2020-05-19 00:00:14.500'),'B'] =1.00
#event3
df.loc[pd.to_datetime('2020-05-19 00:00:40.000'):pd.to_datetime('2020-05-19 00:00:43.000'),'A'] =1.00
df.loc[pd.to_datetime('2020-05-19 00:00:42.000'):pd.to_datetime('2020-05-19 00:00:46.000'),'B'] =1.00
A和B的线段图,以显示重叠的情况。 请注意,我将A移动了0.01以使所有的线都可见。
def plot_Class_AB():
fig, ax = plt.subplots(nrows=1,ncols=1,figsize=(15,4))
ax.set_title("Checking overlaps of A and B")
ax.plot(df['A'].dropna()+0.01,label="A",color='red')
ax.plot(df['B'].dropna(),label="B",color='blue')
ax.set_ylabel("Class")
ax.legend()
我可以得到第一个事件的开始时间和最后一个事件的结束时间,如下所示。
events_startTime = df[(df['A'] == 1.00) & (df['B'] == 1.00)].head(1).index
events_endTime = df[(df['A'] == 1.00) & (df['B'] == 1.00)].tail(1).index
print('events_startTime:',events_startTime)
print('events_endTime: ',events_endTime)
然而,我对单个事件的重叠时间感兴趣。 我期望的输出是类似于这样的。
event1_startTime = 2020-05-19 00:00:01.500
event1_endTime: = 2020-05-19 00:00:02.500
event2_startTime = 2020-05-19 00:00:13.000
event2_endTime: = 2020-05-19 00:00:14.500
event3_startTime = 2020-05-19 00:00:42.000
event3_endTime: = 2020-05-19 00:00:43.000
你能不能建议一下如何解决这个问题?
将两个信号相乘,找到乘积非零的指数呢?
import numpy as np
a = df['A'].dropna().values
b = df['B'].dropna().values
events_idxs = np.where(a*b > 0.5)[0]
(我放了一个0.5的阈值,因为看起来你的信号在事件外不完全是0)
我使用了JacoSolari的建议,它返回一个A == B ==1.00的所有指数的列表。 对于上面的例子,它返回以下数组。
array([ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852,
853, 854, 855, 856, 857, 858, 859, 860], dtype=int64)
最后我添加了下面的函数 从上面的数组中提取出所有事件的开始和停止指数列表 下面的代码。
def find_start_stop_indexes(df):
a = df['A'].dropna().values
b = df['B'].dropna().values
events_idxs = np.where(a*b > 0.5)[0]
if len(events_idxs) > 0:
# initiate a list to store first,last index of each event
first_last = [events_idxs[0]]
i = 1
while i < len(events_idxs):
if (events_idxs[i] - events_idxs[i-1]) < 2:
i = i+1
if i == len(events_idxs):
first_last.append(events_idxs[i-1])
else:
first_last.append(events_idxs[i-1])
first_last.append(events_idxs[i])
i = i +1
if i == len(events_idxs):
first_last.append(events_idxs[i-1])
return(first_last)
else:
return([])
上面例子的函数输出是。
[30, 50, 260, 290, 840, 860]
不知道是否有更简单的解决方案,但它的工作原理是: