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