Геометрия + атрибуты: модель данных

Урок показывает, что геообъект — это всегда связка формы и таблицы, и именно поэтому ГИС так удобно ложится на привычные инструменты анализа данных.

Атрибуты — это таблица свойств объектов, в которой к обычным колонкам добавлена особая колонка с геометрией.

Если в прошлом уроке мы разобрали форму объектов, то теперь — их смысл. Полигон сам по себе — просто набор точек; он становится «городом Казань с населением 1,3 млн» только когда к геометрии приклеена строка таблицы с атрибутами. Эта двойственность — мост между ГИС и обычной аналитикой данных: если вы знаете Pandas, вы уже наполовину знаете векторную ГИС.

Таблица, в которой есть фигуры

Представьте набор городов. В классической таблице это выглядело бы так:

namepopulationgeometry
Москва13 000 000POINT(37.62 55.75)
Казань1 300 000POINT(49.11 55.80)

Колонки name и population — обычные атрибуты, с ними можно делать всё, что вы делаете в таблицах: фильтровать, сортировать, группировать, считать средние. Колонка geometry — особенная: по ней работают пространственные операции (расстояние, попадание в зону, пересечение). Промышленная библиотека GeoPandas — это буквально Pandas с такой геометрической колонкой.

Атрибутивные запросы против пространственных

Запросы к такой таблице бывают двух видов. Атрибутивный запрос смотрит только в обычные колонки: «города с населением больше миллиона». Пространственный запрос смотрит в геометрию: «города в радиусе 300 км от Москвы». Самое интересное — комбинация: «города-миллионники в радиусе 300 км». Покажем атрибутивную часть на чистом Python, моделируя таблицу списком словарей:

cities = [
    {"name": "Москва", "pop": 13_000_000, "lat": 55.75, "lon": 37.62},
    {"name": "Казань", "pop": 1_300_000, "lat": 55.80, "lon": 49.11},
    {"name": "Тула", "pop": 460_000, "lat": 54.20, "lon": 37.62},
    {"name": "Самара", "pop": 1_140_000, "lat": 53.20, "lon": 50.10},
]

# Атрибутивный запрос: миллионники, отсортированные по населению
millionniki = [c for c in cities if c["pop"] >= 1_000_000]
millionniki.sort(key=lambda c: c["pop"], reverse=True)
for c in millionniki:
    print(f"{c['name']}: {c['pop'] // 1000} тыс.")

Вывод:

Москва: 13000 тыс.
Казань: 1300 тыс.
Самара: 1140 тыс.

Как работает под капотом

Внутри ГИС геометрия чаще всего хранится в одном из двух стандартов консорциума OGC: WKT (Well-Known Text, человекочитаемый, как POINT(37.62 55.75)) и WKB (Well-Known Binary, компактный двоичный для базы). База данных строит по геометрической колонке пространственный индекс (обычно R-дерево), который по ограничивающим прямоугольникам быстро отсекает заведомо далёкие объекты — иначе пространственный запрос перебирал бы все миллионы строк. Этот индекс — причина, по которой PostGIS отвечает на «что рядом» за миллисекунды.

Частые ошибки

  • Хранить координаты как текст в разных форматах. «55.75 N» и «55,75» и «55°45'» — кошмар. Геометрию держат в единой числовой модели.
  • Смешивать объекты разной геометрии в одном слое. Слой обычно однороден: либо точки, либо линии, либо полигоны.
  • Терять связь геометрии и атрибутов. Если переставить строки в одной таблице, не тронув другую, — данные «разъедутся».

Двойственность, на которой стоит вся ГИС

Связка «геометрия плюс атрибуты» — не техническая деталь, а фундаментальная идея, объясняющая, почему ГИС так удобно ложится на знакомые инструменты. Половина любого пространственного проекта — это обычная работа с таблицей: отфильтровать объекты по свойству, сгруппировать, посчитать сумму или среднее, соединить с другой таблицей по ключу. Всё это вы умеете из мира Pandas и SQL, и в ГИС оно работает один в один. Геометрия добавляет вторую половину — пространственные операции, — но не отменяет первую. Поэтому переход к геоданным для аналитика данных мягкий: новый только геометрический столбец и горстка функций над ним.

Эта двойственность определяет и архитектуру инструментов. GeoPandas буквально наследует от Pandas, добавляя класс GeoSeries для геометрической колонки, — и потому все привычные методы DataFrame продолжают работать. PostGIS добавляет к таблицам PostgreSQL тип geometry, не меняя обычный SQL. Даже формат данных отражает идею: в GeoJSON каждый Feature — это properties (атрибуты) рядом с geometry (форма). Осознав, что геообъект — это «строка таблицы, у которой одна ячейка содержит фигуру», вы перестаёте видеть в ГИС отдельную загадочную дисциплину и начинаете видеть знакомую работу с данными, обогащённую пространством.

Итог

  • Геообъект = строка таблицы, где одна колонка — геометрия.
  • Атрибутивные запросы работают по обычным колонкам, пространственные — по геометрии.
  • GeoPandas — это Pandas плюс геометрическая колонка.
  • Пространственный индекс (R-дерево) делает запросы «что рядом» быстрыми.
Проверьте себя
1. Что общего у векторной ГИС и библиотеки Pandas?
AОбе работают только с растрами
BГеообъект — это строка таблицы атрибутов плюс геометрическая колонка
CОбе не умеют фильтровать данные
DНи то ни другое не хранит координаты
2. Чем атрибутивный запрос отличается от пространственного?
AНичем
BАтрибутивный смотрит в обычные колонки, пространственный — в геометрию
CПространственный работает только с текстом
DАтрибутивный требует спутник
3. Зачем базе пространственный индекс (R-дерево)?
AЧтобы рисовать карту
BЧтобы быстро отсекать далёкие объекты и не перебирать все строки
CЧтобы хранить картинки
DОн не нужен