Python: Pandas DataFrame groupby resample

Comment analyser des données en les regroupant par les valeurs d'une colonne et en les ré-échantillonant, via une colonne "date", à chaque fin de mois.

J'ai un DataFrame Pandas "df1" avec les données suivantes:

>>> df1
      DATE        USER     DUREE
0     2020-09-03  USER#1   0.50
1     2020-09-02  USER#1   0.00
2     2020-09-02  USER#1   0.25
3     2020-09-01  USER#1   0.00
4     2020-09-01  USER#1   0.25
          ...     ...    ...
10715 2017-08-01  USER#2   0.75
10716 2017-07-19  USER#2   0.00
10717 2017-07-19  USER#2   0.00
10718 2017-07-17  USER#2   0.25
10719 2017-07-17  USER#2   0.00
[10720 rows x 3 columns]

J'ai donc 3 colonnes, une colonne "DATE", une colonne "USER" et une colonne "DUREE" avec les formats suivants:

>>> df1.dtypes
DATE     datetime64[ns]
USER             object
DUREE           float64
dtype: object

J'aimerais donc connaitre le cumul du temps passé par chaque "USER" à chaque fin de mois et obtenir le résultat suivant:

USER        USER#1  USER#2
DATE                     
2011-04-30   76.25    0.00
2011-05-31  109.75    0.00
2011-06-30   74.00    0.00
2011-07-31   31.25    0.00
2011-08-31   83.75    0.00
            ...     ...
2020-05-31    8.75   17.50
2020-06-30   25.50   18.25
2020-07-31    4.25   38.00
2020-08-31   92.75    5.25
2020-09-30    1.25    4.50
[114 rows x 2 columns]

Ce résultat peut-être obtenu en utilisant tout simplement 5 méthodes disponibles pour les DataFrame.

Premièrement, je ré-index mon DataFrame en utilisant la colonne "DATE" - Indispensable pour le ré-échantillonage

>>> df1.set_index('DATE')
              USER  DUREE
DATE                    
2020-09-03  USER#1   0.50
2020-09-02  USER#1   0.00
2020-09-02  USER#1   0.25
2020-09-01  USER#1   0.00
2020-09-01  USER#1   0.25
            ...    ...
2017-08-01  USER#2   0.75
2017-07-19  USER#2   0.00
2017-07-19  USER#2   0.00
2017-07-17  USER#2   0.25
2017-07-17  USER#2   0.00
[10720 rows x 2 columns]

Ensuite, j'effectue mon regroupement sur la colonne "USER"

>>> df1.set_index('DATE').groupby('USER')
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000151789EDEB0>

J'obtiens donc un objet "DataFrameGroupBy"

Pour le ré-échantillonage, j'utilise la méthode "resample" qui va agir sur les données contenues dans mon index (par défaut).
Le paramètre "M" va ré-échantilloner mes dates à chaque fin de mois.

>>> df1.set_index('DATE').groupby('USER').resample('M')
<pandas.core.resample.DatetimeIndexResamplerGroupby object at 0x000001517888F3A0>

J'obtiens donc un objet "DatetimeIndexResamplerGroupby"

Je fais maintenant la somme des valeurs de ma colonne "DUREE"

>>> df1.set_index('DATE').groupby('USER').resample('M')['DUREE'].sum()
USER    DATE     
USER#1  2011-04-30     76.25
        2011-05-31    109.75
        2011-06-30     74.00
        2011-07-31     31.25
        2011-08-31     83.75
                       ... 
USER#2  2020-05-31     17.50
        2020-06-30     18.25
        2020-07-31     38.00
        2020-08-31      5.25
        2020-09-30      4.50
Name: DUREE, Length: 153, dtype: float64

Pour finir, je souhaite transposer le premier niveau "USER" de mon index en colonne.
Pour cela j'utilise la méthode "unstack" avec le paramètre "level=0" pour lui indiquer le premier niveau de mon index et je lui demande de remplacer les valeurs nulles par "0" grâce à "fill_value=0"

>>> df1.set_index('DATE').groupby('USER').resample('M')['DUREE'].sum().unstack(level=0, fill_value=0)
USER        USER#1  USER#2
DATE                     
2011-04-30   76.25    0.00
2011-05-31  109.75    0.00
2011-06-30   74.00    0.00
2011-07-31   31.25    0.00
2011-08-31   83.75    0.00
            ...     ...
2020-05-31    8.75   17.50
2020-06-30   25.50   18.25
2020-07-31    4.25   38.00
2020-08-31   92.75    5.25
2020-09-30    1.25    4.50
[114 rows x 2 columns]

Et voilà, mes données ont été agrégées par "USER" et ré-échantillonées à chaque fin de mois.

Il est possible de filtrer les données par année

>>> df1.set_index('DATE').groupby('USER').resample('M')['DUREE'].sum().unstack(level=0, fill_value=0).loc['2020']
USER        USER#1  USER#2
DATE                     
2020-01-31   25.50   50.50
2020-02-29   35.25   15.25
2020-03-31   33.25   26.75
2020-04-30    6.50    1.25
2020-05-31    8.75   17.50
2020-06-30   25.50   18.25
2020-07-31    4.25   38.00
2020-08-31   92.75    5.25
2020-09-30    1.25    4.50

Ou de calculer le total par "USER"

>>> df1.set_index('DATE').groupby('USER').resample('M')['DUREE'].sum().unstack(level=0, fill_value=0).sum()
USER
USER#1    8219.5
USER#2    2432.5
dtype: float64

Ou de calculer le total par "USER" pour une année précise

>>> df1.set_index('DATE').groupby('USER').resample('M')['DUREE'].sum().unstack(level=0, fill_value=0).loc['2020'].sum()
USER
USER#1    233.00
USER#2    177.25
dtype: float64

Simple comme bonjour.

Merci Pandas

Ajouter un commentaire

Filtered HTML

  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Tags HTML autorisés : <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Les lignes et les paragraphes vont à la ligne automatiquement.

Plain text

  • Aucune balise HTML autorisée.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
CAPTCHA
Cette question permet de s'assurer que vous êtes un utilisateur humain et non un logiciel automatisé de pollupostage.
CAPTCHA visuel
Entrez les caractères (sans espace) affichés dans l'image.