R: sfnetworks: Как найти маршруты между несколькими точками A и B в одном наборе данных
Это мой набор данных
df<-tribble(
~"shop.x",~"shop.y", ~"cust.x", ~"cust.y",
78.100378, 9.944226, 78.096318, 9.954789,
78.101155, 9.932190, 78.089824, 9.929975,
78.141887, 9.928319, 78.110863, 9.952235,
78.100381, 9.944226, 78.104066, 9.97013,
78.097206, 9.948872, 78.11631, 9.947862
)
В наборе данных df указаны местоположения магазинов и покупателей.
Я хочу создать кратчайший путь для каждой строки (для каждого магазина до местоположения покупателя), используя карту OSM в R. Возможно ли использование sfnetworks?
1 ответ
Во-первых, поскольку этот фрейм данных содержит в основном координаты по X и Y для магазинов и покупателей, я конвертирую их в
sf
объекты. По два предмета в каждом наборе.
# Load packages
library(tidyverse)
library(sf)
library(sfnetworks)
library(tidygraph)
# Load the data
df <- tribble(
~"shop.x",~"shop.y", ~"cust.x", ~"cust.y",
78.100378, 9.944226, 78.096318, 9.954789,
78.101155, 9.932190, 78.089824, 9.929975,
78.141887, 9.928319, 78.110863, 9.952235,
78.100381, 9.944226, 78.104066, 9.97013,
78.097206, 9.948872, 78.11631, 9.947862
)
# Convert into sf objects
shop = st_as_sf(df[,1:2], crs = 4326, coords = c("shop.x", "shop.y"))
cust = st_as_sf(df[,3:4], crs = 4326, coords = c("cust.x", "cust.y"))
Дороги
LINESTRINGS
который можно преобразовать в
sfnetwork
объект. Сеть нужно почистить. Подробнее о предварительной обработке сети здесь.
## I downloaded the data attached and saved it locally
roads_dir = "data/roads.shp"
roads = st_read(roads_dir, crs = 4326)
#> Reading layer `Roads' from data source
#> Simple feature collection with 6915 features and 0 fields
#> Geometry type: LINESTRING
#> Dimension: XY
#> Bounding box: xmin: 78.0217 ymin: 9.832762 xmax: 78.22482 ymax: 10.04193
#> Geodetic CRS: WGS 84
# Convert into an sfnetwork
roads_sfn = as_sfnetwork(roads, directed = FALSE)
# Do some network cleaning
roads_clean = roads_sfn %>%
convert(to_spatial_subdivision, .clean = TRUE) %>%
convert(to_spatial_smooth, .clean = TRUE)
Чтобы вычислить пути, мы можем использовать функцию сопоставления
st_network_paths()
функция, передающая аргумент from с местоположением магазинов и аргумент to с местоположением покупателей. Следовательно, пути рассчитываются по порядку для каждой комбинации.
# Calculate the specified paths.
paths = mapply(
st_network_paths,
from = shop,
to = cust,
MoreArgs = list(x = roads_clean)
)["node_paths", ] %>%
unlist(recursive = FALSE)
#> although coordinates are longitude/latitude, st_nearest_points assumes that they are planar
#> although coordinates are longitude/latitude, st_nearest_points assumes that they are planar
#> Warning: Although argument from has length > 1, only the first element is used
Результатом является список из пяти элементов, содержащий индексы узлов для каждого маршрута, которые соответствуют узлам в исходной сети.
paths[[1]]
#> [1] 1842 1843 12191 12190 232 7977 7843 12174 8244 8205 7914 8139
#> [13] 8209 7958 7957 8229 8230 8328
Если мы хотим получить путь как саму сеть, мы можем разрезать исходную сеть следующим образом:
roads_clean %>%
activate("nodes") %>%
slice(paths[[1]])
#> # A sfnetwork with 18 nodes and 17 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # An unrooted tree with spatially explicit edges
#> #
#> # Node Data: 18 x 1 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 78.09568 ymin: 9.943727 xmax: 78.10051 ymax: 9.955158
#> geometry
#> <POINT [°]>
#> 1 (78.10001 9.946228)
#> 2 (78.10051 9.943727)
#> 3 (78.10017 9.945039)
#> 4 (78.09918 9.951894)
#> 5 (78.09895 9.953372)
#> 6 (78.09647 9.955099)
#> # ... with 12 more rows
#> #
#> # Edge Data: 17 x 3
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 78.09568 ymin: 9.943727 xmax: 78.10051 ymax: 9.955158
#> from to geometry
#> <int> <int> <LINESTRING [°]>
#> 1 2 3 (78.10051 9.943727, 78.10029 9.944423, 78.10017 9.945039)
#> 2 6 7 (78.09647 9.955099, 78.09877 9.954435)
#> 3 12 13 (78.09569 9.955158, 78.09568 9.954763)
#> # ... with 14 more rows