Прогнозирование авиапассажиропотока между городами РФ

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

Всем привет!

Это моя первая статья на Хабре, поэтому буду рад комментариям, советам, предложениям и любой реакции.

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

Архитектура

В целом, направления делятся на несколько крупных подгрупп, для которых логично использовать разные паттерны в прогнозировании. Так, например, есть курортные направления из Москвы (Сочи, Крым и прочие), по которым спрос хоть и сезонен, но довольно стабилен. Есть курортные направления из регионов, где спрос сильно сезон - банально по той причине, что рейсы выполняются только летом. В целом, поток на курортных направлений сильно зависит от количества гостиниц - нельзя уместить миллион туристов в Сочи за раз, если койко-мест - всего 500 тысяч. Существует также отдельный пул вахтовых направлений - по ним спрос всесезонный, который зависит от экономики вахтового региона. Я счел целесообразным решить на первом этапе задачу кластеризации, где я по пулу факторов попробую разделить направления на кластеры, и только потом - задачу регрессии.

Соответственно, в качестве факторов, влияющих на пассажиропоток, я выбрал следующие:

  • Тип направления: курортное, вахтовое, деловое (между крупными деловыми центрами)

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

  • Расстояние между городами

  • Сезонность

  • Средняя зарплата в городах, население городов, коэффициент мобильности населения и ВРП региона (для выделения вахтовых направлений)

  • Годовой пассажиропоток между городами

Глобально, алгоритм должен выглядеть следующим образом:

Концептуальная схема прогностической модели
Концептуальная схема прогностической модели

Кластеризация

Определим вводные данные для кластеризации:

Признак

Описание

RSC

Круговой сегмент

Var

Месячный к-т вариации

Dist

Расстояние

Temp*

Среднегодовая температура

Population*

Население

Total*

Годовой пассажиропоток чз город

Mobility*

Коэффициент мобильности населения

GRP*

ВРП региона

GRP_per_capita*

ВРП на душу населения в регионе

ZP*

Средняя заработная плата в регионе

* - парные факторы для города вылета и города прилета

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

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

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

from geopy.geocoders import Nominatim
from geopy.distance import geodesic as GD
from math import radians, cos, sin, asin, sqrt 

app = Nominatim(user_agent='myencoder', timeout=5)

cities_for_dist = tdf['Город'].unique()
dist = pd.DataFrame(columns=['Dist'], index=cities_for_dist)

def get_dist(city1='Москва', city2='Санкт-Петербург'):
    
    loc1 = app.geocode(city1).raw
    loc2 = app.geocode(city2).raw
    lat1 = float(loc1['lat'])
    lon1 = float(loc1['lon'])
    lat2 = float(loc2['lat'])
    lon2 = float(loc2['lon'])
    dest = distance_1(lat1, lat2, lon1, lon2)
    return dest

def distance_1(La1, La2, Lo1, Lo2): 
      
    Lo1 = radians(Lo1) 
    Lo2 = radians(Lo2) 
    La1 = radians(La1) 
    La2 = radians(La2) 
       
    # Формула Гаверсинуса
    D_Lo = Lo2 - Lo1 
    D_La = La2 - La1 
    P = sin(D_La / 2)**2 + cos(La1) * cos(La2) * sin(D_Lo / 2)**2 
  
    Q = 2 * asin(sqrt(P)) 
     
    # Радиус земли для расчета расстояния
    R_km = 6371 
       
    # Итоговый результат
    return(Q * R_km)

Алгоритм выполнялся довольно долго - для 400 направлений ушло около 20 минут. Поэтому я сразу сохранил его в csv и в следующих итерациях читал csv-файл с расстояниями. Удивительно, что не возникло проблем с распознаванием таких специфических городов, как Игарка, Талакан и Купол.

Я планировал сформировать около 5-10 кластеров, чтобы выборки в каждом кластере были адекватного (не слишком маленького) размера.

Вводные данные выглядят следующим образом:

Вводные данные для кластеризации
Вводные данные для кластеризации

Далее я решил отобрать оптимальное число кластеров с помощью коэффициент Силуэта, а заодно подобрать гиперпараметр n_init. Ситуация сложилась следующим образом:

Видим, что лучшее число кластеров - 7 штук, при гиперпараметре в n_init равном 2. Хотя коэффициент Силуэта невысокий, этого достаточно, чтобы получить приемлемые результаты. А результаты кластеризации оказались очень интересными.

Кластерная разбивка
Кластерная разбивка

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

Регрессия

Теперь попробуем построить три модели регрессии: RandomForest, GradientBoosting, CatBoost.

В качестве вводных берем следующие факторы:

Признак

Описание

Total

Пассажиропоток на направлении за год

Var

Месячный к-т вариации

Dist

Расстояние

Temp*

Среднегодовая температура

Population*

Население

Total1*

Годовой пассажиропоток чз город

Mobility*

Коэффициент мобильности населения

GRP*

ВРП региона

GRP_per_capita*

ВРП на душу населения в регионе

ZP*

Средняя заработная плата в регионе

Вводные для регрессии выглядят так:

После отбора гиперпараметров, вышли следующие результаты:

Модель/

Метрика

RandomForest Regressor

GradientBoosting Regressor

CatBoost Regressor

R2

0,56

0,45

0,75

MAPE

29,3%

30,0%

53,6%

Видим, что для всех трех моделей и R2, и MAPE оказались не очень качественными, но для дальнейших исследований я оставлю RandomForest и GradientBoosting.

Вывод

Удалось с умеренной точностью прогнозировать пассажиропоток на московских рейсах с ошибкой менее 30%;

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

Рекомендации для себя на будущее я оставил следующие:

  1. Добавить фактор емкостей конкурентов для повышения точности модели

  2. Включить фактор сезонных мероприятий или перевахтовок для крупных городов

  3. Добавить в анализ перемещения между городами в том числе трансферными рейсами

Спасибо за уделенное внимание. Буду рад обратной связи.

Источник: https://habr.com/ru/post/713160/


Интересные статьи

Интересные статьи

Широко известен исторический анекдот о том, что царица Екатерина II писала простое русское слово из 3 букв с 4 ошибками. Куда менее известно, что эта ошибка вовсе не уник...
Идея статьи возникла желании пропускать определенные сайты через VPN-туннель напрямую через маршрутизатор. Так как количество устройств дома велико, а пускать весь трафик...
В первой, второй и третьей частях мои коллеги рассказали, как и почему мы распиливали монолит. Если коротко, то мы создали решение, которое позволило в рамках одной ...
Всем привет. Открыт набор на новый курс от Otus — "Прикладная аналитика на R", который стартует уже в конце этого месяца. В связи с этим хочу поделиться переводом публикации о разнице между анали...
В Челябинске проходят митапы системных администраторов Sysadminka, и на последнем из них я делал доклад о нашем решении для работы приложений на 1С-Битрикс в Kubernetes. Битрикс, Kubernetes, Сep...