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.

atomh33ls
la source

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+
atomh33ls
la source
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'))
PandasRocks
la source
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.

jpp
la source
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()
Tsando
la source