在Python中对多列进行分组求和和计数

14

我有一个长这样的pandas数据框:

ID     country   month   revenue  profit   ebit
234    USA       201409   10        5       3
344    USA       201409    9        7       2
532    UK        201410    20       10      5
129    Canada    201411    15       10      5

我想按照ID、国家和月份分组,并统计每个月和国家的ID数量,以及收入、利润、EBIT总和。

上述数据的输出结果如下:

 country   month    revenue   profit  ebit   count
   USA     201409     19        12      5      2
   UK      201409     20        10      5      1
   Canada  201411     15        10      5      1

我尝试了 pandas 的不同 groupby、sum 和 count 函数的变体,但是我无法弄清楚如何将 groupby sum 和 count 应用到一起,以给出所示的结果。请分享您可能拥有的任何想法。谢谢!


你能同时发布Tries的代码吗?你尝试了哪种方法? - Maksim Luzik
4个回答

27

你可以使用 pivot_table 这种方式来实现:

>>> df1=pd.pivot_table(df, index=['country','month'],values=['revenue','profit','ebit'],aggfunc=np.sum)
>>> df1 
                ebit  profit  revenue
country month                        
Canada  201411     5      10       15
UK      201410     5      10       20
USA     201409     5      12       19

>>> df2=pd.pivot_table(df, index=['country','month'], values='ID',aggfunc=len).rename('count')
>>> df2

country  month 
Canada   201411    1
UK       201410    1
USA      201409    2

>>> pd.concat([df1,df2],axis=1)

                ebit  profit  revenue  count
country month                               
Canada  201411     5      10       15      1
UK      201410     5      10       20      1
USA     201409     5      12       19      2

更新

可以使用pivot_table一行代码完成,并在aggfunc参数中提供一个应用于每个列的函数字典:

pd.pivot_table(
   df,
   index=['country','month'],
   aggfunc={'revenue': np.sum, 'profit': np.sum, 'ebit': np.sum, 'ID': len}
).rename(columns={'ID': 'count'})

                count  ebit  profit  revenue
country month                               
Canada  201411      1     5      10       15
UK      201410      1     5      10       20
USA     201409      2     5      12       19

1
你能否也看一下这个问题?它变得更加棘手了! - N91

19

您可以进行分组操作,然后将每个国家的计数映射到一个新列中。

g = df.groupby(['country', 'month'])['revenue', 'profit', 'ebit'].sum().reset_index()
g['count'] = g['country'].map(df['country'].value_counts())
g

Out[3]:


    country  month   revenue  profit  ebit  count
0   Canada   201411  15       10      5     1
1   UK       201410  20       10      5     1
2   USA      201409  19       12      5     2

编辑

要按国家和月份获取计数,可以进行另一个 groupby 操作,然后将这两个 DataFrame 进行连接。

g = df.groupby(['country', 'month'])['revenue', 'profit', 'ebit'].sum()
j = df.groupby(['country', 'month']).size().to_frame('count')
pd.merge(g, j, left_index=True, right_index=True).reset_index()

Out[6]:

    country  month   revenue  profit  ebit  count
0   Canada   201411  15       10      5     1
1   UK       201410  20       10      5     1
2   UK       201411  10       5       2     1
3   USA      201409  19       12      5     2

我为英国添加了另一条记录,日期不同 - 请注意现在合并的DataFrame中有两个英国条目,并且计数正确。


谢谢你的帮助,Ben。但是这个解决方案没有考虑到月份。我需要一个计数值,针对每个独特的国家和月份组合,统计所有ID的数量。 - N91
太好了!谢谢! - N91

6
以下解决方案似乎是最简单的。
按国家和月份分组:
grouped_df = df.groupby(['country', 'month'])

将总和应用于感兴趣的列(收入、利润、EBIT):

final = grouped_df[['revenue', 'profit', 'ebit']].agg('sum')

将 grouped_df 的大小赋值给 'final' 中的一个新列:
final['count'] = grouped_df.size()
print(final)

Out[256]: 
                revenue  profit  ebit  count
country month                               
Canada  201411       15      10     5      1
UK      201410       20      10     5      1
USA     201409       19      12     5      2

全部完成!


3
下面的 groupby 解决方案可能是最简单的,并且正是你想要的。
temp2 = temp1.groupby(['country', 'month'])
        .agg({'revenue': 'sum', 'profit': 'sum', 'ebit': 'sum', 'ID': 'count'})
        .reset_index()
        .rename(columns={'ID': 'count'})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接