Извлечение только Месяца и Года отдельно от столбца Pandas Datetime

221

У меня есть Dataframe, df, со следующим столбцом:

df['ArrivalDate'] =
...
936   2012-12-31
938   2012-12-29
965   2012-12-31
966   2012-12-31
967   2012-12-31
968   2012-12-31
969   2012-12-31
970   2012-12-29
971   2012-12-31
972   2012-12-29
973   2012-12-29
...

Элементами столбца являются pandas.tslib.Timestamp.

Я хочу просто указать год и месяц. Я думал, что будет простой способ сделать это, но я не могу понять это.

Вот что я попробовал:

df['ArrivalDate'].resample('M', how = 'mean')

Я получил следующую ошибку:

Only valid with DatetimeIndex or PeriodIndex 

Тогда я попробовал:

df['ArrivalDate'].apply(lambda(x):x[:-2])

Я получил следующую ошибку:

'Timestamp' object has no attribute '__getitem__' 

Какие-либо предложения?

Редактировать: я вроде понял это.

df.index = df['ArrivalDate']

Затем я могу пересчитать другой столбец, используя индекс.

Но я все еще хотел бы метод для перенастройки всего столбца. Любые идеи?

monkeybiz7
источник
11
лучший ответ ясно .. df ['mnth_yr'] = df.date_column.dt.to_period ('M'), как показано ниже от @ jaknap32
ihightower
1
Вы даже не должны делать to_period: df.date_column.dt.month(или .year, или .day) работает
elz
2
@elphz: .dt.monthтеряет год, хотя. И .dt.to_period('M')изменяет тип данных на что-то, что больше не является datetime64. В итоге я воспользовался ответом Хуана, предложив .astype('datetime64[M]')усечь значения.
Николай
Можете ли вы изменить лучший ответ?
Гонсало Гарсия

Ответы:

306

Если вы хотите, чтобы новые столбцы отображали год и месяц отдельно, вы можете сделать это:

df['year'] = pd.DatetimeIndex(df['ArrivalDate']).year
df['month'] = pd.DatetimeIndex(df['ArrivalDate']).month

или...

df['year'] = df['ArrivalDate'].dt.year
df['month'] = df['ArrivalDate'].dt.month

Тогда вы можете объединить их или работать с ними, как они есть.

