Saya pikir ini perlu pembandingan. Menggunakan DataFrame asli 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)]
})
Seperti mengomentari jawabannya, Andy memanfaatkan sepenuhnya vektorisasi dan pengindeksan panda.
c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()
3,42 ms ± 16,7 µs per loop
(rata-rata ± std. Dev. Dari 7 run, masing-masing 100 loop)
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 per loop
(rata-rata ± std. Dev. Dari 7 run, masing-masing 100 loop)
Ini adalah jawaban paling lambat karena dihitung x.sum()untuk setiap jawaban xdi level 0.
Bagi saya, ini masih merupakan jawaban yang berguna, meski tidak dalam bentuknya yang sekarang. Untuk EDA cepat pada set data yang lebih kecil, applymemungkinkan Anda menggunakan rangkaian metode untuk menulis ini dalam satu baris. Oleh karena itu, kami menghapus kebutuhan memutuskan nama variabel, yang sebenarnya sangat mahal secara komputasi untuk sumber daya Anda yang paling berharga (otak Anda !!).
Berikut modifikasinya,
(
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 per loop
(rata-rata ± std. Dev. Dari 7 run, masing-masing 100 loop)
Jadi tidak ada yang peduli tentang 6ms pada kumpulan data kecil. Namun, ini adalah kecepatan 3x dan, pada kumpulan data yang lebih besar dengan grup berkardinalitas tinggi, ini akan membuat perbedaan besar.
Menambah kode di atas, kami membuat DataFrame dengan bentuk (12.000.000, 3) dengan 14412 kategori negara dan 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
})
Menggunakan Andy,
2 s ± 10,4 ms per loop
(rata-rata ± std. Dev. Dari 7 run, masing-masing 1 loop)
dan exp1orer
19 s ± 77.1 ms per loop
(rata-rata ± std. Dev. Dari 7 run, masing-masing 1 loop)
Jadi sekarang kita melihat kecepatan x10 pada kumpulan data berkardinalitas tinggi yang besar.
Pastikan untuk UV ketiga jawaban ini jika Anda UV yang satu ini !!
df['sales'] / df.groupby('state')['sales'].transform('sum')sepertinya jawaban yang paling jelas.