Build and register a k-nearest-neighbours graph between planning units using coordinates.
This constructor does not require polygon geometry. It uses planning-unit
coordinates supplied explicitly or stored in the Problem object.
Usage
add_spatial_knn(
x,
coords = NULL,
k = 8,
name = "knn",
weight_mode = c("constant", "inverse", "inverse_sq"),
distance_eps = 1e-09
)Arguments
- x
A
Problemobject created withcreate_problem.- coords
Optional coordinates specification. This may be:
a
data.frame(id, x, y), ora numeric matrix with two columns
(x, y)aligned to the order of planning units.
If
NULL, coordinates are taken fromx$data$pu_coordsor from columnsx$data$pu$xandx$data$pu$y.- k
Integer giving the number of neighbours per planning unit. Must be at least 1 and strictly less than the number of planning units.
- name
Character string giving the key under which the relation is stored.
- weight_mode
Character string indicating how distance is converted to weight. Must be one of
"constant","inverse", or"inverse_sq".- distance_eps
Small positive numeric constant used to avoid division by zero in inverse-distance weighting.
Details
Use this function when neighbourhood should be defined by a fixed number of nearby planning units rather than by polygon topology or a fixed distance threshold.
Let \(s_i = (x_i, y_i)\) denote the coordinates of planning unit
\(i\). For each planning unit, this function identifies the k
nearest distinct planning units under Euclidean distance.
If \(d_{ij}\) denotes the Euclidean distance between units \(i\) and
\(j\), then the k-nearest-neighbours relation is constructed by adding an
edge from \(i\) to each of its k nearest neighbours.
Edge weights are then assigned according to weight_mode:
"constant": $$\omega_{ij} = 1,$$"inverse": $$\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)},$$"inverse_sq": $$\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)^2},$$
where \(\varepsilon\) = distance_eps is a small constant to avoid
division by zero.
The raw k-nearest-neighbours structure is directional by construction, but
the stored relation is registered as undirected by default through
add_spatial_relations, which collapses duplicate unordered
pairs.
If the RANN package is available, it is used for efficient nearest neighbour search. Otherwise, a full distance matrix is computed.
Examples
pu_tbl <- data.frame(
id = 1:4,
cost = c(1, 2, 3, 4),
x = c(0, 1, 0, 1),
y = c(0, 0, 1, 1)
)
feat_tbl <- data.frame(
id = 1:2,
name = c("feature_1", "feature_2")
)
dist_feat_tbl <- data.frame(
pu = c(1, 1, 2, 3, 4),
feature = c(1, 2, 2, 1, 2),
amount = c(5, 2, 3, 4, 1)
)
p <- create_problem(
pu = pu_tbl,
features = feat_tbl,
dist_features = dist_feat_tbl,
cost = "cost"
)
p <- add_spatial_knn(
x = p,
k = 2,
name = "knn2",
weight_mode = "constant"
)
p$data$spatial_relations$knn2
#> internal_pu1 internal_pu2 weight pu1 pu2 distance source relation_name
#> 2 1 2 1 1 2 1 knn_constant knn2
#> 1 1 3 1 1 3 1 knn_constant knn2
#> 3 2 4 1 2 4 1 knn_constant knn2
#> 6 3 4 1 3 4 1 knn_constant knn2
