Jak pogrupować wpisy DataFrame pandy według daty w nieunikalnej kolumnie

82

Pandy DataFramezawiera kolumnę o nazwie, "date"która zawiera nieunikalne datetimewartości. Mogę pogrupować linie w tej ramce za pomocą:

data.groupby(data['date'])

Jednak powoduje to podział danych według datetimewartości. Chciałbym pogrupować te dane według roku zapisanego w kolumnie „data”. Ta strona pokazuje, jak grupować według roku w przypadkach, gdy znacznik czasu jest używany jako indeks, co nie jest prawdą w moim przypadku.

Jak osiągnąć to grupowanie?

Boris Gorelik
źródło
Dla tych, którzy przyjeżdżają tutaj w roku 2017+, istnieje kilka nowych sposobów na grupowanie według określonego czasu. Zobacz tę odpowiedź poniżej
Ted Petrou

Odpowiedzi:

91

Używam pand 0.16.2. Ma to lepszą wydajność w moim dużym zestawie danych:

data.groupby(data.date.dt.year)

Korzystanie z dtopcji i zabawy z weekofyear, dayofweekitd. Staje się o wiele łatwiejsze.

DACW
źródło
Wydaje się, że jest to pandaiczny sposób uzyskiwania dostępu do atrybutów dat dla serii.
taniec
74

rozwiązanie ecatmur będzie działać dobrze. Będzie to jednak lepsza wydajność w przypadku dużych zbiorów danych:

data.groupby(data['date'].map(lambda x: x.year))
Wes McKinney
źródło
9
Dlaczego mapować zamiast aplikować?
Gus,
1
Afaik, mapzwykle ma dobre cechy wydajnościowe przy stosowaniu dowolnych funkcji w porównaniu do zwykłego używania apply.
Coolio2654
25

Może to być łatwiejsze do wyjaśnienia za pomocą przykładowego zbioru danych.

Utwórz przykładowe dane

Załóżmy, że mamy jedną kolumnę znaczniki czasu, datea inną kolumnę chcielibyśmy przeprowadzić na agregację, a.

df = pd.DataFrame({'date':pd.DatetimeIndex(['2012-1-1', '2012-6-1', '2015-1-1', '2015-2-1', '2015-3-1']),
                   'a':[9,5,1,2,3]}, columns=['date', 'a'])

df

        date  a
0 2012-01-01  9
1 2012-06-01  5
2 2015-01-01  1
3 2015-02-01  2
4 2015-03-01  3

Istnieje kilka sposobów grupowania według roku

  • Użyj akcesorium dt z yearwłaściwością
  • Wprowadź dateindeks i użyj funkcji anonimowej, aby uzyskać dostęp do roku
  • Użyj resamplemetody
  • Konwertuj na okres pandy

.dtakcesor z yearwłasnością

Gdy masz kolumnę (a nie indeks) sygnatur czasowych pand, możesz uzyskać dostęp do wielu dodatkowych właściwości i metod za pomocą dtakcesorium. Na przykład:

df['date'].dt.year

0    2012
1    2012
2    2015
3    2015
4    2015
Name: date, dtype: int64

Możemy użyć tego do utworzenia naszych grup i obliczenia niektórych agregacji w określonej kolumnie:

df.groupby(df['date'].dt.year)['a'].agg(['sum', 'mean', 'max'])

      sum  mean  max
date                
2012   14     7    9
2015    6     2    3

wstaw datę do indeksu i użyj funkcji anonimowej, aby uzyskać dostęp do roku

Jeśli ustawisz kolumnę daty jako indeks, stanie się ona DateTimeIndex z tymi samymi właściwościami i metodami, jak metoda dtakcesora, która daje normalne kolumny

df1 = df.set_index('date')
df1.index.year

Int64Index([2012, 2012, 2015, 2015, 2015], dtype='int64', name='date')

Co ciekawe, korzystając z metody groupby, możesz przekazać jej funkcję. Ta funkcja zostanie niejawnie przekazana do indeksu DataFrame. Tak więc możemy uzyskać ten sam wynik z góry, wykonując następujące czynności:

df1.groupby(lambda x: x.year)['a'].agg(['sum', 'mean', 'max'])

      sum  mean  max
2012   14     7    9
2015    6     2    3

Użyj resamplemetody

Jeśli Twoja kolumna daty nie znajduje się w indeksie, musisz określić kolumnę za pomocą onparametru. Musisz również określić alias przesunięcia jako ciąg.

df.resample('AS', on='date')['a'].agg(['sum', 'mean', 'max'])

             sum  mean  max
date                       
2012-01-01  14.0   7.0  9.0
2013-01-01   NaN   NaN  NaN
2014-01-01   NaN   NaN  NaN
2015-01-01   6.0   2.0  3.0

Konwertuj na okres pandy

Możesz także przekonwertować kolumnę daty na obiekt Pandy Period. Musimy przekazać alias przesunięcia jako ciąg znaków, aby określić długość okresu.

df['date'].dt.to_period('A')

0   2012
1   2012
2   2015
3   2015
4   2015
Name: date, dtype: object

Następnie możemy użyć tego jako grupy

df.groupby(df['date'].dt.to_period('Y'))['a'].agg(['sum', 'mean', 'max'])


      sum  mean  max
2012   14     7    9
2015    6     2    3
Ted Petrou
źródło
W ostatniej metodzie, w której używasz to_period('A'), po co to („A”)?
shiv_90,
2
@ Shiv_90 the 'A'is a timeseries offset-alias: pandas.pydata.org/pandas-docs/stable/...
ptim
Którą metodę poleciłbyś, jeśli trzeba również zapisać oddzielną kolumnę „data”? Na przykład, jeśli uruchomię prostą .dt.yearmetodę i zapiszę ją w nowej ramce danych, daty zostaną zapisane jako indeksy i stanie się to problematyczne, jeśli powiem, że muszę wykreślić dane, ponieważ tak naprawdę nie ma kolumny `` daty '', ale tylko trzy dostarczone w.agg()
shiv_90,
13

To powinno działać:

data.groupby(lambda x: data['date'][x].year)
ecatmur
źródło
0

to też zadziała

data.groupby(data['date'].dt.year)

Chetan Kabra
źródło
Powinien działać, ale po wykonaniu wyświetla lokalizację obiektu w pamięci, ale nie ma rzeczywistego wyniku. <pandas.core.groupby.DataFrameGroupBy object at 0x10d7f6438>jest tym, co otrzymuję po egzekucji.
shiv_90