web-dev-qa-db-fra.com

Renommer les colonnes de résultats de l'agrégation de pandas ("FutureWarning: l'utilisation d'un dict avec un renommage est obsolète")

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?

32
Victor Mayrink

Utiliser groupby apply et renvoyer une série pour renommer des colonnes

Utilisez la méthode groupby apply pour effectuer une agrégation qui 

  • Renomme les colonnes
  • Permet des espaces dans les noms
  • Vous permet de classer les colonnes retournées comme vous le souhaitez
  • Permet des interactions entre les colonnes
  • Retourne un index de niveau unique et PAS un MultiIndex

Pour faire ça:

  • créer une fonction personnalisée que vous passez à apply
  • Cette fonction personnalisée est transmise à chaque groupe en tant que DataFrame
  • Renvoyer une série
  • L'index de la série sera les nouvelles colonnes

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]})

enter image description here

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)

enter image description here

Le gros inconvénient est que cette fonction sera beaucoup plus lente que agg pour les agrégations cythonisées

Utilisation d'un dictionnaire avec la méthode groupby 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
60
Ted Petrou

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")]})
8
Jacob Stevenson

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
0
Jyothsna Harithsa