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
Другие вопросы по тегам