Je pense que cela nécessite une analyse comparative. En utilisant le DataFrame original d'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)]
})
Comme commenté sa réponse, Andy profite pleinement de la vectorisation et de l'indexation des pandas.
c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()
3,42 ms ± 16,7 µs par boucle
(moyenne ± écart type de 7 analyses, 100 boucles chacune)
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 par boucle
(moyenne ± écart-type de 7 analyses, 100 boucles chacune)
C'est la réponse la plus lente car il calcule x.sum()
pour chacun x
au niveau 0.
Pour moi, c'est toujours une réponse utile, mais pas dans sa forme actuelle. Pour une EDA rapide sur des ensembles de données plus petits, apply
vous permet d'utiliser le chaînage de méthodes pour écrire cela sur une seule ligne. Nous supprimons donc le besoin de décider du nom d'une variable, ce qui est en fait très coûteux en calcul pour votre ressource la plus précieuse (votre cerveau !!).
Voici la modification,
(
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 par boucle
(moyenne ± écart type de 7 analyses, 100 boucles chacune)
Donc personne ne va se soucier d'environ 6 ms sur un petit ensemble de données. Cependant, il s'agit d'une vitesse 3x et, sur un ensemble de données plus grand avec des groupbys à cardinalité élevée, cela fera une énorme différence.
En ajoutant au code ci-dessus, nous créons un DataFrame avec une forme (12 000 000, 3) avec 14412 catégories d'état et 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
})
En utilisant Andy's,
2 s ± 10,4 ms par boucle
(moyenne ± écart standard de 7 courses, 1 boucle chacune)
et exp1orer
19 s ± 77,1 ms par boucle
(moyenne ± écart standard de 7 courses, 1 boucle chacune)
Nous voyons maintenant une vitesse x10 sur de grands ensembles de données à cardinalité élevée.
Assurez-vous de UV ces trois réponses si vous UV celle-ci !!
df['sales'] / df.groupby('state')['sales'].transform('sum')
semble être la réponse la plus claire.