В пространственном анализе часто возникает задача объединения набора геоданных в агрегированные показатели, где каждая точка или объект имеет различную значимость. Взвешенная агрегация в геоинформационных вычислениях подразумевает учет дополнительного числового параметра — веса, влияющего на вклад каждого объекта в итоговый результат. В Turf.js подобные операции реализуются через комбинацию базовых геометрических функций и пользовательских вычислений над GeoJSON-структурами.
В Turf.js все пространственные данные представлены в формате GeoJSON. Типичная структура включает:
Feature<Point> — точечные объектыFeature<Polygon> — полигональные областиFeatureCollection — набор объектовВес обычно хранится в свойствах объекта:
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [71.4304, 51.1282]
},
properties: {
value: 120,
weight: 0.7
}
}
Поле weight не является стандартным для Turf.js, но
широко используется как пользовательская метрика для агрегирования
значений.
В Turf.js отсутствует универсальная встроенная функция взвешенного среднего, поэтому применяется комбинация операций:
Формально:
{x} =
где:
Часто агрегация выполняется внутри геометрической области. Для этого
используется @turf/within или
@turf/booleanPointInPolygon в сочетании с перебором
коллекций.
Пример логики:
import * as turf from "@turf/turf";
const points = turf.featureCollection([
turf.point([71.4, 51.1], { value: 10, weight: 0.2 }),
turf.point([71.5, 51.2], { value: 20, weight: 0.5 }),
turf.point([71.6, 51.3], { value: 30, weight: 1.0 })
]);
const polygon = turf.polygon([[
[71.3, 51.0],
[71.7, 51.0],
[71.7, 51.4],
[71.3, 51.4],
[71.3, 51.0]
]]);
Фильтрация точек по полигону:
const inside = points.features.filter(pt =>
turf.booleanPointInPolygon(pt, polygon)
);
После отбора объектов выполняется агрегация:
let weightedSum = 0;
let weightTotal = 0;
inside.forEach(f => {
const w = f.properties.weight ?? 1;
const v = f.properties.value ?? 0;
weightedSum += v * w;
weightTotal += w;
});
const result = weightTotal === 0 ? 0 : weightedSum / weightTotal;
Такой подход используется для вычисления:
Функция turf.collect применяется для сбора свойств
точек, попадающих в полигон, и формирования массива значений внутри
полигонального объекта.
const collected = turf.collect(
polygon,
points,
"value",
"values"
);
Результат:
{
type: "Feature",
properties: {
values: [10, 20, 30]
}
}
После этого взвешивание выполняется вручную:
const values = collected.features[0].properties.values;
const avg = values.reduce((acc, v) => acc + v, 0) / values.length;
Для взвешенной версии необходимо параллельно собирать веса через дополнительную структуру или расширение данных.
Обобщенный паттерн агрегации в Turf.js строится на
reduce:
const aggregated = points.features.reduce(
(acc, f) => {
const w = f.properties.weight ?? 1;
const v = f.properties.value ?? 0;
acc.sum += v * w;
acc.weight += w;
return acc;
},
{ sum: 0, weight: 0 }
);
const weightedAverage = aggregated.sum / aggregated.weight;
Такой подход масштабируется на:
Часто данные агрегируются не по полигонам, а по регулярной сетке.
Turf.js предоставляет squareGrid и
hexGrid.
const bbox = [71.0, 51.0, 72.0, 52.0];
const grid = turf.squareGrid(bbox, 0.1);
Далее каждая ячейка заполняется точками:
const enriched = grid.features.map(cell => {
const pts = points.features.filter(p =>
turf.booleanPointInPolygon(p, cell)
);
let sum = 0;
let wsum = 0;
pts.forEach(p => {
const w = p.properties.weight || 1;
sum += p.properties.value * w;
wsum += w;
});
cell.properties.avg = wsum ? sum / wsum : null;
return cell;
});
Такой подход используется для построения heatmap-подобных визуализаций.
Хотя Turf.js предоставляет turf.centroid, он вычисляет
геометрический центр без учета значений свойств. Для взвешенного центра
применяется пользовательская формула:
x_c = , y_c =
Реализация:
let xSum = 0;
let ySum = 0;
let wSum = 0;
points.features.forEach(f => {
const [x, y] = f.geometry.coordinates;
const w = f.properties.weight ?? 1;
xSum += x * w;
ySum += y * w;
wSum += w;
});
const weightedCentroid = [
xSum / wSum,
ySum / wSum
];
Такой центр используется для:
В Turf.js присутствует @turf/clusters-kmeans, который
группирует точки по пространственной близости. Взвешивание добавляется
после кластеризации:
const clustered = turf.clustersKmeans(points, {
numberOfClusters: 3
});
const clusterStats = {};
clustered.features.forEach(f => {
const cluster = f.properties.cluster;
const w = f.properties.weight || 1;
const v = f.properties.value || 0;
if (!clusterStats[cluster]) {
clusterStats[cluster] = { sum: 0, wsum: 0 };
}
clusterStats[cluster].sum += v * w;
clusterStats[cluster].wsum += w;
});
Результат позволяет анализировать не только географическое распределение, но и значимость объектов внутри групп.
Для непрерывных пространственных полей применяется kernel density
analysis через @turf/point-grid и последующую интерполяцию.
Взвешивание усиливает вклад более значимых точек, формируя сглаженные
поверхности.
Общая схема:
Такой подход используется в:
В реальных задачах применяется комбинация методов:
В результате формируются многослойные пространственные модели, где каждая ячейка или кластер содержит набор статистических характеристик, основанных на взвешенных вычислениях над GeoJSON-структурами Turf.js.