Библиотека Pandas — это весьма эффективный инструмент для обработки данных, представляющих собой временные ряды. На самом деле, эта библиотека была создана Уэсом МакКинни для работы с финансовыми данными, которые состоят, главным образом, из временных рядов.
При работе с временными рядами много сил уходит на выполнение различных операций с датой и временем. Этот материал посвящён ответам на четыре распространённых вопроса из данной сферы.
Возможно, вы уже сталкивались с этими вопросами. Ответить на все из них, кроме последнего, можно сравнительно просто. А вот ответ на последний, довольно-таки хитрый вопрос, представляет собой последовательность из нескольких действий.
Начнём с создания учебного датафрейма (объекта DataFrame
), с которым будем экспериментировать:
df = pd.DataFrame({
"booking_id": [1001, 1002, 1003, 1004, 1005],
"property" : ["A", "A", "B", "B", "C"],
"created_at": ["2022-03-01", "2022-02-10", "2022-04-12",
"2022-04-11", "2022-06-05"],
"checkin_date": ["2022-06-01", "2022-06-10", "2022-06-02",
"2022-06-20", "2022-08-10"],
"checkout_date": ["2022-06-06", "2022-06-15",
"2022-06-06","2022-06-28", "2022-08-16"],
"amount": [5400, 5600, 4800, 9000, 6500]
})
# изменение типа данных
date_cols = ["created_at","checkin_date","checkout_date"]
df[date_cols] = df[date_cols].astype("datetime64[ns]")
# вывод объекта DataFrame
df
Для того чтобы у нас была бы возможность пользоваться функциями pandas, предназначенными для работы с датой и временем, даты в датафрейме должны быть представлены значениями подходящего типа данных. Именно по этой причине мы поменяли тип данных соответствующих столбцов на datetime64[ns]
.
1. Как извлечь из даты информацию о месяце и годе?
Дата содержит различные фрагменты информации, такие как год, день недели, месяц и так далее. Все эти фрагменты можно извлечь из даты с использованием методов, к которым обращаются через аксессор dt
.
Например, месяц можно получить с помощью метода month
. А как получить сведения о годе и месяце в формате ГГГГ-ММ
? Ответ на этот вопрос уже не так очевиден. Извлечь эти сведения из даты можно, прибегнув к методу to_period
:
# создание столбца year_month
df["year_month"] = df["created_at"].dt.to_period("M")
# вывод объекта DataFrame
df
2. Как прибавить к дате временной интервал?
Прибавление к датам временных интервалов или вычитание их из дат — это одна из операций, часто встречающихся при работе с датами. Выполнить её можно, воспользовавшись функцией DateOffset
.
Добавим 1 день к дате выселения (например — из некоего объекта недвижимости) (checkout_date
) для записи о бронировании с идентификатором 1001
:
df.loc[df["booking_id"]==1001, "checkout_date"] = \
df.loc[df["booking_id"]==1001, "checkout_date"] + \
pd.DateOffset(days=1)
# проверка результата
print(df.loc[df["booking_id"]==1001, "checkout_date"])
# вывод
0 2022-06-07
Name: checkout_date, dtype: datetime64[ns]
3. Как найти интервал в днях между двумя датами?
Интервал между двумя датами можно найти, вычтя одну из другой. Результатом этой операции будет объект Timedelta
, а это не совсем то, что нам нужно:
df["checkout_date"][0] - df["checkin_date"][0]
# вывод
Timedelta('6 days 00:00:00')
Получить разницу между датами в днях, в виде целого числа, можно, воспользовавшись атрибутом days
. Создадим столбец, который выводит разницу в днях между датой вселения (checkin_date
) и датой создания бронирования (created_at
):
# разница, выраженная в днях
df["days_to_checkin"] = \
(df["checkin_date"] - df["created_at"]).dt.days
# вывод объекта DataFrame
df
4. Как сформировать последовательность дат между начальной и конечной датами?
Предположим, нам нужен календарь, который показывает дни, в которые объект недвижимости забронирован. Сейчас в первой строке датафрейма есть запись о том, что объект недвижимости A
забронирован с 2022–06–01
по 2022–06–07
. Получается, что объект A
забронирован на даты 2022–06–01
, 2022–06–02
, 2022–06–03
, 2022–06–04
, 2022–06–05
, 2022–06–06
(если предположить, что постоялец выселяется в 10 утра 2022–06–07
).
Такой календарь можно создать, найдя даты между датами вселения и выселения и внеся их в объект DataFrame
.
Для начала создадим датафрейм calendar
, содержащий столбцы property
, checkin_date
и checkout_date
:
# создание объекта DataFrame calendar
calendar = df[["property","checkin_date","checkout_date"]]
Функция date_range
даёт нам даты, находящиеся между начальной и конечной датами. Вот что получится для первой записи о бронировании:
pd.date_range(calendar["checkin_date"][0], calendar["checkout_date"][0])
# вывод
DatetimeIndex(['2022-06-01', '2022-06-02', '2022-06-03',
'2022-06-04', '2022-06-05', '2022-06-06',
'2022-06-07'],
dtype='datetime64[ns]', freq='D')
Тут есть одна проблема: нам не нужно, чтобы дата выселения (checkout_date
) была бы показана как дата, когда объект недвижимости забронирован. Поэтому мы, прежде чем находить диапазон дат, вычтем 1 из даты выселения.
Для того чтобы сделать это для всех строк, нужно воспользоваться функцией apply
. Мы, кроме того, конвертируем вывод функции date_range
в список, воспользовавшись конструктором list
:
# создание столбца booked_days
calendar.loc[:, "booked_days"] = calendar.apply(
lambda x: list(
pd.date_range(
x.checkin_date,
x.checkout_date - pd.DateOffset(days=1)
).date
),
axis = 1
)
# вывод объекта DataFrame
calendar
Далее — нам нужно заполнить датафрейм, развернув даты из столбца booked_days
. В этом нам поможет функция explode
:
# функция explode
calendar = calendar.explode(
column="booked_days", ignore_index=True
)[["property","booked_days"]]
# вывод первых 5 строк
calendar.head()
Теперь у нас имеется календарь дней, в которые объект недвижимости забронирован.
Итоги
Мы нашли ответы на 4 вопроса, решили 4 задачи, с которыми вы, скорее всего, столкнётесь, работая с временными рядами, содержащими даты. Надеемся, вам пригодится то, о чём вы сегодня узнали.
О, а приходите к нам работать? ? ?
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.