Суммирование атрибутов

В основе работы с пространственными данными в Turf.js лежит модель GeoJSON, где каждая сущность представлена объектом Feature, содержащим геометрию и набор атрибутов в properties. Суммирование атрибутов — базовый механизм аналитики, применяемый для вычисления статистик по наборам пространственных объектов: суммарной площади, количества населения, стоимости объектов, длины маршрутов и любых пользовательских метрик.

В Turf.js отсутствует отдельная универсальная функция «sum attributes», поскольку библиотека ориентирована на композицию примитивов и работу через обход коллекций. Суммирование реализуется через модуль мета-функций и стандартные JavaScript-операции накопления.


Модель данных и источник атрибутов

Каждый объект GeoJSON имеет структуру:

{
  "type": "Feature",
  "geometry": { ... },
  "properties": {
    "value": 10,
    "population": 5000
  }
}

Суммирование выполняется по одному или нескольким ключам в properties. Важный принцип: Turf.js не изменяет исходные данные, а использует обход без мутаций.


Обход коллекций через @turf/meta

Модуль @turf/meta предоставляет набор низкоуровневых функций для работы с любыми GeoJSON структурами.

featureEach

Итерация по всем Feature в FeatureCollection:

import { featureEach } from "@turf/meta";

let sum = 0;

featureEach(geojson, (feature) => {
  sum += feature.properties.value || 0;
});

Механизм работы:

  • перебор всех объектов коллекции
  • доступ к properties
  • накопление значения в переменной

propEach

Используется для обхода только атрибутов без привязки к геометрии:

import { propEach } from "@turf/meta";

let total = 0;

propEach(geojson, (properties) => {
  total += properties.value || 0;
});

Различие:

  • featureEach даёт доступ к геометрии и атрибутам
  • propEach работает исключительно с атрибутами

coordEach (косвенное суммирование через геометрию)

Хотя координаты редко суммируются напрямую, функция полезна при вычислении производных значений:

import { coordEach } from "@turf/meta";

let coordinateSum = 0;

coordEach(geojson, (coord) => {
  coordinateSum += coord[0]; // сумма долгот
});

Базовый паттерн суммирования

Наиболее распространённый подход — ручная агрегация:

let total = 0;

for (const feature of geojson.features) {
  total += Number(feature.properties.value) || 0;
}

Этот подход:

  • минимален по накладным расходам
  • не требует дополнительных зависимостей
  • легко расширяется до сложной логики

Суммирование с проверкой типов

В реальных данных атрибуты часто содержат строки, null или отсутствующие значения:

import { featureEach } from "@turf/meta";

let total = 0;

featureEach(geojson, (feature) => {
  const value = feature.properties.value;

  if (typeof value === "number" && !Number.isNaN(value)) {
    total += value;
  }
});

Обработка типов предотвращает:

  • некорректные конкатенации строк
  • NaN в результате операций
  • пропуски данных

Множественные атрибуты и вектор сумм

Часто требуется суммировать несколько полей одновременно:

import { featureEach } from "@turf/meta";

const sum = {
  population: 0,
  area: 0,
  revenue: 0
};

featureEach(geojson, (feature) => {
  const p = feature.properties;

  sum.population += p.population || 0;
  sum.area += p.area || 0;
  sum.revenue += p.revenue || 0;
});

Такой подход используется при построении агрегированных статистик для регионов.


Условное суммирование

Агрегация часто выполняется с фильтрацией по атрибутам:

import { featureEach } from "@turf/meta";

let total = 0;

featureEach(geojson, (feature) => {
  if (feature.properties.type === "urban") {
    total += feature.properties.value || 0;
  }
});

Условия могут включать:

  • категориальные фильтры
  • числовые диапазоны
  • пространственно-атрибутивные комбинации

Суммирование с использованием turf.area

При анализе полигонов часто требуется вычислить суммарную площадь:

import area from "@turf/area";
import { featureEach } from "@turf/meta";

