Цель статьи — измерить расстояние и исследовать соседние точки на карте с помощью Python.

Есть вариант использования этой части, когда профессионал работает в группе экстренного реагирования и хочет определить, как больницы реагируют на аварии в Нью-Йорке. Чтобы решить эту проблему, используется анализ близости. Это решение также применимо к Covid 19 или любой другой проблеме, связанной с распространением и отслеживанием болезни.

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

import math
import geopandas as gpd
import pandas as pd
from shapely.geometry import MultiPolygon

import folium
from folium import Choropleth, Marker
from folium.plugins import HeatMap, MarkerCluster

Используемые библиотеки упоминаются в предыдущих частях этого курса. В этом случае в основном используются такие библиотеки, как math, pandas, geopandas, shapely, folium и т. д. Используются следующие карты: Choropleth, Marker, Heatmap, MarkerCluster и MultiPolygon. Начнем с этого GeoDataFrame с именами столкновений, в котором есть записи крупных столкновений автотранспортных средств между 2013 и 2018 годами. . Код и первые 5 строк кадра геоданных показаны ниже.

collisions = gpd.read_file("NYPD_Motor_Vehicle_Collisions.shp")
collisions.head()

collisions.columns

Index(['DATE', 'TIME', 'BOROUGH', 'ZIP CODE', 'LATITUDE', 'LONGITUDE',
       'LOCATION', 'ON STREET', 'CROSS STRE', 'OFF STREET', 'NUMBER OF',
       'NUMBER O_1', 'NUMBER O_2', 'NUMBER O_3', 'NUMBER O_4', 'NUMBER O_5',
       'NUMBER O_6', 'NUMBER O_7', 'CONTRIBUTI', 'CONTRIBU_1', 'CONTRIBU_2',
       'CONTRIBU_3', 'CONTRIBU_4', 'UNIQUE KEY', 'VEHICLE TY', 'VEHICLE _1',
       'VEHICLE _2', 'VEHICLE _3', 'VEHICLE _4', 'geometry'],
      dtype='object')

Список столбцов показан выше.

Давайте теперь посмотрим, как столкновения выглядят в виде тепловой карты.

m_1 = folium.Map(location=[40.7, -74], zoom_start=11) 

# Your code here: Visualize the collision data
HeatMap(data=collisions[['LATITUDE', 'LONGITUDE']], radius=11).add_to(m_1)

# Show the map
embed_map(m_1, "q_1.html")

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

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

hospitals = gpd.read_file("nyu_2451_34494.shp")
hospitals.head()

Пузырьковая карта для кадра геоданных больницы показана ниже.

m_2 = folium.Map(location=[40.7, -74], zoom_start=11) 

# Your code here: Visualize the hospital locations
for idx, row in hospitals.iterrows():
    Marker([row['latitude'], row['longitude']], popup=row['name']).add_to(m_2)
        
# Show the map
embed_map(m_2, "q_2.html")

Когда ближайшая больница находилась на расстоянии более 10 километров?

Затем создадим фрейм данных outside_range, содержащий все строки из фрейма геоданных collisions с авариями, которые произошли на расстоянии более 10 км от ближайшей больницы.

Обратите внимание, что и hospitals, и collisions используют EPSG 2263 в качестве системы отсчета, а EPSG 2263 использует единицы измерения в метрах.

coverage = gpd.GeoDataFrame(geometry=hospitals.geometry).buffer(10000)
my_union = coverage.geometry.unary_union
outside_range = collisions.loc[~collisions["geometry"].apply(lambda x: my_union.contains(x))]

percentage = round(100*len(outside_range)/len(collisions), 2)
print("Percentage of collisions more than 10 km away from the closest hospital: {}%".format(percentage))

Percentage of collisions more than 10 km away from the closest hospital: 15.12%

Создание рекомендательной системы

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

С учетом этого необходимо создать рекомендателя, который:

  • принимает в качестве входных данных местоположение сбоя (в формате EPSG 2263),
  • находит ближайшую больницу (расчет расстояния выполняется в формате EPSG 2263) и
  • возвращает название ближайшей больницы.
def best_hospital(collision_location):
    idx_min = hospitals.geometry.distance(collision_location).idxmin()
    my_hospital = hospitals.iloc[idx_min]
    name = my_hospital["name"]
    return name

# Test your function: this should suggest CALVARY HOSPITAL INC
print(best_hospital(outside_range.geometry.iloc[0]))

CALVARY HOSPITAL INC

