web-dev-qa-db-fra.com

Pandas: rééchantillonner les séries chronologiques avec group by

Étant donné le pandas DataFrame:

In [115]: times = pd.to_datetime(pd.Series(['2014-08-25 21:00:00','2014-08-25 21:04:00',
                                            '2014-08-25 22:07:00','2014-08-25 22:09:00']))
          locations = ['HK', 'LDN', 'LDN', 'LDN']
          event = ['foo', 'bar', 'baz', 'qux']
          df = pd.DataFrame({'Location': locations,
                             'Event': event}, index=times)
          df
Out[115]:
                               Event Location
          2014-08-25 21:00:00  foo   HK
          2014-08-25 21:04:00  bar   LDN
          2014-08-25 22:07:00  baz   LDN
          2014-08-25 22:09:00  qux   LDN

Je voudrais rééchantillonner les données pour les agréger toutes les heures en nombre tout en les regroupant par emplacement pour produire un bloc de données qui ressemble à ceci:

Out[115]:
                               HK    LDN
          2014-08-25 21:00:00  1     1
          2014-08-25 22:00:00  0     2

J'ai essayé différentes combinaisons de resample () et groupby () mais sans succès. Comment pourrais-je m'y prendre?

32
AshB

Dans mon message d'origine, j'ai suggéré d'utiliser pd.TimeGrouper. De nos jours, utilisez pd.Grouper au lieu de pd.TimeGrouper. La syntaxe est largement la même, mais TimeGrouperest désormais obsolète en faveur de pd.Grouper.

De plus, tandis que pd.TimeGrouper n'a pu être regroupé que par DatetimeIndex, pd.Grouper peut regrouper par colonnes datetime que vous pouvez spécifier via le paramètre key .


Vous pouvez utiliser un pd.Grouper pour regrouper le DataFrame DatetimeIndex'ed par heure:

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])

utilisez count pour compter le nombre d'événements dans chaque groupe:

grouper['Event'].count()
#                      Location
# 2014-08-25 21:00:00  HK          1
#                      LDN         1
# 2014-08-25 22:00:00  LDN         2
# Name: Event, dtype: int64

utilisez unstack pour déplacer le niveau d'index Location vers un niveau de colonne:

grouper['Event'].count().unstack()
# Out[49]: 
# Location             HK  LDN
# 2014-08-25 21:00:00   1    1
# 2014-08-25 22:00:00 NaN    2

puis utilisez fillna pour changer les NaN en zéros.


Mettre tous ensemble,

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])
result = grouper['Event'].count().unstack('Location').fillna(0)

les rendements

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2
40
unutbu

Pandas 0.21 réponse: TimeGrouper devient obsolète

Il existe deux options pour ce faire. Ils peuvent en fait donner des résultats différents en fonction de vos données. La première option regroupe par emplacement et dans les groupes d'emplacement par heure. La deuxième option regroupe en même temps l'emplacement et l'heure.

Option 1 : utilisez groupby + resample

grouped = df.groupby('Location').resample('H')['Event'].count()

Option 2 : regroupez à la fois l'emplacement et DatetimeIndex avec groupby(pd.Grouper)

grouped = df.groupby(['Location', pd.Grouper(freq='H')])['Event'].count()

Les deux entraîneront les résultats suivants:

Location                     
HK        2014-08-25 21:00:00    1
LDN       2014-08-25 21:00:00    1
          2014-08-25 22:00:00    2
Name: Event, dtype: int64

Et puis remodeler:

grouped.unstack('Location', fill_value=0)

Sortira

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2
31
Ted Petrou

Regrouper plusieurs colonnes par

untubu est sur place avec sa réponse, mais je voulais ajouter ce que vous pourriez faire si vous aviez une troisième colonne, dites Cost et vouliez l'agréger comme ci-dessus. C'est en combinant la réponse d'unutbu et celle-ci que j'ai découvert comment faire et pensé que je partagerais pour les futurs utilisateurs.

Créez un DataFrame avec la colonne Cost:

In[1]:
import pandas as pd
import numpy as np
times = pd.to_datetime([
    "2014-08-25 21:00:00", "2014-08-25 21:04:00",
    "2014-08-25 22:07:00", "2014-08-25 22:09:00"
])
df = pd.DataFrame({
    "Location": ["HK", "LDN", "LDN", "LDN"],
    "Event":    ["foo", "bar", "baz", "qux"],
    "Cost":     [20, 24, 34, 52]
}, index = times)
df

Out[1]:
                     Location  Event  Cost
2014-08-25 21:00:00        HK    foo    20
2014-08-25 21:04:00       LDN    bar    24
2014-08-25 22:07:00       LDN    baz    34
2014-08-25 22:09:00       LDN    qux    52

Maintenant, nous regroupons en utilisant la fonction agg pour spécifier la méthode d'agrégation de chaque colonne, par exemple compte, moyenne, somme, etc.

In[2]:
grp = df.groupby([pd.Grouper(freq = "1H"), "Location"]) \
      .agg({"Event": np.size, "Cost": np.mean})
grp

Out[2]:
                               Event  Cost
                     Location
2014-08-25 21:00:00  HK            1    20
                     LDN           1    24
2014-08-25 22:00:00  LDN           2    43

Puis le unstack final avec fill NaN avec des zéros et s'affiche comme int parce que c'est sympa.

In[3]: 
grp.unstack().fillna(0).astype(int)

Out[3]:
                    Event     Cost
Location               HK LDN   HK LDN
2014-08-25 21:00:00     1   1   20  24
2014-08-25 22:00:00     0   2    0  43
8