使用 groupby 的 Pandas 占总数的百分比

新手上路,请多包涵

这显然很简单,但作为一个麻木的新手,我被卡住了。

我有一个 CSV 文件,其中包含 3 列,即州、办公室 ID 和该办公室的销售额。

我想计算给定州每个办公室的销售额百分比(每个州所有百分比的总和为 100%)。

 df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
                   'office_id': range(1, 7) * 2,
                   'sales': [np.random.randint(100000, 999999)
                             for _ in range(12)]})

df.groupby(['state', 'office_id']).agg({'sales': 'sum'})

这将返回:

                   sales
state office_id
AZ    2          839507
      4          373917
      6          347225
CA    1          798585
      3          890850
      5          454423
CO    1          819975
      3          202969
      5          614011
WA    2          163942
      4          369858
      6          959285

我似乎无法弄清楚如何“达到” state 水平 groupby 总计 sales state 计算分数。

原文由 erikcw 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.3k
2 个回答

2022 年 3 月更新

caner 使用 transform这个答案 看起来比我原来的答案好得多!

 df['sales'] / df.groupby('state')['sales'].transform('sum')

感谢 Paul Rougieux 发表的 评论

原始答案(2014)

Paul H 的回答 是正确的,您将不得不创建第二个 groupby 对象,但您可以以更简单的方式计算百分比 --- 只需 groupby state_office 并将 sales 列除以其总和。复制 Paul H 答案的开头:

 # From Paul H
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
                   'office_id': list(range(1, 7)) * 2,
                   'sales': [np.random.randint(100000, 999999)
                             for _ in range(12)]})
state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
# Change: groupby state_office and divide by sum
state_pcts = state_office.groupby(level=0).apply(lambda x:
                                                 100 * x / float(x.sum()))

回报:

                      sales
state office_id
AZ    2          16.981365
      4          19.250033
      6          63.768601
CA    1          19.331879
      3          33.858747
      5          46.809373
CO    1          36.851857
      3          19.874290
      5          43.273852
WA    2          34.707233
      4          35.511259
      6          29.781508

原文由 exp1orer 发布,翻译遵循 CC BY-SA 4.0 许可协议

(此解决方案灵感来自这篇文章 https://pbpython.com/pandas_transform.html

我发现以下解决方案是使用 transformation 最简单(也可能是最快)的解决方案:

转换:虽然聚合必须返回数据的缩减版本,但转换可以返回完整数据的一些转换版本以重新组合。对于这样的转换,输出与输入的形状相同。

所以使用 transformation ,解决方案是 1-liner:

 df['%'] = 100 * df['sales'] / df.groupby('state')['sales'].transform('sum')

如果你打印:

 print(df.sort_values(['state', 'office_id']).reset_index(drop=True))

   state  office_id   sales          %
0     AZ          2  195197   9.844309
1     AZ          4  877890  44.274352
2     AZ          6  909754  45.881339
3     CA          1  614752  50.415708
4     CA          3  395340  32.421767
5     CA          5  209274  17.162525
6     CO          1  549430  42.659629
7     CO          3  457514  35.522956
8     CO          5  280995  21.817415
9     WA          2  828238  35.696929
10    WA          4  719366  31.004563
11    WA          6  772590  33.298509

原文由 Caner 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题