Logistics_Analyzer расчет зон покрытия
Мне показалось что в последнем посте Logistics_Analyzer "Что если?" и новые функции программы мною не до конца был раскрыт вообще весь смысл анализатора "Что если?", а так же данные были очень корявые и не точные. Сегодня я постараюсь объяснить более детально, наглядно и заодно расскажу о новой функции.
Для начала начнем с данных. Я переработал все данные, создал более грубую но работоспособную модель тестовых значений для программы. Ушел от глобализации на всей карте, в сторону "Меньше объектов, один город, при этом более верные данные".
Новая карта объектов:
Сама карта — та же самая, что и была ранее, просто вместо 118 объектов теперь их всего 34, и собраны в одном городе.
Всем объектам была присвоена одинаковая товарная матрица и примерно одинаковые продажи, разница только в том, что один магазин, например, продавал «Сковороды» и у него этот сегмент А, другой продавал холодильники, которые так же попадают в А сегмент, но сковороды у него в С.
Зон доставок я сделал 5 вариантов, т. е. одинаковые зоны будут у 6 объектов, но это не критично, даже хорошо для проведения анализа.
Возьмем за пример объект с кодом ST_MSK_004 (магазин «Таганская»).
У него есть своя зона доставок, которая сложилась исторически.
Мемом выше можно понять, что зона не оптимизирована. Почему этот 004 магазин доставляет в зоны где тоже есть магазины? Загадка, а впрочем, и нет. Это же тест-данные. Я предположил, что, например, есть один объект, у которого каким-то странным образом падала основная часть доставок, и он отдавал сам курьерку. При этом магазин стал слишком мало приносить прибыли, и аренда взлетела, надо закрыть его.
Немного переработал интерфейс, дизайн, добавил новые функции и пока что заглушки для будущих умных расчетов.
Выбираем объект 004, ставим учитывать ABC-анализ и анализировать влияние на доставку клиентам и запускаем расчет.
Пока грузиться процесс, опишу что такое "Влияние на доставку".
У компании Х есть магазин, который они хотят закрыть, надо понять визуально, какое покрытие и кому отдать кусок от «пирога». Вот это как раз и делает программа. И в этом процессе закрылась основная проблема, с которой я долго боролся, на скрине выше, где показана зона, есть маленькие зеленые точки, это исторические данные, куда были произведены отправки. На их основе программа и строит полигональную сетку для визуализации. А как быть с пустыми местами? Вот она, основная проблема. Чуть позже вернемся к этому.
Как раз расчет завершен, предлагаю посмотреть труды.
Окно товарных запасов - визуально на табличном примере показываем фактический остаток товара в магазине
Ближайшие объекты - показывает то куда можно переместить товар, какое расстояние, емкость и доступность
План перераспределения — это уже предлагаемые распределения остатков с закрываемого объекта на ближайшие по следующей логике:
Проверяем товарную матрицу
Проводим АВС анализ (в будущем добавлю и XYZ)
Проверяем вместимость нового объекта
Если не подошло ни под одно действие, либо проверяем все найденные объекты в зоне, либо отправляем на склад, чуть-чуть логики с логов программы ниже:
Логи наверное скажут все за меня и гораздо больше)
Стоимость доставок - вообще должна считать по объему утилизации трака, сейчас как бы тоже (со скрипом) живой вариант, но есть уже накиданная логика, лежит под фичатоглом, надо проверять в будущем.
Влияние на регион - ничего интересного там нету, кейс без особенностей, программа говорит что все отлично
И вот она, та самая "Вишенка" на торте - влияние на доставку
Рассмотрим два типа карт: общая информация и данные о влиянии на время.
Информация о влиянии на время, как считает программа:
Смотрит 3 точки из текущей зоны доставки по закрываемому объекту:
Самая дальняя точка по километражу
Средняя точка
Ближняя точка
2. Считает время от объекта до каждой из этих точек и берет среднее арифметическое значениеКластеризует текущую зону на подзоны для новых объектов и делает аналогичное, как в пункте 1+2, добавляя среднее по всем объектам.
Нажимая на "Синюю" кнопку открывается окно в котором при нажатии на пуск - происходит визуализация перераспределения зоны с учетом объектов и введенных параметров (Учет объектов вне зоны км). Состоит данный процесс из 5ти этапов.
Показываем закрываемый объект
2. Показываем все объекты которые находятся внутри текущей зоны и внешние согласно параметра.
3. Показываем фактическую зону доставок
4. Делим зоны на кластеры. И вот тут самое интересное.
Как сказать программе: «Смотри, есть вот такая зона, в ней есть 10, 15 или 20 объектов, подели рисунок на пропорциональные части с учетом оптимальной логистики?» А ведь внутри родительского кластера есть пустые зоны, в которых исторически не было доставок, а мы все равно должны их учесть и распределить.
Долго я думал над этим процессом, множество раз переписывал код, удалял методы. Вроде работают, но программа не понимает, что я хочу от нее. Ну не может она разделить без вершин пустые зоны.
И я придумал. В один вечер я сидел в какой-то компьютерной игре и ставил метки на карте, тут меня и осенило. Добавить больше точек, но не реальных, не исторических, а виртуальные точки для наполнения родительского кластера. Сделать их невидимыми для пользователя, но видимыми для логики программы. Так получается, мы устраняем эти пробелы, и метод начинает определять зоны, при этом делая этот процесс с большей точностью.
Мы находим в начале объекты и рядом с объектами начинаем раскидывать точки с определенной плотностью.
Дальше мы показываем окончательный процесс (распределения кластеров и привязку их к другим объектам).
На примере одного из кластера. Есть магазин на Павелецкой, есть зона которая перейдет к нему.
Отдаляем карту и чисто визуально мы понимаем, да кластеризация прошла успешно.
Да и отдаленные магазины тоже правильно подхватили кластеры.
Какой же экстаз я словил когда руками проверил и убедился в том что да, все работает как и задумано. Как минимум этот процесс автоматизирован. Не надо теперь руками все это считать, собирать карты по крупицам. Работа которая занимает неделю а то и две может быть выполнена за 1 минуту. Это успех.
На моменте первой визуализации я думал: «Это успех», и лучше уже ничего не добавлять. Но потом пришла мысль, маленькая мысль, которая не давала покоя: «А что, если кому-то этого мало, а если надо показать визуально маршруты, точки из расчета?». Имея готовый скрипт JS и логику, мне просто потребовалось скопировать, вставить и дополнить первоначальный код.
Процесс анимирования занимает гораздо больше времени. Программе надо отправить API запрос, получить ответ, так для каждого объекта по 3 раза.
2025-12-15 16:08:02,800 - INFO - STDOUT - 🌍 Построение маршрута через OSRM (карта: yandex)
2025-12-15 16:08:02,800 - INFO - STDOUT - 🌐 OSRM API: попытка 1/2
2025-12-15 16:08:02,801 - DEBUG - urllib3.connectionpool - Starting new HTTP connection (1): 127.0.0.1:53913
2025-12-15 16:08:03,674 - DEBUG - urllib3.connectionpool - http://127.0.0.1:53913 "GET http://router.project-osrm.org/route/v1/driving/37.6215,55.7... HTTP/1.1" 200 682
2025-12-15 16:08:03,675 - INFO - STDOUT - ✅ Маршрут через OSRM: 0.9 км, 2 мин
2025-12-15 16:08:03,675 - INFO - STDOUT - ✅ Зона 21 добавлена: 1 маршрутов, 10 точек полигона
2025-12-15 16:08:03,675 - INFO - STDOUT - 🔍 Обработка зоны 22: facility=True, polygon=9, points=0
2025-12-15 16:08:03,675 - INFO - STDOUT - ⚠️ Зона 22: нет точек доставки, добавляем без маршрутов
2025-12-15 16:08:03,675 - INFO - STDOUT - ✅ Зона 22 добавлена: 0 маршрутов, 9 точек полигона
2025-12-15 16:08:03,675 - INFO - STDOUT - 🔍 Обработка зоны 23: facility=True, polygon=13, points=0
2025-12-15 16:08:03,675 - INFO - STDOUT - ⚠️ Зона 23: нет точек доставки, добавляем без маршрутов
2025-12-15 16:08:03,675 - INFO - STDOUT - ✅ Зона 23 добавлена: 0 маршрутов, 13 точек полигона
2025-12-15 16:08:03,675 - INFO - STDOUT - 🔍 Обработка зоны 24: facility=True, polygon=10, points=5
Лог работы построения маршрута.
Logistics_Analyzer - умеет работать с геодекодированием, но маршруты - извольте, я даже не знаю как их строить. Интересно было бы посмотреть как создается логика построения маршрута под капотом.
Итог:
Мы получаем кластер с тремя ключевыми точками и путями до них, включая полное описание маршрутов.
На третьем этапе программа последовательно демонстрирует каждый новый кластер и прокладывает маршруты (к сожалению, из-за ограничений медиа, я не могу приложить изображения).
Давайте подведем итоги кластеризации и перераспределения зон.
На мой взгляд, это успех. Конечно, есть некоторые недочеты, но они едва заметны и будут быстро исправлены. Логика работы выстроена, отчет динамичен. Теперь остается только проверить все на практике и собрать для него ОС от пользователей.
Есть план развития дальше, плюс устранение мелких недочетов. Первую бету версию планирую компилировать в начале марта 26г. Кому ее предлагать - это уже другой вопрос. Буду решать в момент возникновения.
В интерфейсе произошли некоторые изменения. Например, я перешел от скучной бежевой темы к более темным цветам. Часть стилей выделил в QSS и настроил их подключение в Main_window. Меню дашбордов стало напоминать Power BI с Excel, и были внесены другие мелкие правки.
Работаю над проектом по вечерам, уделяя этому 2-3 часа. Основные алгоритмы визуализации были написаны давно, но я долго не мог понять, в чем проблема. То данные распределялись неверно, то пробелы не учитывались. В начале реализации функции был у меня дата-файл, где зоны были более реалистичными, чем сейчас. При перераспределении их покрытие составляло всего 30%. То что "Ну очевидно можно сделать вот так" она делала "Тебе очевидно, а мне нет. Хочешь - делай сам".
Всем спасибо за прочтение. Пишите комментарии кто и что думает. Задавайте вопросы - отвечу)

























































