Skip to content

jstnoname/PlaneCostPrediction

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Задача

Научиться предсказывать количество купленных билетов и их классы обслуживание за какое-то время до вылета. Немного изучив данные я пришел к выводу, что в среднем люди покупают билеты за 37.45 дней до рейса. В таком случае поставим задачу как Какое количество билетов будет приобретено за 1 месяц (30 дней) до рейса с учетом класса обслуживания, в таком случае можно будет использовать как статические данные, например время рейса, маршрут, вместимость самолета и тд, так и динамические данные $-$ количество уже приобретенных билетов


Цель проекта

Развить навыки разведочного анализа данных (Exploratory Data Analysis $-$ EDA), обучения модели и работы с современными библиотеками для Data Science и Machine Learning
Научиться работать с популярными библиотеками для ML $-$ pyspark, mlflow


ETL & EDA

Начал работу с поиска таргета. Нашел его в таблице 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'


Modeling & Training

Для оценки моделей использую WAPE и RMSE
Для отслеживания экспериметнов я использовал mlflow, здесь можно посмотреть все результаты моих экспериментов

Baseline

Использовал обычную линейную регрессию, заменил не числовые значения с использованием 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


Improve LR

Использовал линейную регрессию, но сейчас добавил подбор гиперпараметров используя 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%

После подбора гиперпаратеров, модель почти не улучшилась, потому что достигла своего предела. Поэтому перейду к другим методам обучения.


Random Forest

Случайный лес с подбором гиперпараметров через 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%

Такой результат получился из-за нелинейности данного алгоритма, что позволяет искать зависимости между данными лучше, чем простая линейная регрессия


Gradient Boosting

В проекте я реализовал 2 градиентых бустинга из разных библиотек, а именно из pyspark.ml, а второй из lightgbm. Такой выбор был сделан изходя из моей задачи научиться работать со spark, а соответственно и научиться работать при ограниченных ресурсах, по этой причине я решил отказаться от catboost и xgboost так как они требуют больше мощностей и памяти для работы.

PySpark

Использовал 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%
LightGBM

Написал 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%

Models result

Эксперимент в 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 модели для простого использования.

About

Study project for development machine learning skills

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors