Pandas - частота подсчета значений за последние x дней - PullRequest
2 голосов
/ 10 марта 2020

Я нахожу некоторые неожиданные результаты. То, что я пытаюсь сделать, - это создать столбец, который просматривает идентификационный номер и дату, и будет подсчитывать, сколько раз этот идентификационный номер появляется за последние 7 дней (я также хотел бы сделать этот динамический c для x количество дней, но только с 7 днями).

Итак, с учетом этого кадра данных:

import pandas as pd



df = pd.DataFrame(
        [['A', '2020-02-02 20:31:00'],
        ['A', '2020-02-03 00:52:00'],
        ['A', '2020-02-07 23:45:00'],
        ['A', '2020-02-08 13:19:00'],
        ['A', '2020-02-18 13:16:00'],
        ['A', '2020-02-27 12:16:00'],
        ['A', '2020-02-28 12:16:00'],
        ['B', '2020-02-07 18:57:00'],
        ['B', '2020-02-07 21:50:00'],
        ['B', '2020-02-12 19:03:00'],
        ['C', '2020-02-01 13:50:00'],
        ['C', '2020-02-11 15:50:00'],
        ['C', '2020-02-21 10:50:00']],
        columns = ['ID', 'Date'])

Код для вычисления вхождения за последние 7 дней для каждого экземпляра:

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

delta = 7
df['count_in_last_%s_days' %(delta)] = df.groupby(['ID', pd.Grouper(freq='%sD' %delta, key='Date')]).cumcount()

Выход:

   ID                Date  count_in_last_7_days
0   A 2020-02-02 20:31:00                     0
1   A 2020-02-03 00:52:00                     1
2   A 2020-02-07 23:45:00                     2
3   A 2020-02-08 13:19:00                     0 #<---- This should output 3
4   A 2020-02-18 13:16:00                     0
5   A 2020-02-27 12:16:00                     0
6   A 2020-02-28 12:16:00                     1
7   B 2020-02-07 18:57:00                     0
8   B 2020-02-07 21:50:00                     1
9   B 2020-02-12 19:03:00                     0 #<---- THIS SHOULD OUTPUT 2
10  C 2020-02-01 13:50:00                     0
11  C 2020-02-11 15:50:00                     0
12  C 2020-02-21 10:50:00                     0

Ответы [ 2 ]

3 голосов
/ 10 марта 2020

Вы не хотите использовать Grouper на Date, а rolling окно. Группировщик будет сегментировать кадр данных в отдельных последовательных блоках требуемой длительности. Если вам нужно 7 дней с каждой даты, это задание rolling:

delta = 7
df['count_in_last_%s_days' %(delta)] = df.assign(count=1).groupby(
    ['ID']).apply(lambda x: x.rolling('%sD' %delta, on='Date').sum(
        ))['count'].astype(int) - 1

, которое выдает, как и ожидалось:

   ID                Date  count_in_last_7_days
0   A 2020-02-02 20:31:00                     0
1   A 2020-02-03 00:52:00                     1
2   A 2020-02-07 23:45:00                     2
3   A 2020-02-08 13:19:00                     3
4   A 2020-02-18 13:16:00                     0
5   A 2020-02-27 12:16:00                     0
6   A 2020-02-28 12:16:00                     1
7   B 2020-02-07 18:57:00                     0
8   B 2020-02-07 21:50:00                     1
9   B 2020-02-12 19:03:00                     2
10  C 2020-02-01 13:50:00                     0
11  C 2020-02-11 15:50:00                     0
12  C 2020-02-21 10:50:00                     0
1 голос
/ 10 марта 2020

Похоже, что переход на Date с правильным окном будет делать:

(df.set_index('Date')
   .assign(count_last=1)
   .groupby('ID')
   .rolling(f'{delta}D')
   .sum() - 1
)

Вывод:

                        count_last
ID Date                           
A  2020-02-02 20:31:00         0.0
   2020-02-03 00:52:00         1.0
   2020-02-07 23:45:00         2.0
   2020-02-08 13:19:00         3.0
   2020-02-18 13:16:00         0.0
   2020-02-27 12:16:00         0.0
   2020-02-28 12:16:00         1.0
B  2020-02-07 18:57:00         0.0
   2020-02-07 21:50:00         1.0
   2020-02-12 19:03:00         2.0
C  2020-02-01 13:50:00         0.0
   2020-02-11 15:50:00         0.0
   2020-02-21 10:50:00         0.0
...