KieranPC
источник
7
Есть ли способ сделать это в одной строке? Я хочу избежать пересечения одного и того же столбца несколько раз.
fixxxer
2
В результате быстрой бенчмаркнг timeitпредполагает , что DatetimeIndexподход значительно быстрее , чем любой .map/.applyили .dt.
Снорфалорпаг
2
лучший ответ ясно .. df ['mnth_yr'] = df.date_column.dt.to_period ('M'), как показано ниже от @ jaknap32
ihightower
что на самом деле делает pd.Datetimeindex?
ДЖОН
Я иногда делаю это: df['date_column_trunc'] = df[date_column'].apply(lambda s: datetime.date(s.year, s.month, 1)
Stewbaca
229

Лучший способ найден !

df['date_column']должно быть в формате дата и время.

df['month_year'] = df['date_column'].dt.to_period('M')

Вы также можете использовать « DДень», « 2M2 месяца» и т. Д. Для разных интервалов выборки, и если у вас есть данные временного ряда с отметкой времени, мы можем выбрать гранулированные интервалы выборки, например, 45Min45 минут, 15Min15 минут выборки и т. Д.

kabrapankaj32
источник
8
Обратите внимание, что полученный столбец больше не относится к datetime64типу dtype. Использование df.my_date_column.astype('datetime64[M]'), как в ответе @ Juan, конвертирует в даты, представляющие первый день каждого месяца.
Николай
3
Я "м удивляйтесь , это все так , как здесь.
Tim
154

Вы можете сразу получить доступ к yearи monthатрибуты, или запросить datetime.datetime:

In [15]: t = pandas.tslib.Timestamp.now()

In [16]: t
Out[16]: Timestamp('2014-08-05 14:49:39.643701', tz=None)

In [17]: t.to_pydatetime() #datetime method is deprecated
Out[17]: datetime.datetime(2014, 8, 5, 14, 49, 39, 643701)

In [18]: t.day
Out[18]: 5

In [19]: t.month
Out[19]: 8

In [20]: t.year
Out[20]: 2014

Один из способов объединить год и месяц - создать целочисленную кодировку, например, 201408на август 2014 года. В целом по столбцу вы можете сделать это следующим образом:

df['YearMonth'] = df['ArrivalDate'].map(lambda x: 100*x.year + x.month)

или много их вариантов.

Однако я не большой поклонник этого, так как это делает выравнивание даты и арифметику болезненными позже и особенно болезненными для тех, кто сталкивается с вашим кодом или данными без этого соглашения. Лучший способ - выбрать соглашение о дне месяца, например, окончательный день недели, кроме выходных, или первый день и т. Д., И оставить данные в формате даты / времени с выбранным соглашением о дате.

calendarМодуль является полезным для получения значения числа определенных дней , таких как окончательный день недели. Тогда вы можете сделать что-то вроде:

import calendar
import datetime
df['AdjustedDateToEndOfMonth'] = df['ArrivalDate'].map(
    lambda x: datetime.datetime(
        x.year,
        x.month,
        max(calendar.monthcalendar(x.year, x.month)[-1][:5])
    )
)

Если вы ищете способ решить более простую проблему простого форматирования столбца datetime в некоторое строковое представление, для этого вы можете просто использовать strftimeфункцию из datetime.datetimeкласса, например так:

In [5]: df
Out[5]: 
            date_time
0 2014-10-17 22:00:03

In [6]: df.date_time
Out[6]: 
0   2014-10-17 22:00:03
Name: date_time, dtype: datetime64[ns]

In [7]: df.date_time.map(lambda x: x.strftime('%Y-%m-%d'))
Out[7]: 
0    2014-10-17
Name: date_time, dtype: object
Ely
источник
4
Производительность может быть плохой, поэтому всегда полезно максимально эффективно использовать вспомогательные функции, векторизованные операции и pandasметоды разделения-применения-объединения. Мои предложения, приведенные выше, не должны восприниматься как подтверждение того, что они являются наиболее эффективными подходами для вашего случая - просто они являются стилистически обоснованными вариантами Pythonic для ряда случаев.
Ely
Ответ @KieranPC, представленный ниже, намного быстрее
Бен
2
лучший ответ ясно .. df ['mnth_yr'] = df.date_column.dt.to_period ('M'), как показано ниже от @ jaknap32
ihightower
2
Вы должны умножить на 100 в df['YearMonth'] = df['ArrivalDate'].map(lambda x: 1000*x.year + x.month).
Git Gud
1
@ zthomas.nc Я думаю, что они лучше работают как два отдельных ответа, так как они предлагают два совершенно разных способа решения.
Ely
34

Если вы хотите уникальную пару месяца и года, используйте apply довольно гладко.

df['mnth_yr'] = df['date_column'].apply(lambda x: x.strftime('%B-%Y')) 

Выводит месяц-год в одну колонку.

Не забудьте сначала поменять формат на дату-время раньше, я вообще забываю.

df['date_column'] = pd.to_datetime(df['date_column'])
kabrapankaj32
источник
Вы также можете избежать лямбда-функции:df['month_year'] = df['date_column'].dt.strftime('%B-%Y')
Rishabh
13

Извлечение слова года из ['2018-03-04']

df['Year'] = pd.DatetimeIndex(df['date']).year  

DF ['Year'] создает новый столбец. Хотя, если вы хотите извлечь месяц, просто используйте .month

Дуглас
источник
1
Спасибо, это было действительно полезно date_1 = pd.DatetimeIndex (df ['date']) --year = date_1.year # Для лет-- --month = date_1.month # Для месяцев-- --dy = date_1. день # В течение дней--
Эдвин Торрес
7

Вы можете сначала преобразовать ваши строки даты с pandas.to_datetime , который дает вам доступ ко всем многочисленным функциям datetime и timedelta . Например:

df['ArrivalDate'] = pandas.to_datetime(df['ArrivalDate'])
df['Month'] = df['ArrivalDate'].values.astype('datetime64[M]')
Хуан А. Наварро
источник
Это сработало очень хорошо для меня, так как я искал функциональность, аналогичную pyspark trunc. Есть ли документация для astype('datetime64[M]')конвенции?
h1-the-swan
6

Благодаря jaknap32 я хотел объединить результаты по годам и месяцам, так что это сработало:

df_join['YearMonth'] = df_join['timestamp'].apply(lambda x:x.strftime('%Y%m'))

Вывод был аккуратным:

0    201108
1    201108
2    201108
Subspacian
источник
6

Решение @ KieranPC является правильным подходом для Pandas, но его нелегко расширить для произвольных атрибутов. Для этого вы можете использовать getattrв генераторе понимание и комбинировать, используя pd.concat:

# input data
list_of_dates = ['2012-12-31', '2012-12-29', '2012-12-30']
df = pd.DataFrame({'ArrivalDate': pd.to_datetime(list_of_dates)})

# define list of attributes required    
L = ['year', 'month', 'day', 'dayofweek', 'dayofyear', 'weekofyear', 'quarter']

# define generator expression of series, one for each attribute
date_gen = (getattr(df['ArrivalDate'].dt, i).rename(i) for i in L)

# concatenate results and join to original dataframe
df = df.join(pd.concat(date_gen, axis=1))

print(df)

  ArrivalDate  year  month  day  dayofweek  dayofyear  weekofyear  quarter
0  2012-12-31  2012     12   31          0        366           1        4
1  2012-12-29  2012     12   29          5        364          52        4
2  2012-12-30  2012     12   30          6        365          52        4
JPP
источник
1
df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])

Это работало хорошо для меня, не думал, что панды будут интерпретировать полученную строковую дату как дату, но когда я делал сюжет, он очень хорошо знал мою повестку дня и строку year_month, где все было упорядочено должным образом ... должен любить панд!

ТИОЗ
источник
1

Существует два шага для извлечения года для всех данных без использования метода apply.

Шаг 1

преобразовать столбец в datetime:

df['ArrivalDate']=pd.to_datetime(df['ArrivalDate'], format='%Y-%m-%d')

Шаг 2

извлечь год или месяц, используя DatetimeIndex()метод

 pd.DatetimeIndex(df['ArrivalDate']).year
Абделла Эль Атуани
источник
1

ОДИНОЧНАЯ ЛИНИЯ: Добавление столбца с парами 'year-month': ('pd.to_datetime' сначала изменяет столбец dtype на date-time перед операцией)

df['yyyy-mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y-%m')

Соответственно для дополнительного столбца «год» или «месяц»:

df['yyyy'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y')

df['mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%m')
Matthi9000
источник