Всем привет!
Это моя первая статья на Хабре, поэтому буду рад комментариям, советам, предложениям и любой реакции.
Я работаю в авиакомпании, занимаюсь анализом продаж, что сильно связано в том числе с планированием и прогнозированием. В условиях, когда российский рынок авиаперевозок сужается, авиакомпании стремятся оптимизировать свою маршрутную сеть, а если и развиваться - то только на направлениях с высоким пассажиропотоком. Дефицит самолетов в условиях санкций делает ошибки непростительными, поэтому своей целью я ставил разработку модели прогнозирования трафика между городами РФ.
Архитектура
В целом, направления делятся на несколько крупных подгрупп, для которых логично использовать разные паттерны в прогнозировании. Так, например, есть курортные направления из Москвы (Сочи, Крым и прочие), по которым спрос хоть и сезонен, но довольно стабилен. Есть курортные направления из регионов, где спрос сильно сезонен хотя бы по той причине, что рейсы выполняются только летом. В целом, поток на курортных направлениях сильно зависит от количества гостиниц - нельзя уместить миллион туристов в Сочи за раз, если койко-мест - всего 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%;
Решение задачи кластеризации позволило осуществить качественное разделение рейсов по подгруппам, что может быть использовано в авиакомпаниях для упрощения анализа и группировки данных.
Рекомендации для себя на будущее я оставил следующие:
Добавить фактор емкостей конкурентов для повышения точности модели
Включить фактор сезонных мероприятий или перевахтовок для крупных городов
Добавить в анализ перемещения между городами в том числе трансферными рейсами
Спасибо за уделенное внимание. Буду рад обратной связи.
Комментарии (16)
rehci
27.01.2023 10:33+3Прогнозирование авиапассажиропотока между городами РФ
Если ничего не поменялось в плане воровства лизинговых самолетов, то плавное снижение до околонуля? :)
RusikR2D2
27.01.2023 11:05+330% ошибка - это очень и очень много.
С учетом прогресивной цены на билеты.
Тот, кто полетит за 5000р (купив билет за месяц) уже не полетит за 25000, купив билет за неделю. Он или полетит другой авиакомпанией, или поедет на поезде или перенсет свою поездку. Аналогично и для тех, кому билет оплачивает компания.
Теоретический пассажиропоток при цене билетов в 5000р и в 15000р будет разным. - а в вашей моделе цена на билеты вроде вообще никак не заложена.А теоретическое расстояние между городами кажется совсем нереальным - рейс Сочи-Москва летит теперь совсем не по прямой, даже не близко. Да и в обычное время самолеты не по прямой летают.
thevlad
27.01.2023 18:27+1На самом деле модели надо смотреть, относительно тривиального бэйзлайна, например оптимальной константы. Тогда ясно на сколько улучшается метрика, возможно 30% для начала не так уж и плохо.
tmrslk Автор
28.01.2023 23:29+1Да, тарифная составляющая - очень важная. Я хочу попробовать встроить фактор наподобие средней стоимости поездки или средняя стоимость километра полета на направлении. Пока думаю: как, где и откуда вытащить эти данные.
Тем не менее, по опыту могу сказать, что «пустыми» авиакомпании стараются не летать, поэтому готовы опускаться в тарифе до уровня хорошей загрузки (не все случаи, но большинство, на субсидированных рейсах немного не так - там можно позволить себе летать и пустыми). Так что тариф складывается в таком диапазоне, который обеспечит умеренную загрузку выставленных емкостей.
DS28
27.01.2023 12:06+1Классно видеть такую статью, но жаль, что я уже несколько лет не работаю в аэропорту... Вот бы её в 2017 году - может чего совместного придумали))
Теперь критика.
Что тут кластеризовать - я не очень понял... Любой, кто хоть немного поработал в пассажирской авиации понимает специфику и назовёт кластеры без анализа: Москва, СПБ, Юг, топ 10 аэропортов, остальные аэропорты (где можно выделить региональную сеть для каждого), вахтовики...
Расстояния рассчитывать - тоже так себе затея, лучше было получить данные от навигационных служб, ну да ладно, наверняка там своя бюрократия, а данные нужны - кто же сделает лучше, чем сам))Прогнозирование отдельная тема. Пока выходит не очень, среди параметров рекомендую учитывать дату покупки, дату рейса, день недели вылета, время вылета, наличие конкурентов, тип вс, компоновку, наличие поездов, цены (всевозможные)... Тут же посылаю лучи сочувствия - прогнозировать в текущих условиях тяжко. Да и вообще будущее не всегда похоже на прошлое)) Можете попробовать давать прогнозы с отклонением, несколько сценариев...
В общем пока статья совсем слабая и малополезная, хотя может чего-то я не понял...
В любом случае я рад видеть коллегу из авиации на хабре))tmrslk Автор
28.01.2023 17:43Насчет кластеризации - да, однозначно, деление направлений даже неработающий в авиации человек может провести и сам. Но чтобы сделать модель универсальной, я дал на откуп машине процесс разделения направлений на подгруппы, нежели чем почти вручную отбирать направления по подгруппам.
Да, с расстояниями понимаю (особенно про закрытые а/п юга). Исходил из допущения, что сформировавшийся спрос за многие годы сохраняется на прежнем уровне, несмотря на рост времени облета. В целом, расстояние не оказалось очень существенным фактором, влияющим на пассажиропоток, хотя корреляция, конечно, есть.
Про метрики - вы, как человек из авиации, знаете, как много новых направлений закрываются (по моей оценке, для внутренних рейсов таких 40-60%), так и не выполнив одного рейса, либо же не выдерживают даже сезон полетов. Что косвенно и говорит о том, как работает прогнозирование трафика в отрасли))
Про параметры - особенность в том, что я пытался предсказать глобально пассажиропоток (пролетный) за год, поэтому глубина продаж на это не сильно влияет. Про наличие конкурентов - трафик я брал по всей отрасли в целом, и модель прогнозирует суммарный авиатрафик. Объемы рынка и предложенные кресла буду включать в следующие итерации модели.
ay11z
27.01.2023 12:14А как с такой большой ошибкой можно заниматься прогнозированием продаж? Либо в компании попустительски относятся к плану? Не стараюсь обидеть или задеть, сам понимаю, что при невыполнении плана продаж весь отдел не увольняют на первый, второй и даже на 10ый раз, но, всё-таки.
tmrslk Автор
28.01.2023 17:47Предсказывать трафик - сложная задача, а количество открытых и потом отмененных рейсов в РФ довольно существенное - около 40-60%. Это косвенно говорит о "качестве" текущего прогнозирования в отрасли. Для новых рейсов в целом сильные отклонения что в плюс, что в минус, могут быть нормой из-за специфики потоков.
Не думаю, что это связано с низким профессионализмом сотрудников, а скорее со слишком большой неопределенностью. Однозначно, модель не конечная, буду расширять ее за счет новых вводных и стараться заметно уменьшать ошибку.
LevOrdabesov
27.01.2023 14:49+1Плюс авансом. Для отдельной статьи всё же коротковато, ИМХО.
tmrslk Автор
28.01.2023 17:36+1Спасибо. Да, это мой первый опыт и делился пока тем, что есть промежуточно. Первый блин всегда комом)) Когда закончу этот большой проект, обязательно напишу большую и подробную статью
Tzimie
А как ваша программа справилась бы с изменением прогноза потоков 21 сентября?
Ulrih
и с приграничными областями, где за год ниодного гражданского не пролетело.
konst90
Можно ли предвидеть непредвиденные обстоятельства?
Tzimie
Ну, с прошлого года планирование вообще идёт только краткосрочное
tmrslk Автор
Модель ориентирована на прогнозирование долгосрочных потоков, а ажиотаж конца сентября - это статистический "выброс", поэтому глобально тенденция сильно не менялась, только на очень краткосрочный период. Да и модель построена для прогнозирования внутреннего трафика. Грубо говоря, это оценка "сколько потенциально здесь может полететь пассажиров", безотносительно редких, но существенных явлений. "Черные лебеди" на то и черные лебеди, что встроить их в модель нельзя)
Tzimie
... а у нас стаи черных лебедей...