Несколько лет назад Veeam открыла центр исследований и разработок в Праге.
Изначально у нас был небольшой офис примерно на 40 человек, но компания активно растёт, и сейчас в новом просторном офисе «Рустонка» нас уже больше двухсот. Veeam нанимает сотрудников не только из Чехии и Евросоюза, но и активно релокирует успешных кандидатов из России.
Многие люди переезжают с женой и детьми, и тут у них возникает вопрос, с которым мы с семьей столкнулись четыре года назад, когда впервые оказались в Праге: нам нужно было решить, где выбрать жилье, в какой детский сад пойдет моя дочь, и решить множество других проблем, возникших из-за полного незнания города.
Конечно, все это можно проверить своими ногами, но мне хотелось подойти к вопросу с инженерной точки зрения и решить эту проблему, используя подход data science – с помощью анализа данных открытого доступа определить наиболее благоприятные районы Праги для жизнь.
Определение степени благоприятности той или иной местности – задача достаточно широкая, и оценка может быть достаточно субъективной, поэтому сначала уточню немного конкретнее и опишу проблему следующим образом: Какой район Праги наиболее привлекателен с точки зрения пешеходной доступности для детей от 10 до 16 лет? По пешеходной доступности в своей работе я беру дистанцию 1300 метров.
Этот порог, по данным различных исследований, считается оптимальным для данной возрастной группы.
В качестве объектов инфраструктуры я выбрал те, которые, на мой взгляд, посещает большинство детей.
Это школы, библиотеки, образовательные центры, спортивные центры и детские площадки.
Город и данные
Прага – столица Чехии, ее культурный и экономический центр.Это также 14-й по величине город в Европейском Союзе.
На площади 298 кв.
км.
официально проживает 1,3 миллиона человек.
История Праги насчитывает 14 веков.
И, как почти любой европейский город, основанный в раннем средневековье, Прага имеет классическую для такого типа города топологию.
Исторический центр сравнительно небольшой по площади, с плотной застройкой и узкими улочками.
Непосредственно к нему примыкают районы с более поздней застройкой, и, в отличие от самого центра, эти районы неоднократно перестраивались, модернизировались и теперь более приспособлены для жизни современных людей.
Периферия состоит из жилых массивов, постепенно переходящих в малоэтажную застройку, и частных домов.
В целом Прага – очень комфортное место для жизни.
Он компактный, здесь нет многоэтажных застроек, пробок, удобная сеть общественного транспорта.
Но это мое личное мнение, и я не могу сказать, что оно на 100 процентов верное, поэтому было интересно посмотреть на город в цифрах.
Кстати, Прага занимает лидирующие позиции по доступности городских данных.
На портале ИПР Прага собрано огромное количество различных наборов данных: демография, экономика, транспорт, медицина, экология и т.д. Данные доступны абсолютно бесплатно, постоянно обновляются и дополняются.
География и демография
Данные о количественном и качественном составе населения Праги я возьму из набора данных Чешское статистическое бюро .Они были собраны во время последней национальной переписи населения и содержат информацию о поле, возрасте и количестве жителей для каждого населенного пункта Чешской Республики.
Для крупных населенных пунктов – таких как Прага и Брно – данные также приводятся по каждому отдельному административному району города.
Для моего исследования представляют интерес именно эти данные по каждому из 22 отдельных районов Праги.
url_population = ' https://www.czso.cz/documents/10180/25233177/sldb_zv.csv ' df_population = pd.read_csv(url_population,encoding = "ISO 8859-2") df_population = df_population[(df_population.uzcis == 44)& (df_population.nazev.str.find('Praha') != -1)][['nazev','u01','u04', 'u05', 'u06']] df_population.rename(columns={'nazev':'Name','u01':'Total', 'u04':'Kids', 'u05':'Middle', 'u06':'Senior'}, inplace = True) df_population['Name'] = df_population['Name'].
map(lambda x: x.lower())
типуз_наз | назев | узки | узкод | u01 |
---|---|---|---|---|
край | Хлавн? Место Прага | 100 | 3018 | 1268796 |
Они доступны на портале IPR Praha. Для удобства дальнейшего анализа я удалил ненужные столбцы и объединил данные из этих двух источников в одну таблицу, которую можно просмотреть на моем сайте.
Имя | Геометрия | Область | Общий | Дети | |
---|---|---|---|---|---|
0 | Прага 1 | [[14.410891049000043, 50.078674687000046], [14. | 5538443.86 | 30561.0 | 2391.0 |
1 | Прага 10 | [[14.531321086000048, 50.072240288000046], [14. | 18599366.98 | 113200.0 | 12213.0 |
2 | Прага 11 | [[14.54355294800007, 50.03618763800006], [14.5. | 9793679.84 | 75741.0 | 8688.0 |
Куда идут наши дети?
Для данного исследования я решил сосредоточиться на наиболее часто посещаемых местах: школах, клубах, спортивных клубах, детских площадках и библиотеках.Данные были получены из различных источников и преобразованы в набор, содержащий необходимую мне информацию: тип объекта, принадлежность к административному округу, координаты.
Я сознательно не использовал никакого гео API, во-первых, из-за жестких ограничений бесплатных версий, а также потому, что не всегда можно быть уверенным в достоверности этих данных.
Вся актуальная информация о школах, а также других учебных заведениях находится в свободном доступе на сайте Министерства образования.
XML-файл содержит исчерпывающую информацию обо всех учреждениях, подведомственных министерству.
В Праге это 2273 строки.
К сожалению, описания к этому файлу не было, поэтому пришлось вытаскивать все возможные типы заведений, их кодовые обозначения и самому разбираться, какие типы меня интересуют. Отфильтровав ненужные данные, я получил около 500 объектов.
Ненужную мне информацию я тоже сразу удалил, оставив только: тип учреждения, его адрес и районную принадлежность.
Для будущей модели меня не интересует фактический адрес объекта, поэтому с помощью гео-API я получил широту и долготу по адресу.
# Coordinates retrieve function
import geocoder
def get_coordinates(dataFrame, index_row):
dict_coordinates = {}
total_count = len(dataFrame.index)
current = 0
errors = 0
for index, row in dataFrame.iterrows():
try:
g = geocoder.arcgis(row[index_row])
lat = g.json['lat']
lng = g.json['lng']
dict_coordinates[index] = [lat, lng]
current+=1
except:
errors+=1
print ('Failed to get coordinates for {}: {}'.
format(index_row, sys.exc_info()[0])) dataFrame['latitude'] = 0.0 dataFrame['longitude'] = 0.0 for k, v in dict_coordinates.items(): dataFrame.loc[k,'latitude']=v[0] dataFrame.loc[k,'longitude']=v[1] print('Done: Total: {} Success: {} Error {}'.
format(total_count, current, errors)) print('Environment was initializied') url_schools = ' https://rejstriky.msmt.cz/opendata/vrejcz010.xml ' file_schools = 'schools.xml' results = requests.get(url_schools) results.content with open(file_schools, 'w') as file: file.write(results.text) print('Loaded') import xml.etree.ElementTree as et xtree = et.parse(file_schools) xroot = xtree.getroot() dic_scools = [] try: for entry in xroot.findall('PravniSubjekt'): place_group = entry.find('SkolyZarizeni') if(place_group is None): continue for place in place_group.findall('SkolaZarizeni'): s_id = place.find('IZO').
text s_type = place.find('SkolaDruhTyp').
text s_name = place.find('SkolaPlnyNazev').
text s_capasity = place.find('SkolaKapacita').
text s_adress = place.find('SkolaMistaVykonuCinnosti') s_actual_add = s_adress.find('SkolaMistoVykonuCinnosti') s_addres1 = s_actual_add.find('MistoAdresa1').
text s_addres2 = s_actual_add.find('MistoAdresa2').
text s_addres3 = s_actual_add.find('MistoAdresa3').
text dic_scools.append([s_id, s_name, s_type, s_capasity, '{} {} {}'.
format(s_addres1, s_addres2, s_addres3)]) print('Completed. Total schools and educational centers count: {}'.
format(len(dic_scools))) except: print ('Exception', sys.exc_info()[0]) columns = ['id', 'name', 'type', 'capacity', 'address'] df_education = pd.DataFrame(dic_scools, columns = columns) print('Dataframe created: {},{}'.
format(df_education.shape[0], df_education.shape[1])) #upload to datastore df_prague.to_csv('prague_schools.csv') upload_file(storage_creds,'prague_schools.csv','prague_schools.csv') #Check for predefinied types at schools dataframe types = df_education['type'].
unique() print('Types in XML file') for t in types: print(t,df_education[df_education.type == t].
iloc[0,1]) #filtering types with pd.option_context('mode.chained_assignment', None): types = ['B00', 'F10', 'C00','H22', 'G11'] types_shu = types[0:3] df_education_selected = df_education.loc[df_education.type.isin(types)] df_education_selected.loc[df_education_selected['type'].
isin(types_shu), 'Type'] = 'school' df_education_selected = df_education_selected.fillna('educatioanal center') print('Schools and educational centers count {}'.
format(df_education_selected.shape[0])) print('Unique types {}'.
format(df_education_selected['Type'].
unique())) #Cleaning and retriving coordinates df_education_selected.loc[0:, 'District_Name'] = df_education_selected.loc[0:,'address'].
apply(lambda x: ' '.
join(x.split()[-2:]).
lower())
columns_to_drop = ['id','name','capacity', 'type']
df_education_selected.drop(columns = columns_to_drop, inplace = True)
get_coordinates(df_education_selected, 'address')
df_education_selected.drop(columns = ['address'], inplace= True)
df_education_selected.head()
Тип | Район_Название | широта | долгота |
---|---|---|---|
школа | Прага 4 | 50.008620 | 14.448992 |
школа | Прага 1 | 50.080344 | 14.415264 |
Единственная разница заключалась в источниках данных и форматах.
Объединив все в общую таблицу, я получил набор, содержащий 1623 строки.
Вы также можете скачать его с моего Репозиторий GitHub .
Уличный граф
Данные уличной сети я взял из OpenStreetMap. Дорожная сеть Праги представлена геометрическими линиями, характеризующимися длиной.На основе этих данных на этапе моделирования будет построен граф топологии маршрута, и от каждого узла будет построен маршрут до интересующих нас точек.
#Loading data from previous steps
poi_file_name = files['poi']
population_file_name = files['districts']
df_prague_population, selected_pois = get_data(population_file_name, poi_file_name)
print('Total POIs to explore: {}'.
format(len(selected_pois))) print('Total Districts to explore: {}'.
format(len(df_prague_population))) #Buiding graph start_time = time.time() bbox = get_bounding_box(df_prague_population['Geometry']) bbox_string = '_'.
join([str(x) for x in bbox]) net_filename = 'network_{}.
h5'.
format(bbox_string) print('Selected region bounding box is {}'.
format(','.
join([str(x) for x in bbox])) ) bbox_aspect_ratio = (bbox[2] - bbox[0]) / (bbox[3] - bbox[1]) print("Build new network") network = osm.pdna_network_from_bbox(bbox[3], bbox[2], bbox[1], bbox[0],network_type='walk') print ('Remove low-connectivity nodes and save to h5') lcn = network.low_connectivity_nodes(impedance=1000, count=10, imp_name='distance') network.save_hdf5(net_filename, rm_nodes=lcn) upload_file(storage_creds,net_filename,net_filename) print('Network with {:,} nodes builded in {:,.
2f} secs'.
format(len(network.node_ids), time.time()-start_time))
#Statistics
#Edge node pairs completed. Took 311.64 seconds
#Returning processed graph with 140,877 nodes and 204,649 edges.
#Completed OSM data download and Pandana node and edge table creation in 334.49 seconds
#Remove low-connectivity nodes and save to h5 File #network_14.224437012000067_49.94190007000003_14.706787572000053_50.17742967400005.h5 Uploaded
#Network with 140,877 nodes builded in 701.63 secs
Всего пешеходная сеть Праги насчитывает 140 822 узла и 204 575 соединений.
Как видите, строительство заняло около 10 минут. Готовая сеть лежит на GitHub .
На этом этап сбора и очистки данных завершен.
В результате я получил 2 набора данных и уличную сеть Праги.
Более подробно весь процесс вы можете изучить, а также посмотреть код в этом блокноте.
Анализ данных
Общая численность населения Праги составляет около 1,3 миллиона человек.Самые высокие значения в южных регионах: от 110 тысяч до 130 тысяч.
Все районы с численностью населения выше среднего расположены вокруг районов исторического центра.
Средняя численность населения этих районов составляет 70 тысяч человек.
Это ожидаемо: большинство людей в таких городах, как Прага, живут как можно ближе к историческому центру, а не внутри него.
Два крупнейших района на севере – с населением от 90 до 100 тысяч – рассказывают нам о том, в каком направлении развивается Прага.
На следующей диаграмме мы ясно видим области, которые в основном представляют интерес для супружеских пар.
Центральные районы и пригороды имеют самые низкие значения, а районы вокруг центра, но не внутри него, имеют средние значения и составляют примерно от 160 до 180 детей на 1000 взрослых.
Анализируя население Праги с демографической точки зрения, можно заметить, что распределение детей на 1000 взрослых соответствует нашему представлению о районах города.
Топ-10 округов с наибольшим количеством детей повторяют топ-районы из предыдущих графиков.
Наш максимум — 8 процентов в Праге 4.
Выбранные нами объекты также сосредоточены вокруг исторического центра.
Распределение по районам коррелирует с численностью населения районов.
У нас примерно одинаковое количество точек во всех областях из топ-10 по численности населения, но с аномально высокими значениями на юге.
Общее количество учреждений не дает нам полного представления о том, насколько хороша для детей каждая отдельная зона.
Нам интереснее посмотреть на соотношение количества предметов к количеству детей.
Например, если мы посмотрим на гистограмму школ, мы заметим, что максимальные значения не коррелируют с численностью населения.
Прага 1 имеет самые высокие показатели, но если мы посмотрим на предыдущие графики, то увидим, что по проценту детей Прага 1 даже не входит в топ-10. С другой стороны, Прага 4 имеет самые высокие показатели численности населения а также средние школы/1000 значений.
С одной стороны, это связано с низким количеством детей в центре города; с другой стороны, причина в том, что концентрация учебных заведений в центре города обычно выше.
Ту же картину мы видим на следующих гистограммах.
В центральных районах самые высокие показатели количества детей на 1000 детей, а в пригородах — самые низкие.
Построение модели
Для нашего исследования мы не будем использовать четкие границы города, а возьмем квадратную территорию, описывающую реальные границы.(Мы не можем использовать меньшие границы, такие как административные или исторические районы, потому что мы должны учитывать, что дети, живущие на границах двух районов, могут посещать объекты в другом районе.
) На первом этапе мы преобразовали уличную сеть в граф.
Для сборки я использовал фреймворк Пандана .
Огромным преимуществом этого фреймворка является быстрая статистическая обработка данных по всей сети.
В моем случае построение графа на 140 822 узла и последующая его очистка заняло около 5 минут. (Под очисткой в данном случае я подразумеваю удаление точек, которые не представляют собой фактические точки пересечения и не являются узлами согласно теории графов.
)
Второй шаг — наложение наших объектов на график и расчет матриц доступности.
(Под матрицей доступности я рассматриваю набор кратчайших расстояний от каждого узла графа до 3-х объектов.
) На следующем этапе мы будем использовать полученные данные для кластерного анализа.
идентификатор | 1_школа | 2_школа | 3_школа | 1_учебный центр |
---|---|---|---|---|
172508 | 218.384003 | 452.865997 | 502.253998 | 124.689003 |
172510 | 42.796001 | 326.665985 | 347.582001 | 50.898998 |
172512 | 226.128006 | 290.959991 | 300.862000 | 421.157990 |
172513 | 353.912994 | 393.170990 | 442.434998 | 627.351990 |
172514 | 270.234985 | 443.700989 | 492.393005 | 711.030029 |
Этот метод был изобретен в 1950-х годах математиком Хьюго Штейнхаусом.
Работа алгоритма такова, что он стремится минимизировать общее квадратическое отклонение точек кластера от центров этих кластеров.
Алгоритм представляет собой версию алгоритма EM, который также используется для разделения смеси гауссиан.
Он разбивает набор элементов векторного пространства на заранее известное количество кластеров k. Основная идея заключается в том, что на каждой итерации центр масс пересчитывается для каждого кластера, полученного на предыдущем шаге.
Затем векторы снова разбиваются на кластеры в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике.
Алгоритм завершает работу, когда на некоторой итерации не происходит никаких изменений на расстоянии кластера.
Это происходит за конечное число итераций, поскольку число возможных разбиений итогового множества конечно, и на каждом шаге полное квадратическое отклонение уменьшается.
Поэтому зацикливание невозможно.
Поскольку алгоритм предполагает заранее известное количество кластеров, я использовал другой известный алгоритм — Elbow. С его помощью можно определить оптимальное количество кластеров, и в результате у меня получилось 4 кластера.
На заключительном этапе я рассчитал для каждого кластера среднее время, за которое ребенок доберется до ближайшего объекта пешком, а также ввел понятие оценки доступности = фактическое расстояние / 1300.
Кластер № | 0 | 1 | 2 | 3 |
---|---|---|---|---|
Оценка проходимости | 1.3 | 2.3 | 1.0 | 1.7 |
Время ходьбы (минуты) | ||||
Школы | 9 | 44 | 6 | 19 |
Хобби | 36 | 45 | 20 | 44 |
Библиотека | 30 | 45 | 23 | 44 |
Спортивные сооружения | 8 | 43 | 6 | 14 |
Детские площадки | 45 | 45 | 45 | 45 |
выводы
В результате у нас есть 4 кластера в Праге.Кластер №2 имеет оптимальный показатель пешеходной доступности, равный единице.
Это значит, что из каждой точки этого кластера дети могут добраться до всей необходимой инфраструктуры примерно за 15 минут. Школы являются наиболее доступными в этом кластере, что является очень хорошим результатом.
С другой стороны, кластер № 2 охватывает в основном центральный исторический район, и мы знаем, что в этом районе количество детей ниже, чем в соседних районах.
Второй кластер под номером 0 имеет показатель пешеходной доступности около 1,3. Это значит, что до интересующих нас объектов этого кластера можно добраться менее чем за 10 минут. Это тоже очень хороший результат. Однако по обоим этим кластерам библиотеки и дома культуры имеют крайне низкие показатели – в среднем мы получаем около 30 минут ходьбы.
Заключение
В этом исследовании я проанализировал пешеходную доступность Праги для детей 10-16 лет. Я определил основные места посещения выбранной фокус-группы и измерил кратчайшие расстояния до всех выбранных мест. Используя алгоритм кластеризации, я разделил исследуемую область на 4 кластера.В будущих исследованиях я планирую провести более детальный анализ каждого типа.
Также я хотел бы добавить вес моему графу улиц, чтобы при построении маршрута я также учитывал рельеф местности.
Также мне, как родителю, интересно посмотреть на пешеходную доступность не только с точки зрения кратчайших маршрутов, но и с точки зрения наиболее безопасных.
Ссылки
- Живые улицы (Ассоциация пешеходов) ОТЧЕТ О ЖИВЫХ УЛИЦАХ
- Критерии расстояний и корреляты активной транспортировки в школу у бельгийских подростков старшего возраста.
- Науманн С.
и Ковалев М.
Ю.
(2017).
Поиск пешеходного маршрута на основе OpenStreetMap. В Интеллектуальные транспортные системы и поведение в поездках (стр.
87-96) .
Чам: Спрингер.
- Пандана
- МЕХАНИКА ХОДЬБЫ У ДЕТЕЙ
- OSMnx: Python для уличных сетей
- География Праги
- Демография
- Образование и учебные заведения
- Библиотеки Праги: Википедия
- Спортивные учреждения: Opendata Прага
- Детские и спортивные площадки: Opendata Прага
-
- Привет! Техническая Поддержка?
19 Oct, 24 -
Еще Часы Или Когда За Микроконтроллер Стыдно
19 Oct, 24 -
Подвергаем Модель Gpt-3 Тесту Тьюринга
19 Oct, 24 -
Частицы Золота
19 Oct, 24 -
Одна Идея Для Монетизации Социальных Сетей
19 Oct, 24