Original size 1140x1600

Анализ данных о покупках путешествий

The project is taking part in the competition

В данном исследовании я проанализировала датасет от Т-Банка, который содержит информацию о бронировании отелей и покупке авиабилетов клиентами

Эта тема близка мне, потому что я сама люблю путешествовать и пользуюсь подобными сервисами на регулярной основе. Мне всегда было интересно, как банки «видят» своих клиентов-путешественников и что на самом деле влияет на решение купить тур: импульс, промокод или тщательное планирование? И насколько эффективны те самые скидки и кэшбэки, которые нам постоянно предлагают.

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

Датасет был найден на сайте Высшей Школы Экономики, подготовленный совместно с Т-Банком.

Для проверки гипотезы я выбрала следующие типы графиков:

1. Гистограмма с логарифмической шкалой (распределение сумм заказов) Она позволяет увидеть форму распределения цен и выявить, как распределены чеки в целом. 2. Столбчатая диаграмма (доля заказов с промо) Позволяет сравнить долю органических и стимулированных покупок. Этот график станет основой для проверки первой части гипотезы. 3. Boxplot (сравнение чеков) Это визуализация вопроса различаются ли чеки? 4. Гистограмма возраста Она показывает возрастную структуру аудитории, что необходимо для сегментации и понимания, какие возрастные группы чаще используют промокоды. 5. Круговая диаграмма (гендерное распределение) Визуализирует гендерный состав клиентов и может помочь выявить различия в поведении мужчин и женщин. 6. Scatter plot (возраст vs сумма заказа) Демонстрирует взаимосвязь между возрастом и размером чека с сегментацией по полу, позволяя выявить, влияет ли возраст на готовность использовать промокоды.

Выбор данных типов визуализаций обоснован необходимостью ответить на три ключевых вопроса:

Действительно ли большинство заказов органические? (столбчатая диаграмма)

Отличаются ли чеки между органикой и промо? (boxplot, scatter plot)

Есть ли сегменты, более восприимчивые к промокодам? (гистограммы, scatter plot)

big
Original size 1568x672

Этап 1. Визуальная стратегия

Перед началом анализа я выбрала визуальную стратегию. Для палитры я использовала тёплую золотисто-жёлтую гамму, которая ассоциируется с путешествиями, солнцем, комфортом и соответсвует айдентике Т-банка

Все графики выполнены в единой стилистике с акцентами шафрановый и пастельно-желтый. Я использовала шрифт Inter Variable за его чистоту, отличную читаемость даже в мелких подписях и современный вид. Это сделало все визуализации аккуратными и целостными.

Основной цвет: #f4c430 (золотистый жёлтый) — используется для основных элементов графиков и привлекает внимание

Акцентный цвет: #fde68a (светлый пастельный жёлтый) — для вторичных элементов, легендов и контраста между группами

Цвет контура: #8c6d1f (тёмно-жёлтый/коричневый) — для границ, линий и деталей

Фон фигур: #fff7e6 (кремовый) — мягкий, теплый фон, не раздражающий глаз

Этап 2. Загрузка и первичная подготовка данных

Работа началась с загрузки датасета в формате CSV. Особое внимание уделено корректной интерпретации форматов данных: файл использует точку с запятой в качестве разделителя и запятую как десятичный разделитель

import pandas as pd import numpy as np

