Русский
Русский
English
Статистика
Реклама

Снос

Recovery mode Волны московской реновации

27.08.2020 14:07:16 | Автор: admin


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


1. Введение


Вкратце о программе реновации

Программа реновации была запущена Правительством Москвы в 2017 году. Благодаря ей 350 тысяч московских семей, то есть более миллиона человек, переедут в новые квартиры с отделкой комфорткласса.


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


Участники получат равнозначное жилье в своем районе (далее можно прочитать здесь)


На основании приказа правительства Москвы от 12 августа 2020 г. 45/182/ПР-335/20 (прочитать можно здесь) вся программа переселения рассчитана до 2032 года и должна будет пройти в три этапа (три волны):


  • первый этап 2020 2024гг., в него вошло 930 домов, страницы 3-29 в приказе
  • второй этап 2025 2028гг., в него вошло 1636 домов, страницы 30-76 в приказе
  • третий этап 2029 2032гг., в него вошло 1809 домов, страницы 77-128 в приказе
  • без определённого этапа (этапы должны будут определиться до конца 1 квартала 2021г.) 688 домов, страницы 129-148 в приказе

2. Парсинг данных


Данные я взял из этого приказа, т.к. приказ это pdf файл с таблицами, то я использовал библиотеку tabula для парсинга pdf файлов.


import pandas as pdimport numpy as npimport requestsfrom tabula import read_pdfimport jsonimport os

Первым делом я спарсил одну страницу из этих таблиц, чтобы посмотреть, как дальше чистить данные.


test = read_pdf('prikaz_grafikpereseleniya.pdf', pages='3', pandas_options={'header':None})

test.head()


0 1 2 3 4 5
0 No п/п АО Район NaN Адрес дома unom
1 1 ЦАО Басманный Бакунинская ул., д.49 c.4 NaN 1316
2 2 ЦАО Басманный Бакунинская ул., д.77 c.3 NaN 1327
3 3 ЦАО Басманный Балакиревский пер., д.2/26 NaN 19328
4 4 ЦАО Басманный Госпитальный Вал ул., д.3 NaN 31354


Как видно из того, что получилось спарсить, чтобы очистить данные необходимо удалить лишние колонки и строчки, что и делает функция parse_pdf_table.


def parse_pdf_table(pages, pdf_file='prikaz_grafikpereseleniya.pdf'):    df = read_pdf(pdf_file, pages=pages, pandas_options={'header':None})    # удаляем не нужные строки    df = df[~(df.iloc[:,0] == 'No п/п')]    # оставляем только нужные колонки    df = df.iloc[:,1:4]    df.columns = ['AO', 'district', 'address']    return df

Каждая волна находится в своём диапазоне страниц, парсим их и проверяем по документу, т.е. количество строк должно совпадать с тем, что есть в pdf файле. (Также сразу добавляем к данным номер волны, т.к. это пригодится в будущем)


wave_1 = parse_pdf_table('3-29') # 2020 - 2024wave_1['wave'] = 1

wave_1.shape

(930, 4)

wave_2 = parse_pdf_table('30-76') # 2025 - 2028wave_2['wave'] = 2

wave_2.shape

(1636, 4)

wave_3 = parse_pdf_table('77-128') # 2029 - 2032wave_3['wave'] = 3

wave_3.shape

(1809, 4)

unknown = parse_pdf_table('129-148')unknown['wave'] = 0

unknown.shape

(688, 4)

3. Обработка данных


Обрабатывать данные будем на пандасе (pandas), для этого соберём все волны в один датафрейм df.


df = pd.concat([wave_1, wave_2, wave_3, unknown], ignore_index=True)

Выделим своим цветом метки каждой волны.


