これにはベンチマークが必要だと思います。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ループ)
これは、レベル0のx.sum()
それぞれについて計算するため、最も遅い回答x
です。
私にとって、これは現在の形ではありませんが、依然として有用な答えです。小さなデータセットですばやくEDAをapply
実行するには、メソッドチェーンを使用してこれを1行で記述できます。したがって、実際には計算コストが非常に高い変数の名前を決定する必要がなくなります。最も貴重なリソース(脳!!)に対してます。
ここに変更があります
(
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倍のスピードアップであり、カーディナリティの高いgroupbyを使用する大規模なデータセットでは、大きな違いが生じます。
上記のコードに加えて、14412の状態カテゴリと600のoffice_idを持つ形状(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 s ±10.4 ms
(7ランの平均±標準偏差、各1ループ)
およびexp1orer
ループあたり19 s ±77.1 ms
(7つの実行の平均±標準偏差、各1ループ)
大きなカーディナリティのデータセットでx10がスピードアップすることがわかります。
これをUVする場合は、必ずこれら3つの回答をUVしてください。
df['sales'] / df.groupby('state')['sales'].transform('sum')
最も明確な答えのようです。