Скользящие операции над объектом DataFrameGroupby - PullRequest
4 голосов
/ 30 октября 2019

У меня есть фрейм данных pandas, который я хочу выполнить одну и ту же операцию прокрутки для разных групп данных. Рассмотрим следующую df (см. Нижнюю часть вопроса о коде для построения) с четырьмя столбцами:

id      date       category   target
1    2017-01-01      'a'        0
1    2017-01-01      'b'        0
1    2017-01-21      'a'        1
1    2017-01-21      'b'        1
1    2017-10-01      'a'        0
1    2017-10-01      'b'        0
2    2017-01-01      'a'        1    
2    2017-01-01      'b'        1    
2    2017-01-21      'a'        0
2    2017-01-21      'b'        0
2    2017-10-01      'a'        0
2    2017-10-01      'b'        0

Мне нужна операция, которая вычисляет логическое значение для каждой пары уникальных идентификаторов-дат, указывающей, является лицелевой столбец 1 в течение 6 месяцев с указанной даты. Поэтому для предоставленного df я бы ожидал результат, который выглядит следующим образом:

id      date       one_within_6m
1    2017-01-01       True
1    2017-01-21       False
1    2017-10-01       False
2    2017-01-01       False
2    2017-01-21       False
2    2017-10-01       False

Я могу сделать это с помощью цикла for, повторяющегося по строкам и просматривающего 6 месяцев вперед для каждого посещения, но он слишком медленныйиз-за большого размера моего набора данных.

Итак, мне было интересно, можно ли сгруппировать идентификатор по дате и выполнить скользящую операцию с временным окном, чтобы посмотреть на это? Например:

df_grouped = df.groupby(['id', 'date'])

# … do something to set date as index

# ... define some custom function

df_grouped.rolling('6m', on='target').apply(some_custom_function)

Некоторые примечания:

  • В 6-месячном окне может быть несколько «1», это должно рассматриваться как «Истина» для текущегодата.

  • В моей голове some_custom_function проверит, больше ли сумма цели в течение следующих 6 месяцев (исключая текущую дату) больше 1.

Вспомогательный код:

Чтобы создать экземпляр DataFrame, используемый в этом вопросе:

ids = np.concatenate([np.ones(6), np.ones(6)+1])
dates = ['2017-01-01','2017-01-01','2017-01-21','2017-01-21',
         '2017-10-01','2017-10-01','2017-01-01','2017-01-01',
         '2017-01-21','2017-01-21','2017-10-01','2017-10-01']
categories = ['a','b','a','b','a','b','a','b','a','b','a','b']
targets = [0,0,1,1,0,0,1,1,0,0,0,0]

df = pd.DataFrame({'id':ids,
                   'date':dates,
                   'category':categories,
                   'target':targets})

df['date'] = pd.to_datetime(df['date'])

1 Ответ

0 голосов
/ 31 октября 2019

Я нашел работоспособное решение, но оно работает, только если для каждого идентификатора каждая дата уникальна. Это касается моих данных с некоторой дополнительной обработкой:

new_df = df.groupby(['id','date']).mean().reset_index()

, которая возвращает:

    id      date      target
0   1.0   2017-01-01    0
1   1.0   2017-01-21    1
2   1.0   2017-10-01    0
3   2.0   2017-01-01    1
4   2.0   2017-01-21    0
5   2.0   2017-10-01    0

Затем я могу использовать метод прокатки для объекта groupby, чтобы получить желаемый результат:

df = new_df.set_index('date')

df.iloc[::-1].groupby('id')['target'].rolling(window='180D', 
    centre=False).apply(lambda x : x[:-1].sum())

Здесь есть два трюка:

  1. Я изменяю порядок дат (.iloc[::-1]), чтобы посмотреть в будущее;это было предложено в других SO вопросах .

  2. Я удаляю последнюю запись суммы, чтобы удалить «текущую» дату из суммы, поэтому она только выглядитвперед.

Второй «хак» означает, что он работает только тогда, когда для данного идентификатора нет повторов дат.

Мне было бы интересно найти более надежное решение (например, когда для идентификатора повторяются даты).

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