pandy grupa dataframe według daty i godziny

90

Rozważ plik 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

Mogę to przeczytać i przeformatować kolumnę z datą na format daty i godziny:

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

Próbowałem pogrupować dane według miesięcy. Wygląda na to, że powinien istnieć oczywisty sposób dostępu do miesiąca i grupowania według niego. Ale nie mogę tego zrobić. Czy ktoś wie jak?

To, czego obecnie próbuję, to ponowne indeksowanie według daty:

b.index=b['date']

Mam dostęp do miesiąca w następujący sposób:

b.index.month

Jednak wydaje mi się, że nie mogę znaleźć funkcji, która mogłaby łączyć się w całość według miesiąca.

atomh33ls
źródło

Odpowiedzi:

174

Udało się to zrobić:

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

Lub

b.groupby(pd.Grouper(freq='M'))  # update for v0.21+
atomh33ls
źródło
51
Myślę, że bardziej pandoniczne sposoby to albo użycie resample(gdy zapewnia potrzebną funkcjonalność), albo użycie TimeGrouper:df.groupby(pd.TimeGrouper(freq='M'))
Karl D.
10
aby uzyskać wynik sumę lub średnią DataFrame, df.groupby(pd.TimeGrouper(freq='M')).sum()lubdf.groupby(pd.TimeGrouper(freq='M')).mean()
Alexandre
9
pd.TimeGrouperzostał uznany za przestarzały na korzyść pd.Grouper, który jest nieco bardziej elastyczny, ale nadal przyjmuje freqi levelargumentuje.
BallpointBen
pierwsza metoda wydaje się nie działać. Daje błąd „Obiekt serii nie ma atrybutu„ miesiąc ”” dla serii utworzonej za pośrednictwem to_datetime.
ely
1
@ely Odpowiedź niejawnie opiera się na wierszach z pierwotnego pytania, w których bpo odczytaniu z pliku CSV nadawany jest indeks. Dodaj b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')po linii b = pd.read_csv('b.dat'). [Właśnie zredagowałem odpowiedź.]
goodside
71

(aktualizacja: 2018)

Pamiętaj, że pd.Timegrouperjest to amortyzowane i zostanie usunięte. Użyj zamiast tego:

 df.groupby(pd.Grouper(freq='M'))
PandasRocks
źródło
2
Znajdź dokumentację Grouper tutaj i specyfikacje częstotliwości ( freq=...) tutaj . Niektóre przykłady są freq=Dza dni , freq=Bza dni roboczych , freq=Wdla tygodni lub nawet freq=Qna kwartały .
Kim,
1
Uważam, że przydatne jest użycie `` klucza '', aby uniknąć konieczności ponownego zindeksowania df, w następujący sposób: df.groupby (pd.Grouper (key = 'your_date_column', freq = 'M'))
Edward
10

Jednym z rozwiązań pozwalających uniknąć MultiIndex jest utworzenie nowej datetimekolumny ustawiania dnia = 1. Następnie pogrupuj według tej kolumny. Trywialny przykład poniżej.

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

Subtelną zaletą tego rozwiązania jest w przeciwieństwie do tego pd.Grouper, że indeks groupera jest normalizowany do początku każdego miesiąca, a nie do końca, dlatego można łatwo wyodrębnić grupy za pomocą get_group:

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

Obliczenie ostatniego dnia października jest nieco bardziej kłopotliwe. pd.Grouperod wersji 0.23 obsługuje conventionparametr, ale ma to zastosowanie tylko do PeriodIndexgroupera.

jpp
źródło
8

Nieco alternatywne rozwiązanie dla @ jpp, ale wyprowadzanie YearMonthciągu:

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
źródło