Конечно, есть способ сделать это.Возможно, лучшие способы, чем приведенные ниже, но это будет работать.
Инициализация данных:
import pandas as pd
import numpy as np
thresh = [-6.10904,
-12.1848,
-18.2606,
18.19404,
24.2698,
30.34557,
89.94568,
104.2932,
118.6407,
32.55574,
18.20825,
3.860765]
df = pd.DataFrame({'ContextID':[1]*12+[2]*12,
'IndicatorID':[5]*6+[6]*6+[7]*6+[8]*6,
'threshold_values':thresh*2,
'AlarmLevel':[-1, -2, -3, 1, 2, 3, 3, 2, 1, -1, -2, -3]*2,
'actual_values':[-17]*6+[64.114]*6+[26]*6+[64.111]*6})
Я упростил ContextID и IndicatorID, я также добавил некоторые ложные значения для actual_values, потому что вашивсе в пределах допустимого.Мы хотим увидеть, что происходит, когда они выходят за пределы надлежащего диапазона.
df = df.sort_values(['ContextID', 'IndicatorID', 'AlarmLevel'])
df['thresh_high'] = df.groupby(['ContextID', 'IndicatorID'])['threshold_values'].shift(-1)
df['alarm_high'] = df.groupby(['ContextID', 'IndicatorID'])['AlarmLevel'].shift(-1)
df['thresh_high'] = df.thresh_high.fillna(np.Inf)
df['alarm_high'] = df.alarm_high.fillna(4)
df['insideThresh'] = (df.actual_values < df.thresh_high) & (df.actual_values > df.threshold_values)
Мы сортируем информационный кадр, а затем создаем thresh_high
и alarm_high
, которые являются сдвинутыми версиями threshold_values
и * 1012.*
Затем мы создаем столбец, который просто показывает, находится ли фактическое значение между пороговыми значениями.
alarms = df.loc[df.insideThresh == True] \
.groupby(['ContextID', 'IndicatorID', 'insideThresh'])['AlarmLevel'] \
.apply(lambda x: x.min()+1 if x.min() < 0 else x.min()
)
Наконец, мы фильтруем кадр данных только по временам, когда actual_values
сидел в порогах, а затем группируем по ContextId, IndicatorID и insideThresh (это последнеене очень нужно).Мы берем уровень тревоги и применяем пользовательскую функцию, сообщающую ему, что если минимум уровня тревоги, с которого он был взломан, является отрицательным, поднимем уровень до 1, в противном случае возьмем минимум.