Научиться предсказывать количество купленных билетов и их классы обслуживание за какое-то время до вылета. Немного
изучив данные я пришел к выводу, что в среднем люди покупают билеты за 37.45 дней до рейса.
В таком случае поставим задачу как Какое количество билетов будет приобретено за 1 месяц (30 дней) до рейса с учетом класса обслуживания, в таком случае можно будет использовать как статические данные, например время рейса, маршрут,
вместимость самолета и тд, так и динамические данные
Развить навыки разведочного анализа данных (Exploratory Data Analysis
Научиться работать с популярными библиотеками для ML
Начал работу с поиска таргета. Нашел его в таблице segments, агрегировал по flight_id и получил, что у меня на 1
рейс приходится количество билетов эконом класса, комфорта и бизнеса.
Для поиска предположительных признаков я нашел в таблицах данные, связанные с flight_id, после агрегировал по этому
аттрибуту. Из flights я взял время вылета по расписанию, из routes город и страну отправления и прибытия, время
полета, массив дней, в которые осуществляются полеты рейса, из таблицы airplanes и seats
взял модели самолета, его дальность полета, скорость и количество мест каждого класса обслуживания. Данные признаки
будут статическими, так как никак не изменяются. Так же я взял количество приобретенных билетов за 30 дней до полета из
таблицы bookings
После исследования не числовых признаков и постороенния матрицы корреляций для числовых я отобрал следующие признаки:
'target_economy', 'target_comfort', 'target_business', 'departure_day', 'departure_day_of_week', 'departure_month', 'is_weekend', 'departure_hour', 'duration_hours', 'count_of_week_routes', 'airplane_range', 'economy', 'comfort', 'business', 'avg_book_lead_time', 's2_book_lead_time', 'count_book_lead_time', 'is_avg_book_lead_time_missing', 'departure_city', 'departure_country', 'arrival_city','arrival_country', 'airplane_model'
Для оценки моделей использую WAPE и RMSE
Для отслеживания экспериметнов я использовал mlflow, здесь
можно посмотреть все результаты моих экспериментов
Использовал обычную линейную регрессию, заменил не числовые значения с использованием StringIndexer, датасет разделил на train и test по времени, 158 дней (27048 рейсов) пошли в train и 53 дня (9504 рейсов) в test.
- Economy RMSE = 54.2271, WAPE = 20.7532%
- Comfort RMSE = 6.6204, WAPE = 26.4353%
- Business RMSE = 7.6883, WAPE = 23.7712%
- Mean RMSE = 22.8452
- Mean WAPE = 23.6532%
при этом WAPE варьируется от 20% до 26%, а RMSE от 6 до 54
Использовал линейную регрессию, но сейчас добавил подбор гиперпараметров используя optuna. Закодировал признаки
используя OneHotEncoding, так же добавил разделение датасета на train, valid и test, доля которых 75%, 12,5% и 12,5%
соответственно
На test получил следующее:
- Economy RMSE = 50.5890, WAPE = 20.5417%
- Comfort RMSE = 6.6964, WAPE = 27.4487%
- Business RMSE = 6.9002, WAPE = 22.7905%
- Mean RMSE = 21.3952
- Mean WAPE = 23.5936%
После подбора гиперпаратеров, модель почти не улучшилась, потому что достигла своего предела. Поэтому перейду к другим методам обучения.
Случайный лес с подбором гиперпараметров через optuna, кодировал признаки только через StringIndexer, так как это
нелинейный алгоритм, поэтому можно не бояться, что модель может решить, что какой-то из признаков важнее другого из-за
замены. Так же я решил убрать колонки месяца и дня вылета, так как для модели в текущей ситуации будет лишь шумом,
потому что модель может выучить данные на первых нескольких месяцев, а после на новый месяцах получить результаты хуже.
На test выборке получил:
- Economy RMSE = 49.6250, WAPE = 15.9136%
- Comfort RMSE = 6.3739, WAPE = 16.2610%
- Business RMSE = 6.5637, WAPE = 16.3135%
- Mean RMSE = 20.8542
- Mean WAPE = 16.1627%
Такой результат получился из-за нелинейности данного алгоритма, что позволяет искать зависимости между данными лучше, чем простая линейная регрессия
В проекте я реализовал 2 градиентых бустинга из разных библиотек, а именно из pyspark.ml, а второй из lightgbm.
Такой выбор был сделан изходя из моей задачи научиться работать со spark, а соответственно и научиться работать при
ограниченных ресурсах, по этой причине я решил отказаться от catboost и xgboost так как они требуют больше мощностей
и памяти для работы.
Использовал GBTRegressor, был сделан pipeline для препроцессинга данных из StringIndexer и VectorAssembler, обучение в
условиях ограниченных ресурсов было достаточно долгим, на обучение 3 моделей было потрачено примерно от 4:30 до 5:30
минут
- Economy RMSE = 58.1342, WAPE = 19.0185%
- Comfort RMSE = 7.2091, WAPE = 17.8356%
- Business RMSE = 8.0508, WAPE = 18.6125%
- Mean RMSE = 24.4647
- Mean WAPE = 18.4889%
Написал 2 кастомных класса. Первый для препроцессинга данных, а второй для сбора 3 независимых моделей в 1, которая будет предсказывать нужный таргет
- Economy RMSE = 49.9189, WAPE = 15.2878%
- Comfort RMSE = 6.0218, WAPE = 15.4044%
- Business RMSE = 6.9611, WAPE = 16.4939%
- Mean RMSE = 20.9673
- Mean WAPE = 15.7287%
| Эксперимент в MLflow | Mean WAPE | Economy WAPE | Comfort WAPE | Business WAPE | Mean RMSE | Time / Optuna trials |
|---|---|---|---|---|---|---|
| 1. Baseline Linear Regression | 23.65% | 20.75% | 26.43% | 23.77% | 22.85 | 3.6 мин / - |
| 2. Improved LR | 23.59% | 20.54% | 27.44% | 22.79% | 21.40 | 10.0 мин / 20 trials |
| 3. PySpark Random Forest | 16.16% | 15.91% | 16.26% | 16.31% | 20.85 | 11.0 мин / 20 trials |
| 4. LightGBM | 15.39% | 15.18% | 14.65% | 16.32% | 20.88 | 12.9 мин / 50 trials |
| 5. PySpark GBTRegressor | 18.49% | 19.02% | 17.84% | 18.61% | 24.46 | 41.7 мин / 10 trials |
По результатам экспериментов лучшей моделью стала LightGBM. Благодоря быстроте построения деревьев получилось задать
достаточно большое пространство для поиска параметров (num_leaves до 1000 и max_depth до 12).В качестве лосса у
модели была выбрана mse, что позволяла сократить большие ошибки модели, а в optuna метрикой была выбрана wape, что
позволило лучше обучить модель под поставленную задачу.
Я разобрался в основал pyspark и mlflow, разобрался в сырых данных из базы данных и построил датасет для будущего
обучения моделей, провел несколько экспериментов и построил рабочий pipeline модели для простого использования.