Дороги из дома ведут в магазин: вычисляем суммы квартир для всей Москвы
В комментариях в одной из прошлых статей и на гитхаб писали что не обязательно жить близко к магазину, когда есть службы доставки. Вот с этим я могу поспорить — большая часть людей в России покупает продукты и товары в магазинах. В 90е были крайне популярны вещевые рынки и часто покупали одежду там потому что было дешевле. У многих студентов и пенсионеров их финансовая ситуация не располагает не то что платить за доставку курьером, но даже возможность купить хорошие продукты и одежду после квартплаты — это арифметика жизни. Им неосознанно приходится решать задачу коммивояжера в голове чтобы обойти несколько торговых точек и выгодно купить по заранее составленному списку покупок. Шаговая доступность магазинов все еще важна для жителей городов.
Что обычно учитывают при открытии магазина:
Его локация должна быть в удобном месте для потенциальных клиентов. Рядом с офисными зданиями, в туристическом или в жилом районе. Учитываются поток пешеходов, так и доступность общественного транспорта и парковок. И конечно учитывают целевую аудиторию: для магазинов детских товаров, лучше расположить в том районе где много семей с детьми и инфраструктуры для них.
Торговля требует выполнения стандартов безопасности и санитарии. Нужно быть уверенным что здание соответствует требованиям пожарной безопасности, санитарии и перепланировки торгового помещения узаконены. Помещение должно иметь достаточно места для товара и посетителей магазина. Хорошо бы найти профессионального юриста / агента по коммерческой недвижимости для помощи при заключения договора и решении юридических вопросов связанных с торговым помещением. Рекомендации + опыт эксперта поможет избежать лишних трат и распространенных ошибок при выборе здания.
Помимо арендной платы или стоимости покупки помещения, нужно заложить дополнительные расходы на ремонт, обслуживание помещений, зарплаты персонала, закупку товара и уплату налогов.
Как много в этом районе конкурентов? Кто целевая аудитория, где проживает или как часто посещает этот район?
Можно ли адаптировать здание при изменениях в бизнес-модели. Например решите сменить категорию товаров и что нужно будет учесть, что прийдется менять в торговом зале…
И это не все, а мы же сфокусируемся только на расположении и анализе пешеходной доступности магазинов и попрактикуемся в решении задачи — сколько человек сможет дойти до конкретного магазина: обычно люди предпочитаю покупать там где магазин ближе и где больше ассортимент товаров.
Специалисты, кто занимаются геоаналитикой профессионально для открытия новых магазинов, имеют доступ к большому объему часто платной информации: локации абонентов от операторов связи, платежных операторов и банков, доступ к подготовленным данным из ГИС ЖКХ/Реформа ЖКХ, и много еще к чему. Но они, как почтальон Печкин, вам их не дадут. И не дадут результат расчета на данных: дешево, быстро, качественно — выбирай любые два варианта.
Не претендую на академичность и точность моего субъективного исследования, лишь покажу вам как cамостоятельно рассчитать достижимость магазинов клиентами на основе свободных данных из OpenStreetMap. К счастью, для Москвы полнота и качество данных для многоэтажных жилых домов одно из самых лучших по РФ.
Данные и расчеты
Как подготовть данные для анализа я уже рассказывал в «Где 15 минут пешком от дома до метро в Москве…» и в «Где бы вы точно не жили и не остановились даже на время, если бы знали и выбирали на основе фактов». Пример расчета расстояний для магазинов с программой также публиковал в статье «Жилье в 500 м от сетевых продуктовых магазинов в Москве». Данные из OpenStreetMap PBF файла загружаются в PostgreSQL базу с установленным расширением PostGIS и H3.
Кроме пешеходных дистанций, расчитаных с помощью GraphHopper, понадобится еще число квартир в каждом доме. Его можно найти в значениях OSM тега building:flats
. Для жилых домов, у которых не указан этот тег можно проставить среднее значение квартир и умножить на число этажей в доме и площадь здания:
create table flats_precalc as select g.id,g.type,
(case when g.tags->'building:levels' ~ '^\d+(\.\d+)?$' then g.tags->'building:levels' else NULL end)::real levels,
(case when g.tags->'building:flats' ~ '^[0-9]+$' then g.tags->'building:flats' else NULL end)::smallint flats,
(CASE WHEN g.type='ways' and ST_IsClosed(g.geom) THEN st_area(ST_MakePolygon(g.geom)::geography) WHEN g.type='multipolygon' THEN st_area(g.geom::geography) ELSE 0 END) area
from geometry_global_view g where type<>'nodes' and (case when g.tags->'building:levels' ~ '^\d+(\.\d+)?$' then g.tags->'building:levels' else NULL end)::real>2 --and **проверка что здание жилое - портянка OSM тегов**;
create table flats_per_building as
select id,type,
coalesce(flats, (levels*area*
(select avg((flats/levels)/area)
from flats_precalc
where area>0 and flats>0))::smallint) flats
from flats_precalc ;
alter table flats_per_building add primary key(id,type);
Это простое решение чтобы заполнить пропуски в данных. Правильнее и точнее — это обойти дома где не указано число квартир и по почтовым ящикам (табличкам с номером подъезда) посмотреть номера квартир и указать точное число квартир в доме в исходных данных. Когда анализ выполняется для больших территорий, то можно найти данные в ГИС ЖКХ, но выгрузок для этого сайта в открытом доступе нет.
Зеленые точки — building: flats — указан в OSM, серые — апроксимация значени. Видно что точность будет выше не в центре города и не за МКАД (хотя район Митино хорошее исключение).
Итак, у нас есть дистанции расчитаные от многоэтажных жилых домов до магазинов. Если просуммировать число квартир в радиусе 1 км от магазина, то это число будет пропорционально числу людей которые смогут прийти в этот магазин.
osmworld=# \d flats_per_building
Column | Type |
--------+-----------------|
id | bigint |
type | table_reference |
flats | smallint |
Indexes:
"flats_per_building_pkey" PRIMARY KEY, btree (id, type)
osmworld=# \d distance
Column | Type |
---------------+-----------------|
building_id | bigint |
building_type | table_reference |
poi_id | bigint |
poi_type | table_reference |
distance | smallint |
osmworld=# select count(*) from distance;
count
----------
60816611
(1 row)
Time: 1722,807 ms (00:01,723)
Теперь объединим эти данные — сложив число квартир каждого дома в пешеходной доступности 1000 м от точек интереса (POI) — магазинов:
create table flats_per_poi as
select poi_id, poi_type, sum(flats) total_flats
from distance inner join flats_per_building
on building_id=id and building_type=type and distance<=1000
group by poi_id,poi_type
order by total_flats desc;
SELECT 129128
Time: 3108,646 ms (00:03,109)
Обогатим эти данные районом и в каждом районе отсортируем данные по убыванию числа квартир в пешей доступности:
CREATE TABLE moscow_district AS select tags->'name' name,polygon from multipolygon where tags->'admin_level'='8' and tags->'boundary'='administrative';
CREATE INDEX idx_moscow_district_geometry ON moscow_district USING gist (polygon);
create table best_retail_location_per_district as
select name,
row_number() over (partition by district order by total_flats desc) max_flats_rating, district,
total_flats,
centre
from (select total_flats,
coalesce(r.tags->'name',r.tags->'name:ru',r.tags->'name:en') name, (select name from moscow_district where st_contains(polygon, centre) limit 1) district, centre
from flats_per_poi inner join poi r
on poi_id=id and poi_type=type
and 'shop' = any(categories)
and coalesce(r.tags->'name',r.tags->'name:ru',r.tags->'name:en') is not null
order by total_flats desc) shops;
Теперь можно отобразить лучшие N мест на карте:
select * from best_retail_location_per_district where max_flats_rating<=10
Список существующих торговых мест по одному в каждом из районов Москвы с наибольшим количеством квартир в пешеходных окрестностях 1 км от торгового помещения:
select district, total_flats, st_x(centre), st_y(centre)
from best_retail_location_per_district
where max_flats_rating=1
order by total_flats desc;
district | total_flats | st_x | st_y
---------------------------------+-------------+--------------------+--------------------
район Митино | 44554 | 37.355865200000004 | 55.8478696
район Измайлово | 39255 | 37.800719 | 55.793489400000006
район Восточное Измайлово | 39254 | 37.799821800000004 | 55.79304380000001
район Гольяново | 32907 | 37.80093225 | 55.81096895
район Раменки | 31709 | 37.5055284 | 55.70210530000001
район Северное Измайлово | 30541 | 37.8124447 | 55.8050585
Ломоносовский район | 29928 | 37.5473658 | 55.6803493
район Южное Бутово | 29658 | 37.5593346 | 55.5486773
Таганский район | 29457 | 37.6752278 | 55.739144700000004
район Черёмушки | 28843 | 37.5469279 | 55.6735065
Пресненский район | 28788 | 37.518790700000004 | 55.7570794
Гагаринский район | 28615 | 37.5473967 | 55.6811439
район Хорошёво-Мнёвники | 28588 | 37.4602547 | 55.7818655
район Щукино | 28155 | 37.4625799 | 55.8089335
район Ховрино | 27974 | 37.5031309 | 55.8609803
Обручевский район | 27952 | 37.517463 | 55.6643959
район Аэропорт | 27551 | 37.5356024 | 55.803232200000004
район Северное Бутово | 27199 | 37.577473600000005 | 55.568533
район Некрасовка | 27009 | 37.927194300000004 | 55.7028795
Бескудниковский район | 26881 | 37.550535800000006 | 55.875935000000005
район Кунцево | 26791 | 37.410576407649934 | 55.73863922462011
район Богородское | 26623 | 37.719145000000005 | 55.8078323
район Зюзино | 26066 | 37.599057900000005 | 55.653555100000005
район Левобережный | 25818 | 37.475883100000004 | 55.864906600000005
район Северное Тушино | 25815 | 37.4244894 | 55.8499326
район Солнцево | 25813 | 37.4061808 | 55.6502106
район Коньково | 25808 | 37.524680000000004 | 55.6426711
район Восточное Дегунино | 25701 | 37.5481326 | 55.878368900000005
район Люблино | 25541 | 37.7584202 | 55.67367470000001
район Северное Медведково | 25425 | 37.662568300000004 | 55.888120150000006
Академический район | 25403 | 37.5539208 | 55.6836137
район Преображенское | 25278 | 37.717225500000005 | 55.804943400000006
район Выхино-Жулебино | 24985 | 37.8533144 | 55.684696200000005
район Марьино | 24825 | 37.765138 | 55.668098
Дмитровский район | 24682 | 37.5332311 | 55.8812342
район Арбат | 24663 | 37.5830846 | 55.7471182
район Южное Тушино | 24653 | 37.425816600000005 | 55.848617700000005
район Отрадное | 24578 | 37.60205305 | 55.863150100000006
район Новокосино | 24372 | 37.858880500000005 | 55.740321800000004
Нагорный район | 24369 | 37.6060573 | 55.6516913
Ново-Переделкино | 24264 | 37.349189800000005 | 55.6410172
район Текстильщики | 24168 | 37.7484052 | 55.7007545
район Нагатинский Затон | 24130 | 37.6775296 | 55.68217430000001
район Свиблово | 24093 | 37.6462869 | 55.8517595
район Хамовники | 24042 | 37.5789264 | 55.7254597
Тверской район | 24037 | 37.5973848 | 55.7709714
Алексеевский район | 23962 | 37.645125400000005 | 55.81044300000001
Орехово-Борисово Южное | 23737 | 37.7338043 | 55.6073353
район Новогиреево | 23715 | 37.8027832 | 55.753313600000006
Головинский район | 23674 | 37.5111866 | 55.85889400000001
район Чертаново Центральное | 23578 | 37.593337250000005 | 55.60662975
район Кузьминки | 23536 | 37.763281 | 55.705186100000006
район Перово | 23473 | 37.7999486 | 55.754013400000005
Лосиноостровский район | 23342 | 37.6858603 | 55.876531
район Бибирево | 23312 | 37.596387500000006 | 55.8903642
район Южное Медведково | 23006 | 37.6367825 | 55.87363860000001
Рязанский район | 22981 | 37.778901677736364 | 55.71208193761292
район Строгино | 22929 | 37.4063571 | 55.807376600000005
Тимирязевский район | 22852 | 37.5732797 | 55.812274200000004
район Якиманка | 22658 | 37.6136508 | 55.7213738
район Чертаново Южное | 22591 | 37.605664700000005 | 55.594416100000004
район Крылатское | 22568 | 37.4084348 | 55.760584400000006
район Проспект Вернадского | 22325 | 37.512944600000004 | 55.666986800000004
поселение Сосенское | 22225 | 37.477374700000006 | 55.57048090000001
Бабушкинский район | 21958 | 37.6771351 | 55.867305300000005
поселение Внуковское | 21831 | 37.3237201 | 55.6370195
район Зябликово | 21643 | 37.7416136 | 55.6214627
район Тёплый Стан | 21573 | 37.5181272 | 55.632703400000004
Даниловский район | 21467 | 37.6175062 | 55.719938000000006
район Ясенево | 21410 | 37.5439495 | 55.607119700000005
район Ивановское | 21390 | 37.826334100000004 | 55.753645600000006
район Коптево | 21371 | 37.520052 | 55.823584700000005
район Марьина Роща | 21313 | 37.6127702 | 55.7926579
район Лианозово | 21263 | 37.5785372 | 55.89771390000001
район Сокол | 21262 | 37.5147357 | 55.800178700000004
Останкинский район | 21086 | 37.637360900000004 | 55.8134049
Южнопортовый район | 21057 | 37.664825900000004 | 55.731036100000004
Савёловский район | 21011 | 37.5738591 | 55.7945739
район Замоскворечье | 20951 | 37.617964 | 55.7204885
Басманный район | 20784 | 37.6759708 | 55.77245370000001
район Орехово-Борисово Северное | 20782 | 37.708416400000004 | 55.609964500000004
район Западное Дегунино | 20547 | 37.5228794 | 55.8780158
район Чертаново Северное | 20459 | 37.6001775 | 55.6291803
Бутырский район | 20390 | 37.581405100000005 | 55.8199976
район Сокольники | 20328 | 37.676637400000004 | 55.7855112
Войковский район | 20192 | 37.5187881 | 55.821412200000005
Мещанский район | 20033 | 37.621846000000005 | 55.7732935
Можайский район | 19652 | 37.423553500000004 | 55.725824700000004
Донской район | 19509 | 37.607535000000006 | 55.7157616
район Очаково-Матвеевское | 19501 | 37.4757927 | 55.7104287
Тропарёво-Никулино | 19432 | 37.4681865 | 55.664694000000004
Красносельский район | 18394 | 37.636166200000005 | 55.7719856
Алтуфьевский район | 18364 | 37.597489200000005 | 55.885716900000006
район Лефортово | 18326 | 37.7081619 | 55.7505072
район Братеево | 18287 | 37.7634054 | 55.63621010000001
район Соколиная Гора | 18285 | 37.7326258 | 55.779113100000004
район Царицыно | 18200 | 37.6565437 | 55.6260485
Хорошёвский район | 17739 | 37.533148600000004 | 55.776608200000005
район Вешняки | 17409 | 37.823054400000004 | 55.721068200000005
район Котловка | 17388 | 37.5936012 | 55.6813876
район Косино-Ухтомский | 17371 | 37.88647929577547 | 55.7146019953649
район Дорогомилово | 17313 | 37.5489696 | 55.743085300000004
район Филёвский Парк | 17221 | 37.489751000000005 | 55.7397427
район Нагатино-Садовники | 17176 | 37.6629725 | 55.679679900000004
район Печатники | 17069 | 37.7247369 | 55.682193700000006
район Фили-Давыдково | 16830 | 37.451718400000004 | 55.723709500000005
район Беговой | 16642 | 37.5755901 | 55.7896471
район Ростокино | 15438 | 37.6557199 | 55.8335372
район Марфино | 14216 | 37.589894400000006 | 55.8285594
район Метрогородок | 13866 | 37.7586345 | 55.825178550000004
район Бирюлёво Восточное | 13122 | 37.66389045 | 55.601072300000006
район Москворечье-Сабурово | 12305 | 37.663324800000005 | 55.6403018
район Покровское-Стрешнево | 12231 | 37.4536358 | 55.830881500000004
Ярославский район | 10980 | 37.687691 | 55.862006400000006
поселение Московский | 10884 | 37.41915496649685 | 55.660058285851896
район Северный | 10731 | 37.544192200000005 | 55.928780100000004
Нижегородский район | 10346 | 37.681484632205915 | 55.72787293563479
поселение Воскресенское | 9373 | 37.514949 | 55.5256966
район Капотня | 9128 | 37.796075200000004 | 55.6350781
район Куркино | 7364 | 37.428532700000005 | 55.87720755000001
район Внуково | 5940 | 37.2621203 | 55.614216500000005
поселение «Мосрентген» | 4296 | 37.4733691 | 55.620890900000006
район Бирюлёво Западное | 1817 | 37.6464437 | 55.5913467
Где total_flats — число квартир в радиусе 1 км от торговой точки района district и её координаты. Конечно эти цифры включают расчет только по пешеходной доступности и только тех многоэтажных домов, что не дальше 2 км от входа в метро.
Более насыщенный цвет — больше квартир в окрестности торговой точки в районе
Этот рейтинг так же не учитывает как часто люди будут приходить в торговую точку. Одно дело когда это магазин по пути к метро, а другое — ларек спрятанный во дворах. Расположение на пути людей к аттракторам крайне важно для успеха торговли — будут чаще заходить чем ближе торговый объект расположен к ежедневному маршруту человека.
Если углубляться в эту тему, то нужно больше данных и смотреть на применимость модели Хаффа (Huff model), Multinomial Logit Model, Multiplicative Interactive Choice. Данные о расположении торговых точек магазинов по сегментам бизнеса доступны как в данных OSM, так и в объектах Places от Overture Maps Foundation.
Уважаемая бульварная пресса! При публикации этой новости, ссылка на оригинал на сайте Хабр обязательна! Искажение информации при цитировании вами моих статей с Хабра говорит о заказном характере вашей работы и крайне низком профессионализме.
Вывод
Хоть расчет пешеходных расстояний мегаполиса достаточно длительная операция, которая выполняется на обычном ноутбуке больше суток, но в остальном расчитать число людей (из квартир), которые могут дойти в магазин оказалось не сложной задачей.
Использовать open source технологии и открытые данные — лучше чем гадать на кофейной гуще и верить на слово. Конечно это лишь один из факторов выбора места для торговли, где реальный успех малого бизнеса включает множество других факторов.