Вилучення лише місяця та року окремо зі стовпця Pandas Datetime


246

У мене є 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']

Потім я можу зробити вибірку іншого стовпця, використовуючи індекс.

Але я все-таки хотів би метод перенастроювання всього стовпця. Будь-які ідеї?


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]')усікати значення.
Ніколай

Чи можете ви змінити найкращу відповідь?
Гонсало Гарсія,

Відповіді:


347

Якщо ви хочете, щоб нові стовпці відображали рік і місяць окремо, ви можете зробити це:

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

Тоді ви можете комбінувати їх або працювати з ними такими, якими вони є.


9
Чи є спосіб зробити це в один рядок? Я хочу уникнути обходу однієї і тієї ж колонки кілька разів.
fixxxer

2
Деякі швидкі тести з timeitприпускають, що DatetimeIndexпідхід значно швидший, ніж будь-який .map/.applyабо .dt.
Snorfalorpagus

2
найкраща відповідь чітко .. df ['mnth_yr'] = df.date_column.dt.to_period ('M'), як показано нижче від @ jaknap32
ihightower

1
що насправді робить pd.Datetimeindex?
ДЖОН

1
Я іноді роблю так: df['date_column_trunc'] = df[date_column'].apply(lambda s: datetime.date(s.year, s.month, 1)
Stewbaca

247

Найкращий спосіб знайдений !!

df['date_column']має бути в форматі дата і час.

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

Ви також можете використовувати Dдля дня, 2Mпротягом 2 місяців тощо для різних інтервалів вибірки, і якщо у вас є дані часових рядів із позначкою часу, ми можемо скористатися детальними інтервалами вибірки, такими як 45Min45 хв, 15Min15 хв вибірки тощо.


8
Зверніть увагу, що отриманий стовпець більше не є datetime64dtype. Використовуючи df.my_date_column.astype('datetime64[M]'), як у відповіді @ Juan, перетворюється на дати, що представляють перший день кожного місяця.
Ніколай

155

Ви можете безпосередньо отримати доступ до атрибутів yearand 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

4
Продуктивність може бути поганою, тому завжди добре використовувати якнайкраще допоміжні функції, векторизовані операції та pandas методи розділення-застосування-комбінування. Мої наведені вище пропозиції не повинні сприйматися як підтвердження того, що вони є найбільш ефективними підходами для вашої справи - просто те, що вони є стилістично обґрунтованими пітонічними виборами для ряду випадків.
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).
Гіт Гуд

1
@ zthomas.nc Я думаю, що вони функціонують краще як дві окремі відповіді, оскільки вони пропонують два дуже різні способи її вирішення.
Елі

35

Якщо ви хочете унікальну пару місяця року, використання apply досить гладке.

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

Результати за місяць-рік в одній колонці.

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

df['date_column'] = pd.to_datetime(df['date_column'])

2
Ви також можете уникнути лямбда-функції:df['month_year'] = df['date_column'].dt.strftime('%B-%Y')
Рішаб

14

Витяг року сказати з ['2018-03-04']

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

Df ['Рік'] створює новий стовпець. Якщо ви хочете витягти місяць, просто використовуйте .month


1
Дякуємо, це було дуже корисно date_1 = pd.DatetimeIndex (df ['date']) --year = date_1.year # Протягом років-- --month = date_1.month # Протягом місяців-- --dy = date_1. день # По днях
Едвін Торрес

7

Ви можете спочатку перетворити свої рядки дат за допомогою pandas.to_datetime , який надає вам доступ до всіх функцій numpy 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

7

Рішення @ 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

6

Завдяки jaknap32 я хотів узагальнити результати відповідно до року та місяця, тож це спрацювало:

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

Результат був акуратним:

0    201108
1    201108
2    201108

5

ОДИН РЯД: Додавання стовпця з парами "рік-місяць": ("pd.to_datetime" спочатку змінює тип d стовпця на дату-час перед операцією)

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


Це саме те, що я хочу. Дякую,!
Ерол Ердоган,

1
.dt.strftime ('% Y-% m') неймовірно повільний, особливо на мільйонах записів, порівняно з нарізанням та додаванням, як у .dt.year + "-" + .dt.month
Vitalis

Добре, це корисне розуміння. Я використовував його для деяких файлів із 100000 рядків, і у нього все було чудово, але це корисна альтернатива.
Matthi9000

1
df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])

Це добре спрацювало для мене, не думав, що панди будуть інтерпретувати результуючу дату рядка як дату, але коли я складав змову, він добре знав мій порядок денний та рядок year_month, де правильно замовлено ... повинен любити панд!


1

Існує два етапи, щоб витягти рік для всього кадру даних без використання методу.

Крок 1

перетворити стовпець на datetime:

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

Крок 2

витягніть рік або місяць DatetimeIndex()методом

 pd.DatetimeIndex(df['ArrivalDate']).year
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.