J'essaie de faire des agrégations sur un bloc de données de pandas. Voici un exemple de code:
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0]})
df.groupby(["User"]).agg({"Amount": {"Sum": "sum", "Count": "count"}})
Out[1]:
Amount
Sum Count
User
user1 18.0 2
user2 20.5 3
user3 10.5 1
Ce qui génère l'avertissement suivant:
FutureWarning: utiliser un dict avec changement de nom est obsolète et sera supprimé dans une future version retournera super (DataFrameGroupBy, self) .aggregate (arg, * args, ** kwargs)
Comment puis-je éviter ça?
apply
et renvoyer une série pour renommer des colonnesUtilisez la méthode groupby apply
pour effectuer une agrégation qui
Pour faire ça:
apply
Créer de fausses données
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1", "user3"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0, 9],
'Score': [9, 1, 8, 7, 7, 6, 9]})
crée une fonction personnalisée qui retourne une série
La variable x
à l'intérieur de my_agg
est un DataFrame
def my_agg(x):
names = {
'Amount mean': x['Amount'].mean(),
'Amount std': x['Amount'].std(),
'Amount range': x['Amount'].max() - x['Amount'].min(),
'Score Max': x['Score'].max(),
'Score Sum': x['Score'].sum(),
'Amount Score Sum': (x['Amount'] * x['Score']).sum()}
return pd.Series(names, index=['Amount range', 'Amount std', 'Amount mean',
'Score Sum', 'Score Max', 'Amount Score Sum'])
Transmettre cette fonction personnalisée à la méthode groupby apply
df.groupby('User').apply(my_agg)
Le gros inconvénient est que cette fonction sera beaucoup plus lente que agg
pour les agrégations cythonisées
agg
L'utilisation d'un dictionnaire de dictionnaires a été supprimée en raison de sa complexité et de sa nature quelque peu ambiguë. Il y a une discussion en cours sur la manière d'améliorer cette fonctionnalité à l'avenir sur github. Vous pouvez accéder directement à la colonne d'agrégation après l'appel groupby. Passez simplement une liste de toutes les fonctions d'agrégation que vous souhaitez appliquer.
df.groupby('User')['Amount'].agg(['sum', 'count'])
Sortie
sum count
User
user1 18.0 2
user2 20.5 3
user3 10.5 1
Il est toujours possible d'utiliser un dictionnaire pour indiquer explicitement différentes agrégations pour différentes colonnes, comme ici s'il existait une autre colonne numérique nommée Other
.
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0],
'Other': [1,2,3,4,5,6]})
df.groupby('User').agg({'Amount' : ['sum', 'count'], 'Other':['max', 'std']})
Sortie
Amount Other
sum count max std
User
user1 18.0 2 6 3.535534
user2 20.5 3 5 1.527525
user3 10.5 1 4 NaN
Si vous remplacez le dictionnaire interne par une liste de n-uplets, le message d'avertissement disparaît
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0]})
df.groupby(["User"]).agg({"Amount": [("Sum", "sum"), ("Count", "count")]})
C'est ce que j'ai fait:
Créez un faux jeu de données:
import pandas as pd
df = pd.DataFrame({"User": ["user1", "user2", "user2", "user3", "user2", "user1", "user3"],
"Amount": [10.0, 5.0, 8.0, 10.5, 7.5, 8.0, 9],
'Score': [9, 1, 8, 7, 7, 6, 9]})
df
O/P:
Amount Score User
0 10.0 9 user1
1 5.0 1 user2
2 8.0 8 user2
3 10.5 7 user3
4 7.5 7 user2
5 8.0 6 user1
6 9.0 9 user3
J'ai d'abord fait de l'utilisateur l'index, puis un groupby:
ans = df.set_index('User').groupby(level=0)['Amount'].agg([('Sum','sum'),('Count','count')])
ans
Solution:
Sum Count
User
user1 18.0 2
user2 20.5 3
user3 19.5 2