Всем привет!

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

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

Архитектура

В целом, направления делятся на несколько крупных подгрупп, для которых логично использовать разные паттерны в прогнозировании. Так, например, есть курортные направления из Москвы (Сочи, Крым и прочие), по которым спрос хоть и сезонен, но довольно стабилен. Есть курортные направления из регионов, где спрос сильно сезонен хотя бы по той причине, что рейсы выполняются только летом. В целом, поток на курортных направлениях сильно зависит от количества гостиниц - нельзя уместить миллион туристов в Сочи за раз, если койко-мест - всего 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. Добавить в анализ перемещения между городами в том числе трансферными рейсами

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

Комментарии (16)


  1. Tzimie
    27.01.2023 09:42
    +1

    А как ваша программа справилась бы с изменением прогноза потоков 21 сентября?


    1. Ulrih
      27.01.2023 10:13
      +2

      и с приграничными областями, где за год ниодного гражданского не пролетело.


    1. konst90
      27.01.2023 19:22

      Можно ли предвидеть непредвиденные обстоятельства?


      1. Tzimie
        27.01.2023 19:55

        Ну, с прошлого года планирование вообще идёт только краткосрочное


    1. tmrslk Автор
      28.01.2023 17:35

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


      1. Tzimie
        28.01.2023 17:45

        ... а у нас стаи черных лебедей...


  1. rehci
    27.01.2023 10:33
    +3

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

    Если ничего не поменялось в плане воровства лизинговых самолетов, то плавное снижение до околонуля? :)


  1. RusikR2D2
    27.01.2023 11:05
    +3

    30% ошибка - это очень и очень много.
    С учетом прогресивной цены на билеты.
    Тот, кто полетит за 5000р (купив билет за месяц) уже не полетит за 25000, купив билет за неделю. Он или полетит другой авиакомпанией, или поедет на поезде или перенсет свою поездку. Аналогично и для тех, кому билет оплачивает компания.
    Теоретический пассажиропоток при цене билетов в 5000р и в 15000р будет разным. - а в вашей моделе цена на билеты вроде вообще никак не заложена.

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


    1. thevlad
      27.01.2023 18:27
      +1

      На самом деле модели надо смотреть, относительно тривиального бэйзлайна, например оптимальной константы. Тогда ясно на сколько улучшается метрика, возможно 30% для начала не так уж и плохо.


    1. tmrslk Автор
      28.01.2023 23:29
      +1

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

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


  1. DS28
    27.01.2023 12:06
    +1

    Классно видеть такую статью, но жаль, что я уже несколько лет не работаю в аэропорту... Вот бы её в 2017 году - может чего совместного придумали))
    Теперь критика.
    Что тут кластеризовать - я не очень понял... Любой, кто хоть немного поработал в пассажирской авиации понимает специфику и назовёт кластеры без анализа: Москва, СПБ, Юг, топ 10 аэропортов, остальные аэропорты (где можно выделить региональную сеть для каждого), вахтовики...
    Расстояния рассчитывать - тоже так себе затея, лучше было получить данные от навигационных служб, ну да ладно, наверняка там своя бюрократия, а данные нужны - кто же сделает лучше, чем сам))

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

    В общем пока статья совсем слабая и малополезная, хотя может чего-то я не понял...
    В любом случае я рад видеть коллегу из авиации на хабре))


    1. tmrslk Автор
      28.01.2023 17:43

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

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

      Про метрики - вы, как человек из авиации, знаете, как много новых направлений закрываются (по моей оценке, для внутренних рейсов таких 40-60%), так и не выполнив одного рейса, либо же не выдерживают даже сезон полетов. Что косвенно и говорит о том, как работает прогнозирование трафика в отрасли))

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


  1. ay11z
    27.01.2023 12:14

    А как с такой большой ошибкой можно заниматься прогнозированием продаж? Либо в компании попустительски относятся к плану? Не стараюсь обидеть или задеть, сам понимаю, что при невыполнении плана продаж весь отдел не увольняют на первый, второй и даже на 10ый раз, но, всё-таки.


    1. tmrslk Автор
      28.01.2023 17:47

      Предсказывать трафик - сложная задача, а количество открытых и потом отмененных рейсов в РФ довольно существенное - около 40-60%. Это косвенно говорит о "качестве" текущего прогнозирования в отрасли. Для новых рейсов в целом сильные отклонения что в плюс, что в минус, могут быть нормой из-за специфики потоков.

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


  1. LevOrdabesov
    27.01.2023 14:49
    +1

    Плюс авансом. Для отдельной статьи всё же коротковато, ИМХО.


    1. tmrslk Автор
      28.01.2023 17:36
      +1

      Спасибо. Да, это мой первый опыт и делился пока тем, что есть промежуточно. Первый блин всегда комом)) Когда закончу этот большой проект, обязательно напишу большую и подробную статью