Я думаю, що для цього потрібен бенчмаркінг. Використовуючи оригінальний DataFrame OP,
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)]
})
Прокоментувавши свою відповідь, Енді повністю використовує векторизацію та індексацію панд.
c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()
3,42 мс ± 16,7 мкс на цикл
(середнє ± ст. Розряд 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 мс ± 24,4 мкс на цикл
(середнє ± ст. Розряд 7 прогонів, 100 циклів у кожній)
Це найповільніша відповідь, оскільки вона обчислює x.sum()
кожного x
з рівня 0.
Для мене це все ще корисна відповідь, хоча і не в її нинішній формі. Для швидкої EDA на менших наборах даних, apply
ви можете використовувати метод ланцюга, щоб записати це в один рядок. Тому ми усуваємо необхідність вирішувати назву змінної, що насправді є обчислювально дорогим ваш найцінніший ресурс (ваш мозок !!).
Ось модифікація,
(
df.groupby(['state', 'office_id'])
.agg({'sales': 'sum'})
.groupby(level=0)
.apply(lambda x: 100 * x / float(x.sum()))
)
10,6 мс ± 81,5 мкс на цикл
(середнє ± ст. Розряд 7 прогонів, 100 циклів у кожній)
Тому ніхто не піклується про 6 мс на невеликому наборі даних. Однак це 3-кратне прискорення, і для більшого набору даних з високою групою кардинальності, це призведе до значної зміни.
Додавши до вищевказаного коду, ми робимо DataFrame з формою (12 000 000, 3) з 14412 категоріями стану та 600 office_ids,
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 с ± 10,4 мс на цикл
(середнє ± ст. Розряд 7 прогонів, по 1 петлі кожен)
та exp1orer
19 с ± 77,1 мс на цикл
(середнє ± ст. Розряд 7 прогонів, по 1 петлі кожен)
Отже, зараз ми бачимо швидкість x10 на великих, високих наборах даних про кардинальність.
Будьте впевнені, щоб УФ ці три відповіді, якщо ви УФ цей !!
df['sales'] / df.groupby('state')['sales'].transform('sum')
здається, найясніша відповідь.