df['marker-color'] = df['wave'].map({1:'#0ACF00',  # зеленый                                     2:'#1142AA',  # синий                                     3:'#FFFD00',  # жёлтый                                     0:'#FD0006'}) # красный

Также подпишем каждую метку в зависимости от волны.


df['iconContent'] = df['wave'].map({1:'1',                                    2:'2',                                    3:'3',                                    0:''})

В описание метки добавим адрес.


df['description'] = df['address']

Если не уточнить город Москва, то по данным, полученным из геокодера получится, что реновация началась по всей стране, да что там, во всём мире. (Даёшь реновацию во всём мире! :)



df['address'] = 'Москва, ' + df['address']

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


def geocoder(addr, key='введи свой ключ'):       url = 'https://geocode-maps.yandex.ru/1.x'    params = {'format':'json', 'apikey': key, 'geocode': addr}    response = requests.get(url, params=params)    try:        coordinates = response.json()["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"]        lon, lat = coordinates.split(' ')    except:        lon, lat = 0, 0    return lon, lat

%%timedf['longitude'], df['latitude'] = zip(*df['address'].apply(geocoder))

CPU times: user 2min 11s, sys: 4.31 s, total: 2min 15sWall time: 15min 14s

Все координаты определились удачно (именно удачно, т.к. нет гарантий, что геокодер спарсил адрес так как нам нужно), другими словами он хотя-бы что-то вернул.


len(df[df['longitude'] == 0])

0

Сохраним полученные данные.


df.to_csv('waves.csv')

#df = pd.read_csv('waves.csv')

4. Формирование карты волн реновации


Для отображения полученных данных на карте я использовал формат GeoJSON.


def df_to_geojson(df, properties, lat='latitude', lon='longitude'):    geojson = {'type':'FeatureCollection', 'features':[]}    for _, row in df.iterrows():        feature = {'type':'Feature',                   'properties':{},                   'geometry':{'type':'Point',                               'coordinates':[]}}        feature['geometry']['coordinates'] = [row[lon],row[lat]]        for prop in properties:            feature['properties'][prop] = row[prop]        geojson['features'].append(feature)    return geojson

Т.к. меток получилось очень много, то полная карта может медленно работать на слабом ПК, поэтому я разделил данные по округам Москвы для удобства.


properties = ['marker-color', 'iconContent', 'description']if not os.path.exists('data'):    os.makedirs('data')for ao, data in df.groupby('AO'):    geojson = df_to_geojson(data, properties)    with open('data/' + ao + '.geojson', 'w') as f:        json.dump(geojson, f, indent=2) 

Полученные данные в формате .geojson я сохранил в папку data. В файле ВСЕ_ОКРУГА.geojson записаны данные по всем округам вместе.


geojson = df_to_geojson(df, properties)with open('data/ВСЕ_ОКРУГА.geojson', 'w') as f:    json.dump(geojson, f, indent=2) 


ссылка на полную карту (может работать медленно) здесь.



В целом получилось не плохо, все метки внутри границ Москвы, однако, есть и несколько ошибок, как например недалеко от Сергиева Посада Пролетарий СНТ территория (п.Вороновское), д.1 или в окрестностях Орехово-Зуево Гаражный пер. (пос.ДСК Мичуринец, п.Внуковское), д.8/КБ/Н. (Честно говоря я бы и сам не сразу понял, где это находится)


5. Что хотелось сделать, но не получилось :(


Официальный список стартовых площадок находится здесь.


Также на карту волн реновации я хотел добавить стартовые площадки, однако это не получилось сделать. Проблема даже не в том, что нормально спарсить список не удалось, это можно было бы решить, проблема в том, что геокодер не может точно определить координаты по владению, например, Шмитовский проезд, вл. 39, Мукомольный проезд, вл. 6, или где находится этот адрес район Южное Медведково, мкр. 1, 2, 3, корп. 38.


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


Однако не всё так плохо и выход всё же есть можно добавить эти метки вручную!



Видео-инструкция о том, как это сделать есть в исходном коде проекта, а также её можно посмотреть/скачать здесь.


Выводы


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


Исходный код залит на github и скачать его можно здесь.


Спасибо за внимание.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru