按条件检索时间行。在一天之内获得成功的代码

时间:2019-12-03 13:13:38

标签: python pandas

我有事件的df。基本示例可以通过以下代码重现:

data = [['2019-01-11 16:27:39', 'AC', '2019-01-11 16:54:53'], ['2019-01-11 16:27:39', 'DC', '2019-01-11 16:54:53'], ['2019-01-11 17:03:42', 'AC', '2019-01-14 10:00:25'], ['2019-01-11 17:03:42', 'DC', '2019-01-14 09:58:39'], ['2019-01-11 17:03:42', 'Battery', '2019-01-14 10:00:48'], ['2019-01-11 17:03:48', 'Cell', '2019-01-12 17:26:48'], ['2019-01-14 10:00:36', 'DC', '2019-01-14 10:33:42'], ['2019-01-14 10:32:42', 'AC', '2019-01-14 10:45:27']]  

df = pd.DataFrame(data, columns = ['Start', 'Alarm', 'End'])  
df['Start'] = pd.to_datetime(df['Start'], format='%d.%m.%Y %H:%M:%S')
df['End'] = pd.to_datetime(df['End'], format='%d.%m.%Y %H:%M:%S')

我的总体目标是监视发生的警报。诸如DC /电池/电池之类的警报通常与AC同时发生或在以后发生。

因此,我想添加“ AC Start”列,其中将填充与其他警报关联的相应AC警报的时间戳,然后计算AC警报发生与其他警报发生之间的时间差。

这是我要执行的代码:

ac_mask = df.Alarm.eq('AC')
df['AC Start'] = df.Start.where(ac_mask).ffill().mask(ac_mask)
df['AC End'] = df.End.where(ac_mask).ffill().mask(ac_mask)
df['Time between events'] = (df['Start'] - df['AC Start']).dt.total_seconds()/60  

效果很好,直到我遇到警报发生的时间早于正确的交流电且关联错误时。 (参见照片)enter image description here

所以我的问题是如何调整代码使其仅在一天之内工作以查找匹配项?

2 个答案:

答案 0 :(得分:1)

只需对ac_mask进行一些其他过滤,并稍微改变创建AC StartAC End的方式:

# 1. Change condition to ne('AC') instead of eq('AC')
# 2. Add conditional that Start must be on the same date, backfilled NA values

ac_mask = df.Alarm.ne('AC') & df.Start.dt.date.eq(df.Start.shift().bfill().dt.date)

让我们看看面具的样子:

>>> df['ac_mask'] = ac_mask
>>> df[['Start', 'Alarm', 'ac_mask']]
                Start    Alarm  ac_mask
0 2019-01-11 16:27:39       AC    False
1 2019-01-11 16:27:39       DC     True
2 2019-01-11 17:03:42       AC    False
3 2019-01-11 17:03:42       DC     True
4 2019-01-11 17:03:42  Battery     True
5 2019-01-11 17:03:48     Cell     True
6 2019-01-14 10:00:36       DC    False   # <-- Alarm on different date is no longer captured
7 2019-01-14 10:32:42       AC    False

现在还可以调整遮罩AC StartAC End的方式:

df['AC Start'] = df.Start.mask(ac_mask).ffill().where(ac_mask)
df['AC End'] = df.End.mask(ac_mask).ffill().where(ac_mask)

其余内容相同:

df['Time between events'] = (df['Start'] - df['AC Start']).dt.total_seconds()/60  

>>> df
                Start    Alarm                 End            AC Start              AC End  Time between events  
0 2019-01-11 16:27:39       AC 2019-01-11 16:54:53                 NaT                 NaT                  NaN     
1 2019-01-11 16:27:39       DC 2019-01-11 16:54:53 2019-01-11 16:27:39 2019-01-11 16:54:53                  0.0  
2 2019-01-11 17:03:42       AC 2019-01-14 10:00:25                 NaT                 NaT                  NaN  
3 2019-01-11 17:03:42       DC 2019-01-14 09:58:39 2019-01-11 17:03:42 2019-01-14 10:00:25                  0.0  
4 2019-01-11 17:03:42  Battery 2019-01-14 10:00:48 2019-01-11 17:03:42 2019-01-14 10:00:25                  0.0  
5 2019-01-11 17:03:48     Cell 2019-01-12 17:26:48 2019-01-11 17:03:42 2019-01-14 10:00:25                  6.0  
6 2019-01-14 10:00:36       DC 2019-01-14 10:33:42                 NaT                 NaT                  NaN  
7 2019-01-14 10:32:42       AC 2019-01-14 10:45:27                 NaT                 NaT                  NaN  

答案 1 :(得分:0)

解决了循环问题,但请确保必须有一种更优雅的方法。因此问题仍然悬而未决。

as_start = tr[tr['Alarm']=='AC']['Start'].dt.date.unique()  

dt = pd.DataFrame([])
for date in as_start:
    tt = tr[tr['Start'].dt.date==date]
    ac_mask = tt.Alarm.eq('AC')
    tt['AC Start'] = tt.Start.where(ac_mask).ffill().mask(ac_mask) 
    tt['AC End'] = tt.End.where(ac_mask).ffill().mask(ac_mask)
    tt['Time between events'] = (tt['Start'] - tt['AC Start']).dt.total_seconds()/60
    dt = dt.append(tt)