Собесов

Aviasales Booking — динамика профита и доли услуг в обороте

Кейсы и метрикиПродуктовая аналитикаСредняяMiddle

Условие

По датасету Aviasales-Booking (order_id, order_price, service, service_price, service_profit, origin_country, destination_country, order_platform, booking_depth, is_return, adults, children, order_date) ответьте:

  1. Визуализируйте динамику профита, оборота и доли профита от оборота по заказам с услугами. Опишите распределения и сделайте выводы.
  2. Сравните распределения цен заказов в зависимости от платформыdesktop, ios, android. Сделайте выводы.
  3. Проанализируйте зависимость глубины бронирования от цены.
  4. Найдите ещё 2–3 интересные взаимосвязи между переменными в датасете.

Решение

Подготовка

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
 
df = pd.read_csv("booking_analytics_test_df.csv", parse_dates=["order_date"])
df["month"] = df["order_date"].dt.to_period("M").dt.to_timestamp()
df["profit_share"] = df["service_profit"] / df["order_price"]

Вопрос 3. Динамика профита, оборота, доли

monthly = df.groupby("month").agg(
    revenue=("order_price", "sum"),
    services_revenue=("service_price", "sum"),
    services_profit=("service_profit", "sum"),
    orders=("order_id", "nunique"),
).reset_index()
 
monthly["profit_to_gmv"] = monthly["services_profit"] / monthly["revenue"]
 
fig, axes = plt.subplots(3, 1, figsize=(10, 9), sharex=True)
axes[0].plot(monthly["month"], monthly["revenue"], marker="o")
axes[0].set_title("Оборот (GMV) по месяцам")
axes[1].plot(monthly["month"], monthly["services_profit"], marker="o", color="green")
axes[1].set_title("Профит по услугам")
axes[2].plot(monthly["month"], monthly["profit_to_gmv"], marker="o", color="orange")
axes[2].set_title("Доля профита по услугам в GMV")
plt.tight_layout()

Что искать:

  • Параллельный рост GMV и services_profit — здоровый рост. Если GMV растёт, а profit нет — апсейл услуг падает.
  • Доля profit в GMV — ключевой sanity-индикатор. Стабильна 0.5–2% → норм. Падение — проблема монетизации.
  • Сезонность отпусков (июнь-август, январь, новогодние) часто даёт пик GMV, но более слабый пик profit (туристы покупают больше билетов, но не доп. услуги).
  • Структурные сдвиги — выпуск новой услуги, отмена страховки.

Вопрос 4. Распределение цен по платформе

fig, ax = plt.subplots(figsize=(10, 5))
sns.violinplot(
    data=df, x="order_platform", y="order_price",
    inner="quartile", cut=0, ax=ax,
)
ax.set_yscale("log")
ax.set_title("Распределение цены заказа по платформе (log)")

И табличка:

df.groupby("order_platform")["order_price"].describe(percentiles=[.25, .5, .75, .9])

Типичные выводы:

  • desktop — широкий диапазон, длинный правый хвост; покупают business и семейные маршруты с высокой ценой.
  • ios — выше медианы и mean (платежеспособные пользователи).
  • android — медианы ниже, концентрация в low-cost.

Гипотеза: десктоп выбирают для серьёзной покупки (планирование, длинные поездки), мобайл — для импульсных или коротких. Проверка:

df.groupby("order_platform")["booking_depth"].median()

Если на desktop медианная глубина 30–60 дней, а на mobile 7–14 — гипотеза подтверждается.

Вопрос 5. Зависимость глубины бронирования от цены

sns.scatterplot(data=df.sample(2000, random_state=1), x="booking_depth", y="order_price", alpha=0.3)
plt.xscale("log"); plt.yscale("log")
plt.title("Booking depth vs Order price (log–log)")

Лучше — биннинг и средние:

df["depth_bin"] = pd.qcut(df["booking_depth"], 10, duplicates="drop")
agg = df.groupby("depth_bin")["order_price"].agg(["mean", "median", "count"])
print(agg)

И корреляция Спирмена (нелинейная зависимость):

from scipy.stats import spearmanr
r, p = spearmanr(df["booking_depth"], df["order_price"])
print(f"Spearman r = {r:.3f}, p = {p:.2e}")

Что обычно видно:

  • Корреляция положительная: чем дальше до поездки, тем дороже билет (планирование за полгода — длинные/международные перелёты).
  • Хвост низкой глубины (<7 дней) — last-minute, могут быть и дешёвыми (недогруз) и дорогими (срочные перелёты).
  • Локальный минимум на ~30–60 дней — оптимальный horizon покупки (общеизвестный факт авиаиндустрии).

Вопрос 6. Доп. инсайты

Несколько направлений для копания:

a) is_return × order_price

df.groupby("is_return")["order_price"].agg(["mean", "median", "count"])

Round-trip почти всегда дороже one-way, но не в 2 раза — авиакомпании дают скидку за обратный.

b) Профит услуг по странам назначения

top10_dest = (df.groupby("destination_country")["service_profit"]
                .sum().sort_values(ascending=False).head(10))
top10_dest.plot(kind="barh")

Часто страны-курорты (TR, AE, EG) дают повышенный профит — туристы покупают страховки и ассистанс.

c) service × платформа: какие услуги покупают на чём

pd.crosstab(df["service"], df["order_platform"], normalize="columns") * 100

Например, notification на mobile может быть выше, чем на desktop (push-уведомления нативны).

d) Доля заказов с детьми и средний чек

df["has_children"] = df["children"] > 0
df.groupby("has_children")["order_price"].agg(["mean", "median", "count"])

С детьми обычно дороже (длиннее поездка, больше пассажиров, страховка обязательна).

Подводные камни

  1. Ось Y — log. Цены билетов имеют тяжёлый хвост (лонгхол / бизнес). Без log все графики «прижимаются» к нулю.
  2. Сглаживание динамики. Один месяц — шум; считайте 3-месячный rolling average для чистого тренда.
  3. profit_share per-order vs aggregate. df["profit_share"].mean()df["profit"].sum() / df["price"].sum(). Для бизнеса — второе, потому что взвешено по выручке.
  4. Корреляция ≠ причинность. «Глубина → цена» можно интерпретировать наоборот (дешёвые билеты быстро разлетаются, и за месяц до вылета остаются только дорогие).
  5. Платформа не=пользователь. Один и тот же человек смотрит на десктопе, покупает с iPhone. Платформа — это последний касание, а не профиль клиента.
  6. booking_depth = 0 — это покупка в день вылета? Может быть и баг данных.
  7. Сезонные кампании. Если в апреле была большая распродажа — графика покажет пик, но это не «продуктовый» рост.

Эталонный ответ

Структура отчёта:

  1. Динамика: GMV, профит, profit/GMV — три линии. Главный вывод: «доля профита стабильна на 1.4±0.2%, аномалий нет».
  2. Платформы: на iOS медианная цена выше desktop в 1.3×, hypothesis — premium-сегмент.
  3. Глубина → цена: Spearman ≈ +0.2, локальный минимум на 30–60 дней.
  4. Доп.: обратные билеты в 1.7× дороже, курортные страны дают +30% к профиту услуг, на mobile апсейл notification выше.

Каждый вывод — с числом, а не «выглядит как растёт».

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти