pandas dataframe groupby datetime month

87

Betrachten Sie eine CSV-Datei:

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

Ich kann dies einlesen und die Datumsspalte in das Datum / Uhrzeit-Format umformatieren:

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

Ich habe versucht, die Daten nach Monat zu gruppieren. Es scheint, dass es eine offensichtliche Möglichkeit geben sollte, auf den Monat zuzugreifen und danach zu gruppieren. Aber ich kann es nicht scheinen. Weiß jemand wie?

Was ich derzeit versuche, ist die Neuindizierung nach Datum:

b.index=b['date']

Ich kann wie folgt auf den Monat zugreifen:

b.index.month

Ich kann jedoch keine Funktion finden, die sich monatlich zusammenfasst.

atomh33ls
quelle

Antworten:

167

Hat es geschafft:

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])

Oder

b.groupby(pd.Grouper(freq='M'))  # update for v0.21+
atomh33ls
quelle
51
Ich denke, die pandonischeren Möglichkeiten sind, entweder zu verwenden resample(wenn es die Funktionalität bietet, die Sie benötigen) oder zu verwenden TimeGrouper:df.groupby(pd.TimeGrouper(freq='M'))
Karl D.
7
um das Ergebnis DataFrame Summe oder Durchschnitt zu erhalten, df.groupby(pd.TimeGrouper(freq='M')).sum()oderdf.groupby(pd.TimeGrouper(freq='M')).mean()
Alexandre
7
pd.TimeGrouperwurde zugunsten von abgelehnt pd.Grouper, was etwas flexibler ist, aber immer noch nimmt freqund levelargumentiert.
BallpointBen
Die erste Methode scheint nicht zu funktionieren. Es gibt den Fehler "Serienobjekt hat kein Attribut" Monat "für eine Serie, die über erstellt wurde to_datetime.
Ely
1
@ely Die Antwort basiert implizit auf den Zeilen in der ursprünglichen Frage, in denen bnach dem Lesen aus der CSV ein Index angegeben wird. b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')Nach der Zeile hinzufügen b = pd.read_csv('b.dat'). [Ich habe die Antwort gerade auch bearbeitet.]
goodside
66

(Update: 2018)

Beachten Sie, dass dies pd.Timegrouperabgeschrieben wird und entfernt wird. Verwenden Sie stattdessen:

 df.groupby(pd.Grouper(freq='M'))
PandasRocks
quelle
2
Finden Sie die Grouper docs hier und die Frequenz - Spezifikationen ( freq=...) hier . Einige Beispiele sind freq=Dfür Tage , freq=Bfür Werktage , freq=Wfür Wochen oder sogar freq=Qfür Viertel .
Kim
10

Eine Lösung, die MultiIndex vermeidet, besteht darin, eine neue zu erstellen datetime Spalteneinstellungstag = 1 Gruppieren Sie dann nach dieser Spalte. Triviales Beispiel unten.

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

Der subtile Vorteil dieser Lösung besteht darin, dass pd.Grouperder Grouper-Index im Gegensatz zum Anfang normalisiert wird eines jeden Monats und nicht zum Ende des Monats Daher können Sie Gruppen einfach extrahieren über get_group:

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

Die Berechnung des letzten Oktobertages ist etwas umständlicher. pd.GrouperAb Version 0.23 wird zwar ein conventionParameter unterstützt, dies gilt jedoch nur für einen PeriodIndexGrouper.

jpp
quelle
7

Etwas alternative Lösung zu @ jpps, aber Ausgabe eines YearMonthStrings:

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
quelle