벤치마킹이 필요하다고 생각합니다. 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.42ms ± 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의 루프 당
(평균 ± 표준. DEV. 7 개 실행의 100 개 루프 각)
이것은 레벨 0에서 x.sum()
각각 x
에 대해 계산할 때 가장 느린 답변 입니다.
나에게 이것은 현재 유용한 형식은 아니지만 여전히 유용한 대답입니다. 작은 데이터 세트에서 빠른 EDA apply
를 수행하려면 메소드 체인 을 사용 하여이를 한 줄로 작성할 수 있습니다 . 따라서 변수 이름에 대한 결정이 필요하지 않습니다. 실제로 가장 귀중한 자원 (뇌)에 계산 비용이 많이 듭니다 .
여기 수정 사항이 있습니다.
(
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의 루프 당
(평균 ± 표준. DEV. 7 개 실행의 100 개 루프 각)
따라서 작은 데이터 세트에서 아무도 6ms를 신경 쓰지 않습니다. 그러나 이것은 3 배 빠른 속도이며 높은 카디널리티 그룹을 가진 더 큰 데이터 세트에서 큰 차이를 만들 것입니다.
위의 코드에 추가하여 14412 상태 범주와 600 office_ids로 모양 (12,000,000, 3)의 DataFrame을 만듭니다.
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.4ms
(평균 7 회 실행, 각 1 루프의 평균 ± 표준)
exp1orer
루프 당 19 초 ± 77.1ms
(평균 7 회 실행, 각 1 회 루프 평균 ± 표준)
이제 큰 카디널리티 데이터 세트에서 x10 속도가 향상되었습니다.
당신이 이것을 UV라면이 3 가지 대답을 UV로해라!
df['sales'] / df.groupby('state')['sales'].transform('sum')
가장 명확한 대답 인 것 같습니다.