Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Пространственное объединение

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

Пространственное объединение (spatial join) — это метод, позволяющий связать атрибутивную информацию двух наборов геоданных в зависимости от их взаимного пространственного расположения.

С помощью пространственного объединения можно, например:

  • определить, к какому району относится каждая точка;

  • агрегировать данные по пространственным единицам.

В GeoPandas для выполнения таких операций используется функция sjoin, которая позволяет гибко задавать тип пространственного отношения и способ объединения данных.

В этом разделе мы разберём, как выполнять пространственные объединения и применять их для анализа геоданных.

0. Импортируем библиотеки и подготавливаем данные

0.1 Импорт библиотек

import pandas as pd  
import geopandas as gpd

0.2 Подготовка данных

В этом разделе будут использованы файлы из нашего репозитория:

  • spb_admin.gpkg — полигональные данные о границах районов и округов Санкт-Петербурга.
    Источник: материалы курса «Методы пространственного анализа», НИУ ВШЭ (Р. Гончаров)

  • spb_theaters.csv — данные о театрах Санкт-Петербурга.
    Источник: Портал открытых данных Санкт-Петербурга

Прочитаем данные о границах округов в Санкт-Петербурге (spb_admin.gpkg)

okrug_gpkg = gpd.read_file("./data/spb_admin.gpkg", layer="okrug")

okrug_gpkg.explore(tiles="cartodbpositron")
Loading...

Прочитаем данные о театрах Санкт-Петербурга из CSV-файла и создадим на их основе GeoDataFrame.

theaters_csv = pd.read_csv('./data/spb_theaters.csv')
theaters_csv= theaters_csv.dropna(subset=['longitude', 'latitude']) 

theaters_gpd = gpd.GeoDataFrame(
    theaters_csv,
    geometry=gpd.points_from_xy(theaters_csv['longitude'], theaters_csv['latitude']),
    crs = 4326
)

theaters_gpd.explore(tiles="cartodbpositron")
Loading...

1. Объединение данных

Давайте определим, в каком округе Санкт-Петербурга находится каждый из театров. Для этого выполним пространственное объединение слоя театров со слоем округов.

Вспомним, что при пространственном объединении используется один из пространственных предикатов. В данном случае нам нужно определить, внутри какого округа расположен театр, поэтому будем использовать предикат within.

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

1.1. Проверяем системы координат

Проверим, совпадают ли системы координат:

okrug_gpkg.crs == theaters_gpd.crs
True

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

1.2. Выполняем пространственное объединение

Для каждого театра определяем округ, внутри которого он расположен. Для этого используем метод sjoin, в котором указываем тип пространственного предиката within, а также способ объединения данных (how="left"), чтобы сохранить все объекты из слоя театров.

theaters_in_okrug = gpd.sjoin(
    theaters_gpd,
    okrug_gpkg,
    how="left",
    predicate="within"
)

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

Посмотрим на результат. Выведем названия театров и соответствующих им округов, используя поля так, как они заданы в исходных данных: name — для театров и NAME — для округов.

theaters_in_okrug[["name", "NAME"]].head()
Loading...

Теперь у нас есть информация о том, в каком из округов находится каждый театр

2. Агрегирование результатов

После выполнения пространственного объединения у нас есть информация о том, в каком округе расположен каждый театр. Теперь на основе этих данных можно выполнить агрегирование и, например, подсчитать количество театров в каждом округе.

Сгруппируем данные по названию округа (NAME) и подсчитаем количество театров в каждом из них. В результате получаем таблицу, где для каждого округа указано число расположенных в нём театров.

theater_counts = (
    theaters_in_okrug
    .groupby("NAME")
    .size()
    .reset_index(name="theater_count")
    .sort_values("theater_count", ascending=False)
)

theater_counts.head()
Loading...

Таким образом, пространственное объединение позволяет перейти от анализа отдельных объектов к анализу пространственных единиц.

Итог

В этом разделе мы познакомились с пространственным объединением (spatial join) — методом, позволяющим связывать данные разных слоёв на основе их пространственного расположения.

Мы рассмотрели, как с помощью функции sjoin можно сопоставлять объекты из разных слоёв на основе их пространственного расположения.

Также мы увидели, что результат пространственного объединения можно использовать для дальнейшего анализа — например, агрегирования данных и подсчёта количества объектов в пределах заданных территорий.