我认为这需要进行基准测试。使用OP的原始DataFrame,
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)]
})
如对他的回答的评论所述,Andy充分利用了矢量化和熊猫索引的优势。
c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()
每个循环3.42 ms ±16.7 µs
(平均±标准偏差,共运行7次,每个循环100个)
state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
state = df.groupby(['state']).agg({'sales': 'sum'})
state_office.div(state, level='state') * 100
每个循环4.66 ms ±24.4 µs
(平均±标准偏差,共运行7次,每个循环100个)
这是最慢的答案,因为它x.sum()
针对x
级别0中的每个答案进行计算。
对我来说,尽管不是目前的形式,这仍然是一个有用的答案。为了在较小的数据集上apply
实现快速EDA,允许您使用方法链接将其写在一行中。因此,我们无需决定变量的名称,而实际上这在计算上非常昂贵对于您最宝贵的资源(您的大脑!)来说。
这是修改,
(
df.groupby(['state', 'office_id'])
.agg({'sales': 'sum'})
.groupby(level=0)
.apply(lambda x: 100 * x / float(x.sum()))
)
每个循环10.6 ms ±81.5 µs
(平均±标准偏差,共运行7次,每个循环100个)
因此,在小型数据集上,没有人会关心6ms。但是,这是3倍的速度,并且在具有高基数groupbys的较大数据集上,这将产生巨大的差异。
添加到上面的代码中,我们制作一个形状为(12,000,000,3)的DataFrame,其中包含14412个状态类别和600个office_id,
import string
import numpy as np
import pandas as pd
np.random.seed(0)
groups = [
''.join(i) for i in zip(
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
)
]
df = pd.DataFrame({'state': groups * 400,
'office_id': list(range(1, 601)) * 20000,
'sales': [np.random.randint(100000, 999999)
for _ in range(12)] * 1000000
})
使用安迪的
每个循环2 s ±10.4毫秒
(平均±标准偏差,共运行7次,每个循环1次)
和exp1orer
每个循环19 s ±77.1 ms
(平均±标准偏差,共运行7次,每个循环1次)
因此,现在我们看到x10在大型,高基数的数据集上速度加快。
如果要紫外线这三个答案,一定要紫外线这三个答案!
df['sales'] / df.groupby('state')['sales'].transform('sum')
似乎是最明确的答案。