Как проверить наличие зависших данных во фрейме данных pandas - PullRequest
3 голосов
/ 04 августа 2020

Этот вопрос был отредактирован для ясности на основе комментариев

Цель: Отметить переменное количество застрявших / повторяющихся значений в столбцах фрейма данных на основе группы.

Желаемое решение: желаемое решение должно соответствовать следующим критериям:

  1. Важны скорость и краткость
  2. Решение должно принимать в качестве входной переменной количество пороговых значений для отметки о зависании / повторении значения для каждой зоны. Например: {"Zone1": 4, "Zone2": 2} -> указывая, что в Zone1 должны быть 4 последовательных повторяющихся значения для logi c, чтобы помечать, а в Zone2, по крайней мере, 2 или более повторения значения должны запускать флаг
  3. По возможности добавьте комментарии, чтобы упростить понимание
  4. Предпочтительно использовать Pandas и / или Numpy
  5. Время принятия решения тестовый фрейм данных с 87600 значениями (сгенерируйте фрейм данных с 87,600 значениями по времени)

Входные данные / формулировка проблемы:

import pandas as pd
import numpy as np
from random import randint

# Generate some random data
ts_index = pd.date_range("1/1/2019", periods=24, freq="1H")
v1 = [randint(1, 100) for i in range(24)]
v2 = [2] * 24
v3 = [2, 2, 2, 2, 4, 4, 0, 2, 2, 1, 9, 2, 4, 1, 2, 2, 0, 2, 1, 8, 1, 7, 3, 5]
test_df = pd.DataFrame({"v1": v1, "v2": v2, "v3": v3}, index=ts_index)
print(test_df) 

Теперь пример вывода должен выглядеть следующим образом .

Ответы [ 3 ]

2 голосов
/ 06 августа 2020

Сначала мы получаем абсолютную разницу для столбцов, а затем cumsum().

Предполагая, что если значение не изменится, совокупная сумма различий останется постоянной, мы можем использовать pandas .shift().

Мы должны сравнить каждое значение в зоне 1 с 4 строками выше. Аналогично зоне 2.

import pandas as pd
import numpy as np
import datetime


# Generate some random data
ts_index = pd.date_range("1/1/2019", periods=24, freq="1H")
v1 = [random.randint(1, 100) for i in range(24)]
v2 = [2] * 24
v3 = [2, 2, 2, 2, 4, 4, 0, 2, 2, 1, 9, 2, 4, 1, 2, 2, 0, 2, 1, 8, 1, 7, 3, 5]
df = pd.DataFrame({"v1": v1, "v2": v2, "v3": v3}, index=ts_index)
df1 = df.diff().fillna(0)

# Add hour and time of day to create flag
df['Hour'] = df.index.hour
df['Flag'] = np.where((df['Hour'] <= 8) | (df['Hour'] >= 18), 'Zone1', 'Zone2')
df1['Flag'] = np.where((df['Hour'] <= 8) | (df['Hour'] >= 18), 'Zone1', 'Zone2')

df1[["v1", "v2","v3"]] = np.abs(df1[["v1", "v2","v3"]])
df1[["v1", "v2","v3"]] = df1.groupby("Flag")["v1", "v2","v3"].cumsum()
columns = ["v1","v2","v3"]

z1_p = 3
z2_p = 1

for col in columns:
    df["Flag_"+col] = (np.array(df1[col].shift(z1_p) == df1[col]) & np.array(df1["Flag"] == "Zone1")) | \
(np.array(df1[col].shift(z2_p) == df1[col]) & np.array(df1["Flag"] == "Zone2"))
    for element in df[df["Flag_"+col] == True].index:
        if df.loc[element]["Flag"] == "Zone1":
            for i in range(1,4):
                a = a.append(pd.Index([element - datetime.timedelta(hours=i)]))
        else:
            a = a.append(pd.Index([element - datetime.timedelta(hours=1)]))
    df.at[a,"Flag_"+col] = True

df

Вывод:

                    v1  v2  v3  Hour    Flag    Flag_v1 Flag_v2 Flag_v3
