В этой статье мы расскажем о работе с бесплатной и открытой картой мира Open Street Map в Python. Для взаимодействия с ней воспользуемся библиотекой OSMnx, которая позволяет загружать, обрабатывать, визуализировать, анализировать уличные сети Open Street Map. Также читайте в нашей статье, как рассчитать маршрут от нью-йоркских отелей до Эмпайр-стейт-билдинг.
Установка OSMnx и датасет c отелями
Прежде всего установим библиотеку OSMnx. Это можно сделать через загрузку и настройку всех необходимых зависимостей или с помощью Docker-образа. Развертывание будет выглядеть так:
- Windows
docker run --rm -it -p 8888:8888 -v "%cd%":/home/jovyan/work gboeing/osmnx:latest
- Mac/Linux:
docker run --rm -it -p 8888:8888 -v "$PWD":/home/jovyan/work gboeing/osmnx:latest
После загрузки, в адресной строке веб-браузера набирается http://localhost:8888.
В качестве примера будем использовать датасет, содержащий информацию о местах Нью-Йорка, где можно пожить некоторое время (для простоты мы будем называть их отелями). Скачать его можно на сайте Kaggle — онлайн-площадке соревнований по Machine Learning. Перед началом импортируем нужные библиотеки и прочитаем датасет:
import osmnx as ox import networkx as nx import pandas as pd data = pd.read_csv('AB_NYC_2019.csv')
Вот так выглядят некоторые из атрибутов датасета:
Ключевыми атрибутами для нас являются географические координаты — долгота longitude и ширина latitude. Ход выполнения работы можно также посмотреть в видеобзоре.
Определяем подходящий отель
Попробуем найти отели, удовлетворяющие нашим условиям. Например, они должны:
- находиться в Манхэттене;
- быть недорогими;
- предоставлять комнату на 1 или 2 ночи;
- быть популярными (иметь количество отзывов больше среднего);
- иметь приватный тип комнаты;
- быть доступными для бронирования хотя бы больше 300 дней.
Подобные условия можно выполнить, воспользовавшись булевой индексацией Pandas, которую мы обсуждали тут. Для этого напишем следующий код:
target = data[ (data.neighbourhood_group == 'Manhattan') & (data.price < data.price.quantile(.2)) & (data.minimum_nights < 3) & (data.number_of_reviews > data.number_of_reviews.mean()) & (data.room_type == 'Private room') & (data.availability_365 > 300) ]
Стоит отметить, второе условие указывает на то, что цена проживания должна быть меньше 0.2 квантиля, что соответствует $60.
Таким образом, после фильтрации мы получили 18 отелей Манхэттена.
Строим на карте отели и Эмпайр-стейт-билдинг с OSMnx
Построим полученные отели на карте Манхэттена. В первую очередь, нужно получить граф c помощью функции graph_from_place
Python-библиотеки OSMnx. В качестве аргументов она получает запрос к Open Street Map в виде местоположения. Также можно указать вид передвижения (пешком, на машине, на велосипеде и т.д.). Мы пойдем пешком:
G = ox.graph_from_place('Manhattan, New York, USA', network_type='walk')
Далее, метод plot_graph
построит карту (граф). Он принимает аргументом вычисленный граф. Кроме того, выделим точками на карте полученные отели, а также Эмпайр-стейт-билдинг. Так как метод plot_graph
использует библиотеку matplotlib
, то мы имеем право добавить свои данные, например, с помощью метода scatter
, о котором шла речь тут.
lat_target = target.latitude # массив координат отелей lng_target = target.longitude lat_ESB = 40.748817 # координаты Эмпайр-стейт-билдинг lng_ESB = -73.985428 fig, ax = ox.plot_graph(G, figsize=(5,5), close=False, show=False) ax.scatter(lng_target, lat_target, c='red', s=100) # точки отелей ax.scatter(lng_ESB, lat_ESB, c='green', s=500) # точка Эмпайр-стейт-билдинг
Стоит отметить, для того чтобы иметь возможность редактировать карту, аргументы show
и close
должны быть равны False
. В результате получили:
Нахождение кратчайшего пути до Эмпайр-стейт-билдинг в OSMnx
Определим кратчайший путь от отеля до Эмпайр-стейт-билдинг. В первую очередь, нужно найти ближайшие ребра около точек: для отелей используется функция get_nearest_edges
. Если точка всего одна, то нужен метод get_nearest_edge
:
nearest_edges = ox.get_nearest_edges(G, lng_target, lat_target) nearest_edge_ESB = ox.get_nearest_edge(G, (lat_ESB, lng_ESB))
Стоит обратить внимание: get_nearest_edges
принимает векторы долготы и широты, соответственно, в то время как get_nearest_edge
— одну точку (кортеж).
Построим маршрут от первого отеля до Эмпайр-стейт-билдинг. Чтобы найти кратчайший путь, воспользуемся Python-библиотекой networkx [1], которая позволяет работать с графами. В этой библиотеке есть функция shortest_path
, определяющая кратчайший путь. Для построения маршрута используется функция plot_graph_route
библиотеки OSMnx:
route = nx.shortest_path(G, nearest_edge_ESB[0], nearest_edges[0][0]) fig, ax = ox.plot_graph_route(G, route, figsize=(5,5))
Результатом является карта:
Считаем затраченное время в OSMnx
Посчитаем сколько понадобится времени, чтобы добраться от первого отеля до Эмпайр-стейт-билдинг. Для этого нам нужно определить скорости (км/ч) и затраченное время маршрута (секунды):
G = ox.add_edge_speeds(G) G = ox.add_edge_travel_times(G)
Чтобы получить время необходимо просуммировать все отрезки времени:
route_times = sum(ox.utils_graph.get_route_edge_attributes(G, route, 'travel_time')) print('Затраченное время = %.0f секунд или %.0f минут' % (route_times, route_times/60))
В результате мы получили:
Затраченное время = 1189 секунд или 20 минут
Примеры можно посмотреть в github репозитории. В следующей статье поговорим о том, как решается задача регрессии на примере этого же датасета с отелями. Еще больше практических примеров работы с географическими картами в Python, вы узнаете на наших курсах в лицензированном учебном центра обучения и повышения квалификации ИТ-специалистов в Москве.