Дороги из дома ведут в магазин: вычисляем суммы квартир для всей Москвы

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

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

Источник: https://habr.com/ru/articles/778970/


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

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

Со скольки лет можно оставлять ребенка одного дома по закону?Никаких ограничений и возрастных границ для таких ситуаций в законодательстве нет. В жизни это скорее моральный и психологический вопрос, а...
Не то, чтобы это было кому-то интересно, но на такую тему тексты пишутся легко и непринуждённо, потому решил написать. Разбив на несколько частей — про выбор железа, выбор софта, сборку (хотя тут не у...
Привет, меня зовут Александра Хорошкова, я менеджер проектов по рассылкам в SuperJob. Каждый день наши email-сообщения получают миллионы пользователей. Эта аудитория даёт отличную возможность для быст...
Я разрабатывал один проект по недвижимости и появилась задача показывать объекты расположенные в радиусе 20 км с просматриваемым. Т.е. у нас есть объект, в нашем случае э...
Подходил к концу календарный год, к праздникам правительство ужесточило локдаун и ввело комендантский час. Впереди было дней 10 выходных, и я решил, что наступает самое то время, чтобы за...