группа данных pandas по дате и времени месяц

91

Рассмотрим файл 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

Я могу прочитать это и переформатировать столбец даты в формат datetime:

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

Я пытался сгруппировать данные по месяцам. Похоже, должен быть очевидный способ доступа к месяцу и группировки по нему. Но я не могу этого сделать. Кто-нибудь знает как?

В настоящее время я пытаюсь переиндексировать по дате:

b.index=b['date']

Я могу получить доступ к месяцу так:

b.index.month

Однако я, кажется, не могу найти функцию, чтобы объединить в кучу по месяцам.

атомh33ls
источник

Ответы:

175

Удалось это сделать:

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

Или

b.groupby(pd.Grouper(freq='M'))  # update for v0.21+
атомh33ls
источник
52
Я думаю, что более пандоничными способами являются либо использование resample(когда он обеспечивает необходимую вам функциональность), либо использование TimeGrouper:df.groupby(pd.TimeGrouper(freq='M'))
Карл Д.
10
чтобы получить сумму или среднее значение DataFrame, df.groupby(pd.TimeGrouper(freq='M')).sum()илиdf.groupby(pd.TimeGrouper(freq='M')).mean()
Александр
9
pd.TimeGrouperустарел в пользу pd.Grouper, что является немного более гибким, но все же принимает freqи levelаргументы.
BallpointBen
первый метод не работает. Выдает ошибку: «Объект серии не имеет атрибута« месяц »для серии, созданной через to_datetime.
ely
1
@ely Ответ неявно зависит от строк в исходном вопросе, где bпосле чтения из CSV дается индекс. Добавьте b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')после строки b = pd.read_csv('b.dat'). [Я тоже только что редактировал ответ.]
goodside
72

(обновление: 2018)

Обратите внимание, что pd.Timegrouperэто обесценивается и будет удалено. Вместо этого используйте:

 df.groupby(pd.Grouper(freq='M'))
ПандыСкалы
источник
2
Найти документы Группировщика здесь и спецификацию частоты ( freq=...) здесь . Некоторые примеры freq=Dдля дней , в freq=Bтечение рабочих дней , в freq=Wтечение недель или даже freq=Qдля помещений .
Ким
1
Я счел полезным использовать 'key', чтобы избежать переиндексации df, следующим образом: df.groupby (pd.Grouper (key = 'your_date_column', freq = 'M'))
Эдвард
10

Одним из решений, позволяющих избежать MultiIndex, является создание нового datetimeстолбца с настройкой day = 1. Затем сгруппируйте по этому столбцу. Тривиальный пример ниже.

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

Тонкое преимущество этого решения, в отличие от этого, заключается в том, pd.Grouperчто индекс группировщика нормализуется к началу каждого месяца, а не к концу, и поэтому вы можете легко извлекать группы с помощью get_group:

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

Вычислить последний день октября немного сложнее. pd.Grouper, начиная с v0.23, поддерживает conventionпараметр, но это применимо только для PeriodIndexгруппировщика.

jpp
источник
8

Немного альтернативное решение для @ jpp, но с выводом YearMonthстроки:

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()
тсандо
источник