Посчитать уникальные текстовые значения в столбце нарастающим итогом (по месяцам)

Есть таблица:

-- для теста

df = pd.DataFrame(({'date': ['2021-10-02', '2021-10-02', '2021-11-02',  '2021-12-02', '2022-01-02'],
                 'user_id': ['user_1', 'user_2', 'user_9', 'user_5', 'user_1'],
                    'year': [2021, 2021, 2021, 2021, 2022],
                   'month': [10, 10, 11, 12, 1],
                    'week': [39, 39, 42, 48, 1]}))

df['date'] = pd.to_datetime(df['date'])
     date       user_id     year    month   week
0   2021-10-02  user_1      2021    10      39
1   2021-10-02  user_2      2021    10      39
2   2021-11-02  user_9      2021    11      42
3   2021-12-02  user_5      2021    12      48
4   2022-01-02  user_1      2022    01      01

Мне нужно посчитать уникальное количество юзеров нарастающим итогом по месяцам (неделям):

year    month   cum_number_users
2021    10      2
2021    11      3
2021    12      4
2022    01      4

Я пробовала код со всевозможными вариациями:

table = df.groupby(['year', 'month'], as_index=False).agg({'user_id': 'nunique'})

Но так выводится уникальное количество юзеров по каждому месяцу. Метод cumsum() работает только с числами.

Можно также вручную посчитать нарастающий итог через query:

df.query("10 <= month <= 11").agg({'user_id': 'nunique'}) # за октябрь и ноябрь

или

df.query("10 <= month <= 12").agg({'user_id': 'nunique'}) # за октябрь, ноябрь и декабрь

Но мне нужно не вручную. Вот никак не соображу :(


Ответы (1 шт):

Автор решения: strawdog

Когда вы применяете группировку, аггрегирующая функция применяется только к группе.

Я бы рекомендовал сделать так:

  • сначала проверяете, является ли user_id дубликатом,если да, помечаете его и инвертируете отметку
  • делаете свою группировку с суммированием положительных отметок (не дубликаты) в колонке user_id
  • считаете кумулятивную сумму по колонке user_id
df["user_id"] = (~df["user_id"].duplicated())
table = df.groupby(['year', 'month'], as_index=False)["user_id"].sum()
table["user_id"] = table["user_id"].cumsum()

table:

   year  month  user_id
0  2021     10        2
1  2021     11        3
2  2021     12        4
3  2022      1        4
→ Ссылка