与groupby的求和不适用于熊猫

时间:2018-11-29 17:07:51

标签: python pandas pandas-groupby cumsum

我有一个数据帧,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)

基于我在这里找到的其他答案(thisthis)。

我得到的结果只是支出列('localSpend.amount')的副本,而不是唯一['metadata.campaignName', 'date', 'daily_cap']组上的累积总和。

为什么这不起作用?

编辑:我已经将示例数据框创建为字典here(太大,无法粘贴到此处)。

2 个答案:

答案 0 :(得分:0)

您要分组的类别列之一可能对于每个观察值都是数字的或唯一的,因此不会进行分组(这就是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
您可以验证的

是正确的。

答案 1 :(得分:0)

在这种情况下,我发现最干净的解决方案是

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

这使累积总和适用于每组广告系列名称/日期(小时)。在这种情况下,可能需要按日期/小时的升序对其进行排序。

我的问题是我在组中加入了date列,因此每个组都是完全唯一的(例如@ALollz指出)。

此外,如果每天提取数据(这就是我的情况),它也可以工作。