Я думаю, что это требует сравнительного анализа. Используя оригинальный 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 циклу каждый)
Так что теперь мы видим ускорение в 10 раз на больших наборах данных с большим количеством элементов.
Обязательно УФ эти три ответа, если вы УФ этот !!
df['sales'] / df.groupby('state')['sales'].transform('sum')
кажется, самый ясный ответ.