2019-01-01 00:00:00 31  2   2   0       Zone1   False   True    True
2019-01-01 01:00:00 93  2   2   1       Zone1   False   True    True
2019-01-01 02:00:00 48  2   2   2       Zone1   False   True    True
2019-01-01 03:00:00 56  2   2   3       Zone1   False   True    True
2019-01-01 04:00:00 9   2   4   4       Zone1   False   True    False
2019-01-01 05:00:00 75  2   4   5       Zone1   False   True    False
2019-01-01 06:00:00 29  2   0   6       Zone1   False   True    False
2019-01-01 07:00:00 61  2   2   7       Zone1   False   True    False
2019-01-01 08:00:00 64  2   2   8       Zone1   False   True    False
2019-01-01 09:00:00 82  2   1   9       Zone2   False   True    False
2019-01-01 10:00:00 13  2   9   10      Zone2   False   True    False
2019-01-01 11:00:00 97  2   2   11      Zone2   False   True    False
2019-01-01 12:00:00 74  2   4   12      Zone2   False   True    False
2019-01-01 13:00:00 26  2   1   13      Zone2   False   True    False
2019-01-01 14:00:00 77  2   2   14      Zone2   False   True    True
2019-01-01 15:00:00 39  2   2   15      Zone2   False   True    True
2019-01-01 16:00:00 79  2   0   16      Zone2   False   True    False
2019-01-01 17:00:00 35  2   2   17      Zone2   False   True    False
2019-01-01 18:00:00 65  2   1   18      Zone1   False   True    False
2019-01-01 19:00:00 74  2   8   19      Zone1   False   True    False
2019-01-01 20:00:00 72  2   1   20      Zone1   False   True    False
2019-01-01 21:00:00 23  2   7   21      Zone1   False   True    False
2019-01-01 22:00:00 28  2   3   22      Zone1   False   True    False
2019-01-01 23:00:00 59  2   5   23      Zone1   False   True    False
1 голос
/ 12 августа 2020

Сработает ли это

import pandas as pd, numpy as np
from random import randint


def processGroup(zone, ZoneGroup):
    ZoneGroup.sort_index(inplace=True)
    repeatation = repeatations[zone]
    
    repeat_counts = [0]*len(cols)
    previous_value = [None]*len(cols)
    
    for i, record in ZoneGroup.iterrows():
        for j, c in enumerate(cols):
            if previous_value[j] == record[c]:
                repeat_counts[j] += 1
            else:
                repeat_counts[j] = 0
                
            if repeat_counts[j] >= repeatation:
                test_df.at[i, c+'RepeatFlag']=True
                
            previous_value[j] = record[c]

TotalRecords = 87600 #24*10
ts_index = pd.date_range("1/1/2019", periods=TotalRecords, freq="1H")
v1 = [randint(1, 2) for i in range(TotalRecords)]
v2 = [randint(1, 3) for i in range(TotalRecords)]
v3 = [randint(1, 5) for i in range(TotalRecords)]

test_df = pd.DataFrame({"v1": v1, "v2": v2, "v3": v3}, index=ts_index)
test_df['Zone'] = pd.Series(test_df.index).apply(lambda t: 'Zone'+ str(int((t.hour+t.minute/60+t.second/3600)// 8 + 1))).to_list()

# You can tweak repaet values here
repeatations = {'Zone1':4, 'Zone2':3, 'Zone3':2}
cols = test_df.columns[:-1]

#test_df[cols+'RepeatFlag']=False
for c in cols+'RepeatFlag':
    test_df[c]=False

for i, g in test_df.groupby('Zone'):
    processGroup(i, g)
    
print(test_df)
repeat_df = test_df[test_df.v1RepeatFlag | test_df.v2RepeatFlag | test_df.v3RepeatFlag]
print(repeat_df)
0 голосов
/ 13 августа 2020

Я проверил код. Посмотрите на скриншот Блокнота. Попробуйте хоть раз отредактировать код. снимок экрана ноутбука

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...