Библиотека 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
Столбец year_month в датафрейме
Столбец year_month в датафрейме

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
Столбец days_to_checkin в датафрейме
Столбец days_to_checkin в датафрейме

4. Как сформировать последовательность дат между начальной и конечной датами?

Предположим, нам нужен календарь, который показывает дни, в которые объект недвижимости забронирован. Сейчас в первой строке датафрейма есть запись о том, что объект недвижимости A забронирован с 2022–06–01 по 2022–06–07. Получается, что объект A забронирован на даты 2022–06–012022–06–022022–06–032022–06–042022–06–052022–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 в датафрейме
Столбец booked_days в датафрейме

Далее — нам нужно заполнить датафрейм, развернув даты из столбца booked_days. В этом нам поможет функция explode:

# функция explode 
calendar = calendar.explode(
    column="booked_days", ignore_index=True
)[["property","booked_days"]]
# вывод первых 5 строк
calendar.head()
Первые 5 строк календаря
Первые 5 строк календаря

Теперь у нас имеется календарь дней, в которые объект недвижимости забронирован.

Итоги

Мы нашли ответы на 4 вопроса, решили 4 задачи, с которыми вы, скорее всего, столкнётесь, работая с временными рядами, содержащими даты. Надеемся, вам пригодится то, о чём вы сегодня узнали.

О, а приходите к нам работать? ???? ????

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Присоединяйтесь к нашей команде.

Комментарии (0)