Увеличить условно pandas

#python #pandas #logging #time

#python #pandas #ведение журнала #время

Вопрос:

У меня есть фрейм данных pandas со следующими условиями:

  • У каждой записи есть группа, дата и индикатор, если произошло событие
  • Ежедневные записи для каждой группы (не обязательно одинаковые временные рамки для каждой группы)
  • Отсортировано по группе, дате

Мне нужно реализовать столбец счетчика, который начинается с первого события для группы и увеличивается только тогда, когда (счетчик < 3 * numEvents).

  • если счетчик = 1 и numevents = 1 -> счетчик = 1
  • если счетчик = 3 и numevents = 1 -> ничего не делать

Счетчик может увеличиваться только в 3 раза без возникновения другого события. если он застрял на значении, кратном 3 для нескольких записей, то после того, как произойдет другое событие, позволяющее увеличить его, ему все равно нужно увеличить только на 1.

Пример фрейма данных

 group        date  event  numEvents         Counter
    A  2020-08-05      0          0               0
    A  2020-08-06      1          1               1
    A  2020-08-07      0          1               2
    A  2020-08-08      0          1               3
    A  2020-08-09      0          1               3
    A  2020-08-10      0          1               3
    A  2020-08-11      1          2               4
    A  2020-08-12      0          2               5
    A  2020-08-13      0          2               6
    A  2020-08-14      0          2               6
    B  2020-08-05      1          1               1
    B  2020-08-06      1          2               2
    B  2020-08-07      0          2               3
    B  2020-08-08      0          2               4
    B  2020-08-09      0          2               5
    B  2020-08-10      0          2               6
    B  2020-08-11      0          2               6
    B  2020-08-12      0          2               6
    B  2020-08-13      0          2               0
    B  2020-08-14      0          2               0
  

Код для генерации примера фрейма данных

 import pandas as pd
import datetime as datetime
base = datetime.datetime.today()
numdays = 10
date_list = [(base - datetime.timedelta(days=x)).date() for x in range(numdays)]

df = pd.DataFrame(columns=['group', 'date'])
for group in ['A', 'B']:
    tmp = pd.DataFrame({'group': group, 'date': date_list})
    df = df.append(tmp)
df = df.sort_values(['group', 'date'])

groupA_events = [0, 1, 0, 0, 0, 0, 1, 0, 0, 0]
groupB_events = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
events = groupA_events   groupB_events
df['event'] = events
df['numEvents'] = df.groupby('group')['event'].cumsum()

df['Counter'] = [0, 1, 2, 3, 3, 3, 4, 5, 6, 6, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6]
  

Основная проблема здесь в том, что я не могу понять, как условно увеличить столбец на основе самого себя. Я пытался использовать .cumsum(), но не нашел способа использовать его, который работает для этого сценария.

Спасибо

Комментарии:

1. Привет, Ричи, спасибо за информацию. Я не совсем уверен, что вы имеете в виду, но, пожалуйста, посмотрите только что внесенную мной правку.

Ответ №1:

Я не совсем понимаю логику, необходимую для получения ожидаемых результатов, но вот пара методов, которые могут быть полезны.

  • True и False представлены как 1 и 0.
  • Вы можете использовать это с умножением и кумулятивными суммами.
  • Кроме того, .shift() можно перенести значение из более ранней (или более поздней) строки в текущую строку.
 df = pd.DataFrame(
    {'x': [10, 20, 30, 40, 50, 60],
     'flag_1': [True] * 3   [False] * 3, 'flag_2': [True, False] * 3})

# get previous x and current x on same row
df['prev_x'] = df['x'].shift(1)  

# multiply by boolean
df['y'] = df['x'] * df['flag_1']

# cumulative sum of boolean (conditional increment)
df['z'] = df['flag_2'].cumsum()

print(df)

    x  flag_1  flag_2  prev_x   y  z
0  10    True    True     NaN  10  1
1  20    True   False    10.0  20  1
2  30    True    True    20.0  30  2
3  40   False   False    30.0   0  2
4  50   False    True    40.0   0  3
5  60   False   False    50.0   0  3
  

Наконец, сравните .transform(min) с .min() с groupby (использование transform возвращает то же количество строк, что и исходный фрейм данных).

Комментарии:

1. Привет, спасибо за этот совет! Одна из проблем, с которой я сталкиваюсь, заключается в том, что условие, при котором увеличивается счетчик, основано на самом счетчике. Поэтому при использовании shift это не отражает должным образом условие (по крайней мере, так, как я пытался). Я внес некоторую ясность в свой вопрос, не могли бы вы, пожалуйста, взглянуть на него еще раз? Спасибо!

2. Спасибо! Это оказало мне огромную помощь в решении проблемы.