idx_min дает индекс мест столкновений в больницахкадре геоданных. Подкадр геоданных my_hospital содержит список больниц, ближайших к местам столкновений. Название – это список только названий всех больниц, извлеченных с точки зрения близости мест столкновений. Если мы видим результат печати, CAVALRY HOSPITAL INC находится ближе всего или в верхнем индексе.

Для определения больницы с наибольшим спросом используется фрейм данных outside_range.

highest_demand = outside_range.geometry.apply(best_hospital).value_counts().idxmax()

Чтобы найти места, где должны быть построены новые больницы, нам нужно визуализировать расположение больниц в дополнение к столкновениям, которые произошли на расстоянии более 10 км от ближайшей больницы.

m_6 = folium.Map(location=[40.7, -74], zoom_start=11) 

coverage = gpd.GeoDataFrame(geometry=hospitals.geometry).buffer(10000)
folium.GeoJson(coverage.geometry.to_crs(epsg=4326)).add_to(m_6)
HeatMap(data=outside_range[['LATITUDE', 'LONGITUDE']], radius=9).add_to(m_6)
folium.LatLngPopup().add_to(m_6)

embed_map(m_6, 'm_6.html')

Город Нью-Йорк хочет выбрать места для двух совершенно новых больниц. В частности, они хотят определить места, чтобы расчетный процент был меньше 10 процентов. Используя карту (и не беспокоясь о законах о зонировании или о том, какие потенциальные здания придется снести, чтобы построить больницы), необходимо определить два места, которые помогут городу достичь этой цели.

Поместите предлагаемые широту и долготу для больницы 1 в lat_1 и long_1 соответственно. (Аналогично для больницы 2.)

Процентное значение по сравнению с предыдущим (Процент столкновений на расстоянии более 10 км от ближайшей больницы) должно сократиться до менее 10 % в целом.

# Proposed location of hospital 1
lat_1 = 40.6714
long_1 = -73.8492

# Proposed location of hospital 2
lat_2 = 40.6702
long_2 = -73.7612


# Do not modify the code below this line
try:
    new_df = pd.DataFrame(
        {'Latitude': [lat_1, lat_2],
         'Longitude': [long_1, long_2]})
    new_gdf = gpd.GeoDataFrame(new_df, geometry=gpd.points_from_xy(new_df.Longitude, new_df.Latitude))
    new_gdf.crs = {'init' :'epsg:4326'}
    new_gdf = new_gdf.to_crs(epsg=2263)

    # get new percentage
    new_coverage = gpd.GeoDataFrame(geometry=new_gdf.geometry).buffer(10000)
    new_my_union = new_coverage.geometry.unary_union
    new_outside_range = outside_range.loc[~outside_range["geometry"].apply(lambda x: new_my_union.contains(x))]
    new_percentage = round(100*len(new_outside_range)/len(collisions), 2)
    print("(NEW) Percentage of collisions more than 10 km away from the closest hospital: {}%".format(new_percentage))
    
    # Did you help the city to meet its goal?
    q_6.check()
    
    # make the map
    m = folium.Map(location=[40.7, -74], zoom_start=11) 
    folium.GeoJson(coverage.geometry.to_crs(epsg=4326)).add_to(m)
    folium.GeoJson(new_coverage.geometry.to_crs(epsg=4326)).add_to(m)
    for idx, row in new_gdf.iterrows():
        Marker([row['Latitude'], row['Longitude']]).add_to(m)
    HeatMap(data=new_outside_range[['LATITUDE', 'LONGITUDE']], radius=9).add_to(m)
    folium.LatLngPopup().add_to(m)
    display(embed_map(m, 'q_6.html'))
except:
    q_6.hint()



(NEW) Percentage of collisions more than 10 km away from the closest hospital: 9.12%

Чтобы объяснить приведенный выше код, два новых набора значений широты и долготы используются для создания нового фрейма геоданных. Мы повторяем шаги, описанные выше, чтобы получить новое процентное значение. Если процент ‹ 10 %, то тепловая карта создается по покрытию столкновений (с использованием new_coverage, основанного на новом кадре геоданных с близостью столкновений более 10 км). Затем определяются 2 местоположения (рекомендуется) в соответствии с новыми местоположениями широты и долготы, где новые больницы могут быть созданы при условии процента столкновений более чем 10 км от ближайшей больницысоставляет менее 10 % (в данном случае 9,12 %). Созданная карта выглядит следующим образом.

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

На этом мы заканчиваем серию Курс по геопространственному анализу. Ссылка из здесь. Следите за обновлениями и ищите статьи об автоматизации Python, примеры использования машинного обучения и НЛП, а также различные проекты. Подпишитесь на меня и скажите привет.

Отличный набор ресурсов по теме Наука о геопространственных данных с использованием Python.