我无法发表评论,因为我是堆栈溢出的新手,所以不能直接在线程中询问,但我想澄清这个问题的解决方案:
# 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()))
我了解多索引选择(级别 0 与级别 1),但我不清楚 lambda 函数中的每个x
指的是什么。对我来说,x.sum()
中的x
是指level = 0
(将每个分组中的所有结果相加level = 0
),但100 * x
中的x
似乎是指 groupby 对象中的每个单独结果(而不是分组level = 0
索引)。
很抱歉这样一个基本问题,但解释会非常有用!
这是数据帧state_office
:
state_office
Out:
sales
state office_id
AZ 2 589661
4 339834
6 201054
CA 1 760950
3 935865
5 464993
CO 1 737207
3 154900
5 277555
WA 2 510215
4 640508
6 557411
如果将其分组在级别=0,则组将是:
sales
state office_id
AZ 2 589661
4 339834
6 201054
sales
state office_id
CA 1 760950
3 935865
5 464993
sales
state office_id
CO 1 737207
3 154900
5 277555
当您将 groupby.apply 与自定义函数一起使用时,这些组将成为此函数的输入(在 lambda x 中x
)。我将使用术语group
而不是 x 来更明确。
让你感到困惑的事情叫做广播。如果您使用group / group.sum()
的特定组,那么它将把该组中的每个元素除以总和。让我们以第一组为例:
sales
state office_id
AZ 2 589661
4 339834
6 201054
group.sum()
回报:
group.sum()
Out:
sales 1130549
dtype: int64
由于它只有一个元素,float(x.sum())
将返回 1130549.0。(更简洁的版本是在 GroupBy 对象上选择销售系列,然后应用该函数。state_office.groupby(level=0)['sales'].apply(lambda x: 100 * x / x.sum())
在这里,x
是一个系列,所以x.sum()
将是一个标量,所以你不需要float(x.sum())
)。
如果将每个元素除以此值,则会得到所需的结果:
group / group.sum()
Out:
sales
state office_id
AZ 2 0.521570
4 0.300592
6 0.177837
此时的 Pandas/NumPy 发现,如果形状不相同但有一个共同的轴,则应基于此进行操作(更基本的是,如果您传递三个数字,则它将执行逐元素除法,但由于您只传递一个数字,它知道您要将这三个数字中的每一个除以这个数字)。
让我们一起阅读文档。(来源)
GroupBy.apply(func, *args, **kwargs)[source] Apply functionfunc按组划分并将结果组合在一起。
从上面的签名中查看func
:
函数 : 函数
一个可调用对象,它将数据帧作为其第一个参数,并返回 数据帧、序列或标量。此外,可赎回的可能需要 位置和关键字参数
在 OP 的示例中,文档中func
lambda x: 100 * x / float(x.sum()
。从文档中,x
此处是一个数据帧,即groupby
调用后的一组组。