#python-3.x #pandas #logic
#python-3.x #pandas #Логические
Вопрос:
У меня есть фрейм данных, содержащий столбцы, выглядящие следующим образом (имеющие 1400 уникальных contextID
записей и 28 разных IndicatorID
записей):
ContextID IndicatorID threshold_values AlarmLevel actual_values
7289972 204511 -6.10904 -1 0
7289972 204511 -12.1848 -2 0
7289972 204511 -18.2606 -3 0
7289972 204511 18.19404 1 0
7289972 204511 24.2698 2 0
7289972 204511 30.34557 3 0
7289972 204512 89.94568 1 64.114
7289972 204512 104.2932 2 64.114
7289972 204512 118.6407 3 64.114
7289972 204512 32.55574 -1 64.114
7289972 204512 18.20825 -2 64.114
7289972 204512 3.860765 -3 64.114
7289998 204511 -6.10904 -1 1
7289998 204511 -12.1848 -2 1
7289998 204511 -18.2606 -3 1
7289998 204511 18.19404 1 1
7289998 204511 24.2698 2 1
7289998 204511 30.34557 3 1
7289998 204512 89.94568 1 64.111
7289998 204512 104.2932 2 64.111
7289998 204512 118.6407 3 64.111
7289998 204512 32.55574 -1 64.111
7289998 204512 18.20825 -2 64.111
7289998 204512 3.860765 -3 64.111
actual_values
Столбец — это реальное значение, считываемое датчиком машины. threshold_values
Столбцы содержат различные пороговые значения, определенные для различных индикаторов (в IndicatorID
столбце), в зависимости от которых будет подан сигнал тревоги, если значение превысит определенный предел.
Пример: Если значение в actual_values
лежит между threshold_values
значениями, определенными для уровня тревоги -1 и 1, продукт не является дефектным. Но, если значение находится между -1 и -2, должен быть подан сигнал тревоги, равный -1 (поскольку оно превысило порог, определенный для -1), а если значение находится между 1 и 2, должен быть подан сигнал тревоги, равный 1, и так далее. В конце концов, для ContextID
должен быть присвоен самый большой уровень тревоги, то есть, если один индикатор поднял тревогу 1, а второй индикатор поднял тревогу -2, уровень тревоги -2 должен считаться большим и присваиваться ему в качестве окончательного сигнала ContextID
(предпочтительно в новом столбце).
Я хотел получить некоторую помощь в реализации этой концепции. Я хотел бы знать, можно ли закодировать такую реализацию.
Я пытаюсь реализовать это, используя 2 разных for
цикла, один для всех ContextID
s и другой для IndicatorID
s, но почему-то мне не удается придумать логику, которая может решить эту задачу.
Я был бы благодарен за помощь и указания.
Спасибо
Редактировать 1:
Пример:
ContextID IndicatorID threshold_values AlarmLevel actual_values thresh_high alarm_high insideThresh
7291899 204515 0.708226 -3 0.949486 0.742542 -2 FALSE
7291899 204515 0.742542 -2 0.949486 0.76 -1 FALSE
7291899 204515 0.76 -1 0.949486 0.914122 1 FALSE
7291899 204515 0.914122 1 0.949486 0.948438 2 FALSE
7291899 204515 0.948438 2 0.949486 0.982754 3 TRUE
7291899 204515 0.982754 3 0.949486 610.9839 -3 FALSE
thresh_value
Значение 610.9839
принадлежит другому IndicatorID
(204516), но это значение используется для вычисления уровня тревоги IndicatorID
(204515)
Ответ №1:
Уверен, что есть способ сделать это. Возможно, способы получше приведенного ниже, но это сработает.
Инициализировать данные:
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) amp; (df.actual_values > df.threshold_values)
Мы сортируем фрейм данных, а затем создаем thresh_high
и alarm_high
, которые являются сдвинутыми версиями threshold_values
и AlarmLevel
Затем мы создаем столбец, который просто показывает, находится ли фактическое значение между пороговыми значениями.
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, в противном случае увеличьте минимальный.
Комментарии:
1. Конечно, изменение порога и значения уровня тревоги работает. Интересно, почему я не подумал об этом простом решении. Спасибо, Мэтт, что помог мне 🙂
2. Привет, @Matt, у меня был небольшой запрос. Не могли бы вы объяснить, что вы имеете в виду, когда говорите, если минимум аварийного уровня, с которого он был нарушен, отрицательный, увеличьте уровень на 1, в противном случае возьмите минимум. ? Спасибо
3. Да — таким образом, то, как я это сделал, показало бы вам пороговую полосу, в которую оно попало. Если оно упало на -2, -1, вы хотите назвать его -1, потому что оно прошло -1, если оно упало на 1,2, вы хотите назвать его 1. В столбце alarmlevel если вы возьмете минимальное значение первой части этого значения (-2 из-2, -1 или 1 из 1,2), вы получите правильный alarm # для 1,2, но у -2, -1 должен быть уровень тревоги -1. Итак, если оно отрицательное, то есть оно захватывает значение -2, добавьте к нему единицу, чтобы получить сигнал тревоги -1
4. да, верно, я на самом деле печатал ответ для этого.
5. Я обновил свой код, чтобы в нем были сдвиги groupby, чтобы он не переходил в другую группу. сдвиги groupby будут сдвигаться внутри каждой указанной группы, и тогда в конце она будет иметь нулевое значение, поскольку сдвигать дальше 3 нечего. Итак, мы заполняем это высокое пороговое значение бесконечностью из numpy и называем это пороговое значение 4.