df = pd.read_csv ( «dano_dataset_travel.csv», sep=»;», # разделитель — точка с запятой decimal=»,», # десятичный разделитель — запятая encoding="utf-8», low_memory=False )

pd.set_option («display.max_rows», 200) pd.set_option («display.max_columns», 200)

print («SHAPE:», df.shape) display (df.head ())

Датасет содержит 835 938 строк и 56 столбцов. Все дальнейшие операции выполняются на копии датасета, именуемой eda, что позволяет сохранить исходные данные без изменений.

Этап 2. Создание целевых переменных и первичный анализ

На этом этапе я создала ключевые бинарные переменные для анализа: флаг успешной покупки и флаг использования промо-механик.

Покупка (успешный заказ)

eda['is_purchase'] = eda['order_status_cd'] == 'SUC'

Использование промо

eda['used_promo'] = eda['promo_code_discount_amt'].fillna (0) > 0

Проверка

display ( eda[['is_purchase', 'used_promo']] .apply (lambda x: x.value_counts (normalize=True) * 100) ) is_purchase used_promo False 9.090148 99.076726 True 90.909852 0.923274

Original size 513x188

Эти цифры уже подтверждают основную часть гипотезы: большинство заказов в датасете совершаются органически, без использования промокодов

Далее я более комплексно подготовила данные, используя клиппинг на 99-й перцентиль, исключающий экстремальные значения без потери массива данных и расчет относительных показателей (доля скидки) для нормализации эффекта промокодов и корректного сравнения между заказами разного размера.

import numpy as np import pandas as pd

Копия для EDA

eda = df.copy ()

Приводим datetime

date_cols = [ 'created_dttm', 'book_start_dttm', 'local_book_start_dttm', 'book_end_dttm', 'last_session_dttm' ]

for col in date_cols: eda[col] = pd.to_datetime (eda[col], errors='coerce')

Флаги наличия

eda['has_email'] = eda['last_email_send_dt'].notna () eda['has_free_cancel'] = eda['free_cancel_booking_dttm'].notna ()

Чистка денег (клиппинг)

for col in [ 'nominal_price_rub_amt', 'monthly_income_amt', 'month_beginning_balance_rub' ]: p99 = eda[col].quantile (0.99) eda[col + '_clip'] = eda[col].clip (lower=0, upper=p99)

Доля скидки

eda['discount_share'] = ( eda['promo_code_discount_amt'] / eda['nominal_price_rub_amt'] ).replace ([np.inf, -np.inf], np.nan)

Этап 3. Визуализация 1: Распределение суммы заказа

Первая визуализация демонстрирует распределение сумм заказов с использованием логарифмической шкалы по оси Y.

import matplotlib.pyplot as plt

plt.figure (figsize=(8, 5), facecolor='#fff7e6') plt.hist ( eda['nominal_price_rub_amt_clip'].dropna (), bins=100, log=True, # логарифмическая шкала для лучшей визуализации длинного хвоста color='

f4c430',

основной золотистый цвет edgecolor='

8c6d1f',

тёмная обводка для контрастности alpha=0.85 # небольшая прозрачность ) plt.title ('Распределение суммы заказа (RUB, log scale)', fontsize=13, pad=10) plt.xlabel ('Сумма заказа') plt.ylabel ('Количество заказов (log)') plt.grid (axis='y', linestyle='--', alpha=0.4) plt.show ()

Original size 694x476

Основная масса заказов сосредоточена в диапазоне низких и средних чеков (10–50 тысяч рублей), что указывает на преобладание заказов среднего ценового сегмента. Количество заказов быстро и экспоненциально уменьшается с ростом суммы.

Логарифмическая шкала позволяет одновременно увидеть как массовые (тысячи заказов), так и редкие крупные покупки (единицы или десятки крупных чеков)

Этап 4. Визуализация 2: Доля заказов с промо

На этом графике отображена ключевая статистика для проверки первой части гипотезы: какой процент заказов совершён с использованием маркетинговых стимулов?

promo_share = eda['used_promo'].value_counts (normalize=True) * 100

plt.figure (figsize=(5, 5), facecolor='#fff7e6') plt.bar ( promo_share.index.astype (str), promo_share.values, color='

f4c430',

основной золотистый цвет edgecolor='

8c6d1f',

тёмная обводка alpha=0.9 ) plt.title ('Доля заказов с промо', fontsize=13, pad=10) plt.ylabel ('%') plt.grid (axis='y', linestyle='--', alpha=0.4) plt.show ()

Original size 463x456

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

Этап 5. Визуализация 3: Сравнение чеков (Boxplot)

Boxplot (объясняющий формат) позволяет ответить на ключевой вопрос: различаются ли суммы заказов в зависимости от использования промокодов?

plt.figure (figsize=(7, 5), facecolor='#fff7e6')

Определяем стили элементов boxplot

boxprops = dict (facecolor='

f4c430', color='

8c6d1f') medianprops = dict (color='#8c6d1f', linewidth=2) whiskerprops = dict (color='#8c6d1f') capprops = dict (color='#8c6d1f')

eda.boxplot ( column='nominal_price_rub_amt_clip', by='used_promo', showfliers=False, # скрываем выбросы для наглядности основной массы patch_artist=True, boxprops=boxprops, medianprops=medianprops, whiskerprops=whiskerprops, capprops=capprops )

plt.title ('Чек: промо vs органика', fontsize=13, pad=10) plt.suptitle ('') # удаляем автоматический заголовок plt.xlabel ('Использовался промо') plt.ylabel ('Сумма заказа (RUB)') plt.grid (axis='y', linestyle='--', alpha=0.4) plt.show ()

Original size 605x451

В данной визуализации оранжевая линия внутри ящика — медиана (50-й перцентиль), то есть средний чек для группы. Нижняя граница ящика — 25-й перцентиль (Q1), 25% заказов имеют меньшую сумму. Верхняя граница ящика — 75-й перцентиль (Q3), 75% заказов имеют меньшую сумму. Межквартильный размах (IQR) — высота ящика, показывает разброс для основных 50% данных. «Усы» — линии, показывающие минимальное и максимальное значения без учёта выбросов

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

Межквартильный размах (высота ящика) для обеих групп примерно одинаков, что означает сопоставимую вариативность сумм заказов

Выбросы скрыты для ясности, но их наличие указывает на существование небольшого количества клиентов с нетипичным поведением (как очень крупные, так и очень малые заказы)

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

Этап 6. Визуализация 4: Распределение возраста клиентов

Гистограмма возраста показывает возрастную структуру клиентской базы и помогает выявить, какие возрастные сегменты более активны в путешествиях.

plt.figure (figsize=(8, 5), facecolor='#fff7e6') plt.hist ( eda['age'].dropna (), bins=40, color='

f4c430',

основной золотистый цвет edgecolor='

8c6d1f',

тёмная обводка alpha=0.9 ) plt.title ('Распределение возраста клиентов', fontsize=13, pad=10) plt.xlabel ('Возраст') plt.ylabel ('Количество клиентов') plt.grid (axis='y', linestyle='--', alpha=0.4) plt.show ()

Original size 721x476

Основная масса клиентов сосредоточена в возрастном диапазоне трудоспособного населения (примерно 25–55 лет). Распределение имеет один выраженный пик, что указывает на наличие основного целевого сегмента. Крайние значения (молодые люди до 20 лет и пожилые старше 70) встречаются значительно реже

Этап 7. Визуализация 5: Гендерное распределение

Круговая диаграмма показывает долю мужчин и женщин в датасете путешественников.

gender_share = ( eda['gender_cd'] .value_counts (normalize=True) .mul (100) .round (1) )

plt.figure (figsize=(7, 7), facecolor='#fff7e6') plt.pie ( gender_share.values, labels=gender_share.index, autopct='%1.1f%%', # отображение процентов на срезах startangle=90, colors=['

f4c430', '

fde68a'], # две вариации жёлтого для контраста wedgeprops={'edgecolor': '#8c6d1f', 'linewidth': 1.2}, textprops={'fontsize': 11} ) plt.title ( 'Соотношение мужчин и женщин среди клиентов', fontsize=14, pad=20 ) plt.show ()

Круговые диаграммы наиболее эффективны для отображения долей небольшого количества категорий. Они позволяют интуитивно оценить относительные размеры групп за счёт визуального сравнения площадей секторов. При наличии двух основных групп круговая диаграмма особенно наглядна. Мужская составляющая преобладает в данном случае

Original size 558x601

Этап 8. Визуализация 6: возраст vs сумма заказа (Scatter plot)

Последняя визуализация демонстрирует взаимосвязь между двумя непрерывными переменными (возраст и сумма заказа) с дополнительной сегментацией по полу для выявления гендерных различий.

Из 835 тысяч заказов берём 15 тысяч для предотвращения перегружения графика

sample = eda.dropna (subset=['gender_cd']).sample (15000, random_state=42)

plt.figure (figsize=(10, 6), facecolor='#fff7e6')

for gender, color, label in [ ('M', '

f4c430', 'Male'),

мужчины — насыщенный жёлтый ('F', '

fde68a', 'Female')

женщины — светлый жёлтый ]: subset = sample[sample['gender_cd'] == gender] plt.scatter ( subset['age'], subset['nominal_price_rub_amt_clip'], alpha=0.45, # прозрачность для видения перекрытий и плотности s=30, # размер точек label=label, edgecolors='

8c6d1f'

контур для лучшей видимости )

plt.title ( 'Зависимость суммы заказа от возраста клиента', fontsize=14, pad=15 ) plt.xlabel ('Возраст клиента') plt.ylabel ('Сумма заказа (RUB)') plt.legend (title='Пол') plt.grid (True, linestyle='--', alpha=0.4) plt.show ()

Scatter plot позволяет визуально оценить наличие корреляционной связи между возрастом и суммой заказа. Можно выявить наличие групп клиентов с похожим поведением и отследить нетипичные паттерны.

Original size 876x561

Отсутствие ярко выраженной линейной корреляции между возрастом и суммой заказа указывает на то, что возраст не является основным фактором, определяющим размер среднего чека. Вертикальный разброс точек (большой разброс значений Y при одном значении X) свидетельствует о том, что при одинаковом возрасте клиенты совершают заказы очень различных сумм — от минимальных до максимальных.

Плотность точек выше в возрастном диапазоне 30–50 лет и в диапазоне сумм 20–40 тысяч рублей, что подтверждает результаты предыдущих графиков о целевой аудитории.

Можно сделать вывод, что чек путешественника зависит не столько от его возраста, сколько от других факторов — типа путешествия (отель vs авиабилет), продолжительности поездки, класса предоставляемых услуг и личных предпочтений.

Original size 1568x672

Вывод

Проект демонстрирует, что гипотеза проекта подтверждена: путешественники действительно совершают большинство значимых покупок органически, из внутреннего желания. Промокоды и кэшбэки используются менее чем в 1% случаев, что указывает либо на их низкую эффективность, либо на истинно мотивированность целевой аудитории. Дальнейший анализ мог бы раскрыть, являются ли эти редкие 1% заказов с промо преимущественно от новых клиентов (привлечение) или постоянных клиентов (удержание и увеличение чека).

В ходе выполнения проекта использовалась технология искусственного интеллекта в целях оптимизации процесса обработки, анализа и представления результатов: структурирование и организация исследования, лингвистическое оформление, методологическое консультирование и визуальное оформление.

Perplexity AI: платформа для работы с искусственным интеллектом, модель Sonar [Электронный ресурс] / компания Perplexity Inc. — Режим доступа: https://www.perplexity.ai/ (дата обращения: 20.12.2025).

Krea AI, модель Flux 2 Max [Электронный ресурс] // Krea AI. URL: https://www.krea.ai/ (дата обращения: 23.12.2024).