let totalArea = 0;

featureEach(polygons, (feature) => {
  totalArea += area(feature);
});

Особенности:

  • площадь вычисляется в квадратных метрах
  • поддерживаются только полигоны и мультиполигоны
  • результат зависит от геодезической модели

Суммирование длин линий

Для линейных объектов используется length из Turf.js:

import length from "@turf/length";
import { featureEach } from "@turf/meta";

let totalLength = 0;

featureEach(lines, (feature) => {
  totalLength += length(feature, { units: "kilometers" });
});

Применение:

  • дорожные сети
  • маршруты доставки
  • инженерные коммуникации

Группировка и суммирование

Более сложный сценарий — агрегирование по категориям:

import { featureEach } from "@turf/meta";

const groups = {};

featureEach(geojson, (feature) => {
  const key = feature.properties.region;

  if (!groups[key]) {
    groups[key] = 0;
  }

  groups[key] += feature.properties.value || 0;
});

Результат — объект агрегированных значений:

  • ключ — категория
  • значение — сумма

Reduce-подход как универсальная форма агрегации

JavaScript reduce позволяет выразить суммирование декларативно:

const total = geojson.features.reduce((acc, feature) => {
  return acc + (feature.properties.value || 0);
}, 0);

Этот стиль:

  • компактный
  • функциональный
  • легко комбинируется с map/filter

Суммирование с пространственными ограничениями

Часто данные ограничиваются географически:

import bbox from "@turf/bbox";
import booleanPointInPolygon from "@turf/boolean-point-in-polygon";

const polygon = ...;

let total = 0;

featureEach(points, (feature) => {
  if (booleanPointInPolygon(feature, polygon)) {
    total += feature.properties.value || 0;
  }
});

Используется для:

  • анализа зон покрытия
  • подсчёта объектов в пределах области
  • региональной статистики

Производительность при больших наборах данных

При работе с тысячами и миллионами объектов важны следующие оптимизации:

  • минимизация обращения к вложенным объектам
  • предварительное извлечение ссылок на properties
  • использование обычных циклов вместо сложных цепочек функций
  • избегание лишних вызовов Turf-функций внутри циклов

Пример оптимизированного варианта:

const features = geojson.features;
let sum = 0;

for (let i = 0; i < features.length; i++) {
  sum += features[i].properties.value || 0;
}

Суммирование после трансформаций

Turf.js часто используется как этап обработки перед агрегацией:

import buffer from "@turf/buffer";
import { featureEach } from "@turf/meta";

const buffered = buffer(points, 5, { units: "kilometers" });

let totalArea = 0;

featureEach(buffered, (feature) => {
  totalArea += feature.properties.area || 0;
});

Пайплайн:

  • геометрическое преобразование
  • обогащение атрибутами
  • последующая агрегация

Атрибутная агрегация в аналитических цепочках

Суммирование редко используется изолированно. Оно является частью цепочек:

  • фильтрация (boolean-intersects, within)
  • трансформация (buffer, transform-scale)
  • измерение (area, length)
  • агрегация (sum, mean, count)

Типовой аналитический контур:

featureEach(dataset, (feature) => {
  if (feature.properties.category === "A") {
    result += feature.properties.value;
  }
});

Обработка отсутствующих и разреженных данных

При работе с реальными источниками данных важно учитывать:

  • отсутствие ключей
  • null значения
  • смешанные типы данных

Универсальная защита:

const value = Number(feature.properties.value);
if (Number.isFinite(value)) {
  sum += value;
}

Композиция суммирования с другими агрегатами

Сумма часто вычисляется вместе с другими метриками:

let sum = 0;
let count = 0;

featureEach(geojson, (feature) => {
  const v = feature.properties.value;

  if (typeof v === "number") {
    sum += v;
    count++;
  }
});

const average = sum / count;

Это базовая форма статистического анализа внутри Turf.js-экосистемы.