pandas dataframe groupby datetime mois


90

Considérez un fichier csv:

string,date,number
a string,2/5/11 9:16am,1.0
a string,3/5/11 10:44pm,2.0
a string,4/22/11 12:07pm,3.0
a string,4/22/11 12:10pm,4.0
a string,4/29/11 11:59am,1.0
a string,5/2/11 1:41pm,2.0
a string,5/2/11 2:02pm,3.0
a string,5/2/11 2:56pm,4.0
a string,5/2/11 3:00pm,5.0
a string,5/2/14 3:02pm,6.0
a string,5/2/14 3:18pm,7.0

Je peux lire ceci et reformater la colonne de date au format datetime:

b=pd.read_csv('b.dat')
b['date']=pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')

J'ai essayé de regrouper les données par mois. Il semble qu'il devrait y avoir un moyen évident d'accéder au mois et de le regrouper. Mais je n'arrive pas à le faire. Quelqu'un sait-il comment?

Ce que j'essaye actuellement est de réindexer par la date:

b.index=b['date']

Je peux accéder au mois comme ceci:

b.index.month

Cependant, je n'arrive pas à trouver une fonction à regrouper par mois.

Réponses:


174

J'ai réussi à le faire:

b = pd.read_csv('b.dat')
b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')
b.groupby(by=[b.index.month, b.index.year])

Ou

b.groupby(pd.Grouper(freq='M'))  # update for v0.21+

51
Je pense que les moyens les plus pandoniques sont d'utiliser resample(quand il fournit les fonctionnalités dont vous avez besoin) ou d'utiliser un TimeGrouper:df.groupby(pd.TimeGrouper(freq='M'))
Karl D.

10
pour obtenir le résultat DataFrame somme ou moyenne, df.groupby(pd.TimeGrouper(freq='M')).sum()oudf.groupby(pd.TimeGrouper(freq='M')).mean()
Alexandre

9
pd.TimeGroupera été déconseillé en faveur de pd.Grouper, qui est un peu plus flexible mais prend toujours freqet levelarguments.
BallpointBen

la première méthode ne semble pas fonctionner. Il donne l'erreur 'L'objet Série n'a pas d'attribut' mois '' pour une Série créée via to_datetime.
ely

1
@ely La réponse repose implicitement sur les lignes de la question d'origine où best donné un index après avoir été lu à partir de CSV. Ajoutez b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')après la ligne b = pd.read_csv('b.dat'). [J'ai également modifié la réponse.]
goodside

71

(mise à jour: 2018)

Notez qu'il pd.Timegrouperest amorti et sera supprimé. Utilisez à la place:

 df.groupby(pd.Grouper(freq='M'))

2
Trouvez la documentation de Grouper ici et les spécifications de fréquence ( freq=...) ici . Quelques exemples sont freq=Ddes jours , freq=Bpour jours ouvrables , freq=Wpour semaines ou même freq=Qpour les quarts .
Kim

1
J'ai trouvé utile d'utiliser 'key' pour éviter d'avoir à réindexer le df, comme suit: df.groupby (pd.Grouper (key = 'your_date_column', freq = 'M'))
Edward

10

Une solution qui évite MultiIndex est de créer une nouvelle datetimecolonne en définissant le jour = 1. Regrouper ensuite par cette colonne. Exemple trivial ci-dessous.

df = pd.DataFrame({'Date': pd.to_datetime(['2017-10-05', '2017-10-20']),
                   'Values': [5, 10]})

# normalize day to beginning of month
df['YearMonth'] = df['Date'] - pd.offsets.MonthBegin(1)

# two alternative methods
df['YearMonth'] = df['Date'] - pd.to_timedelta(df['Date'].dt.day-1, unit='D')
df['YearMonth'] = df['Date'].map(lambda dt: dt.replace(day=1))

g = df.groupby('YearMonth')

res = g['Values'].sum()

# YearMonth
# 2017-10-01    15
# Name: Values, dtype: int64

L'avantage subtil de cette solution est que, contrairement à ce que pd.Grouperl'index du mérou est normalisé au début de chaque mois plutôt qu'à la fin, vous pouvez facilement extraire des groupes via get_group:

some_group = g.get_group('2017-10-01')

Le calcul du dernier jour d'octobre est un peu plus fastidieux. pd.Grouper, à partir de la version 0.23, prend en charge un conventionparamètre, mais cela n'est applicable que pour un PeriodIndexgroupeur.


8

Solution légèrement alternative à @ jpp mais sortie d'une YearMonthchaîne:

df['YearMonth'] = pd.to_datetime(df['Date']).apply(lambda x: '{year}-{month}'.format(year=x.year, month=x.month))

res = df.groupby('YearMonth')['Values'].sum()
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.