#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. Спасибо! Это оказало мне огромную помощь в решении проблемы.