Cumsum с группой не работает в пандах - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть фрейм данных, hourly_subset_df, где

hourly_subset_df.columns = ['date', 'metadata.campaignName', 'localSpend.amount', 'daily_cap']

. Он содержит различные рекламные кампании с соответствующими значениями расходов в час дня.

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

Я пытался сделать:

hourly_subset_df['cumsum'] = hourly_subset_df.groupby(['metadata.campaignName', 'date', 'daily_cap'])['localSpend.amount'].cumsum()

и

hourly_subset_df.groupby(['metadata.campaignName', 'date', 'daily_cap'])['localSpend.amount'].transform(pd.Series.cumsum)

на основе другого ответа, который я нашел здесь ( this , это ).

Там результаты, которые я получаю, - это просто копия столбца расходов ('localSpend.amount') вместо совокупной суммы по уникальной группе ['metadata.campaignName', 'date', 'daily_cap'].

Почему это не работает?

РЕДАКТИРОВАТЬ: я создал образец кадра данных в качестве dict здесь (был слишком велик, чтобы вставить здесь).

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

В данном конкретном случае я обнаружил, что самое чистое решение -

hourly_subset_df['cumsum'] = hourly_subset_df\
.groupby(['metadata.campaignName', 'daily_cap'])\
.agg({'localSpend.amount': 'cumsum'})

. Таким образом, совокупная сумма работает для каждой группы названия кампании / даты (часы).Вероятно, требуется, чтобы даты / часы были отсортированы в порядке возрастания, как в данном случае.

Моя проблема заключалась в том, что я включил в группу столбец date, поэтому каждая группа была полностью уникальной (например,@Allollz указал).

Кроме того, он работает, если данные извлекаются ежедневно (как в моем случае).

0 голосов
/ 29 ноября 2018

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

import numpy  as  np
import pandas  as pd 

n_rows = int(1e5)
n_cats = (24, 11, 7)
randcats = lambda ln: np.random.choice(np.arange(ln).astype(int), size=n_rows) 

cols = np.array(['date',
                 'metadata.campaignName', 
                 'localSpend.amount', 
                 'daily_cap'])
groupcols = cols[[0, 1, 3]]

x = np.random.uniform(420.0, 1100.37, size=n_rows)
hrs, camps, caps = map(randcats, n_cats)
df = pd.DataFrame(np.vstack([hrs, camps, x, caps]).T, columns=cols)
df = df.sort_values(by=cols[[1,0,-1]], kind='mergesort')
df['cum_sums'] = df.groupby(groupcols.tolist()).cumsum()
df[groupcols] = df[groupcols].astype(int)
grouped = list(df.groupby(groupcols.tolist()))

Итак, мы настроили данные, которые выглядят как ...

      date  metadata.campaignName  localSpend.amount  daily_cap
396      0                      0             526.14          0
2502     0                      0             777.32          0
2587     0                      0             777.40          0
7198     0                      0             423.22          0

Затем вы можете проверить значения для различных групп ...

In [11]: grouped[0][-1].head(4).round(2)
Out[11]:
      date  metadata.campaignName  localSpend.amount  daily_cap  cum_sums
396      0                      0             526.14          0    526.14
2502     0                      0             777.32          0   1303.46
2587     0                      0             777.40          0   2080.86
7198     0                      0             423.22          0   2504.08

In [12]: grouped[1][-1].head(4).round(2)
Out[12]:
      date  metadata.campaignName  localSpend.amount  daily_cap  cum_sums
1382     0                      0             798.77          1    798.77
1430     0                      0             682.32          1   1481.09
1990     0                      0            1083.74          1   2564.83
2870     0                      0             775.08          1   3339.91

In [13]: grouped[int(len(grouped)/2)][-1].head(4).round(2)
Out[13]:
      date  metadata.campaignName  localSpend.amount  daily_cap  cum_sums
1045    12                      0             624.18          0    624.18
3708    12                      0             657.94          0   1282.12
4890    12                      0             595.12          0   1877.23
5326    12                      0             891.11          0   2768.34

, которые вы можете проверить, верно.

...