група кадрів даних pandas за датою та місяцем


90

Розглянемо файл 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

Однак я, здається, не можу знайти функції, щоб згрупуватись по місяцях.

Відповіді:


174

Вдалося це зробити:

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+

51
Я думаю, що більш пандонічними способами є або використовувати 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

71

(оновлення: 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групера.


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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.