R:如何将 osmdata 的运行时间减少为 igraph 转换

标签 r openstreetmap igraph sf overpass-api

是否可以减少以下代码的运行时间?
我的目标是从框边界指定的开放街道数据区域中获取加权 igraph 对象。
目前我正在尝试使用立交桥 api 来卸载内存负载,这样我就不必在内存中保留大的 osm 文件。
首先我得到一个由bbox(仅街道)指定的osm数据作为xml结构

library(osmdata)
library(osmar)
install.packages("remotes")
remotes::install_github("hypertidy/scgraph")
library(scgraph)


dat <- opq(bbox = c(11.68771, 47.75233, 12.35058, 48.19743 )) %>%
  add_osm_feature(key = 'highway',value = c("trunk", "trunk_link", "primary","primary_link", "secondary", "secondary_link", "tertiary","tertiary_link", "residential", "unclassified" ))%>% 
  osmdata_xml ()
然后我转换生成的 xml 对象 数据 到 osmar 对象 dat_osmar 最后到了 igraph 目的:
dat_osmar <-as_osmar(xmlParse(dat))
dat_graoh <- as_igraph(dat_osmar)
我怎样才能优化这些例程?
也许可以分开数据 (XML) 对象成块并并行解析?
我经历了几个步骤,最后才得到一个加权的非有向图。
目前,整个过程在我的机器上需要 89.555 秒。
如果我可以减少这两个步骤的运行时间:
dat_osmar <-as_osmar(xmlParse(dat))
dat_graoh <- as_igraph(dat_osmar)
那会有所帮助。
我尝试的方法之一是使用 osmdata_sc() 而不是 osmdata_xml() .
这提供了一个硅酸盐对象,我可以将其转换为:
scgraph::sc_as_igraph(dat)
到 igraph。
它相当快,但遗憾的是重量正在丢失,因此它不是解决方案。
原因是:如果我使用来自 的转换奥斯玛 反对 igraph 具有函数 osmar::as_igraph() 的对象权重根据两条边之间的距离计算并添加到 igraph 中:
    edges <- lapply(dat, function(x) {
    n <- nrow(x)
    from <- 1:(n - 1)
    to <- 2:n
    weights <- distHaversine(x[from, c("lon", "lat")], x[to, 
      c("lon", "lat")])
    cbind(from_node_id = x[from, "ref"], to_node_id = x[to, 
      "ref"], way_id = x[1, "id"], weights = weights)
  })
scgraph::sc_as_igraph(dat) 中缺少此信息
如果这可以添加到 硅酸盐 igraph 转换
我可以跳过 dat_osmar <-as_osmar(xmlParse(dat))
然后去 overpass->silicate->igraphoverpass->xml->osmar->igraph 快得多的路由.
osmdata 包还提供了顺丰回复 osmdata_sf()
所以也许是工作流程 overpass->sf->igraph速度更快,但在使用这种方式时,我需要根据边的距离将权重合并到图中,而我目前还不够好,并且非常感谢任何帮助。
此外,在使用 sf 和生成的 igraph 对象时,不应丢失 openstreetmap gps 点及其 ID 之间的连接。这意味着我应该能够从生成的 Igraph 中找到一个 ID 的 GPS 位置。一个查找表就足够了。如果我去 overpass->silicate->igraphoverpass->xml->osmar->igraph路线是可能的。我不确定 overpass->sf->igraph 是否仍然可行路线。

最佳答案

如果您想从 R 中的道路网络开始创建图形对象,那么我将使用以下过程。
首先,我需要安装sfnetworks来自 github repo(因为我们最近修复了一些错误并且最新版本不在 CRAN 上)

remotes::install_github("luukvdmeer/sfnetworks", quiet = TRUE)
然后加载包
library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(tidygraph)
#> 
#> Attaching package: 'tidygraph'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(sfnetworks)
library(osmdata)
#> Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
从 Overpass API 下载数据
my_osm_data <- opq(bbox = c(11.68771, 47.75233, 12.35058, 48.19743 )) %>%
  add_osm_feature(
    key = 'highway', 
    value = c("trunk", "trunk_link", "primary","primary_link", "secondary", "secondary_link", "tertiary","tertiary_link", "residential", "unclassified")
  ) %>% 
  osmdata_sf(quiet = FALSE)
#> Issuing query to Overpass API ...
#> Rate limit: 2
#> Query complete!
#> converting OSM data to sf format
现在我提取道路并构建 sfnetwork 对象:
system.time({
  # extract the roads
  my_roads <- st_geometry(my_osm_data$osm_lines)
  
  # build the sfnetwork object
  my_sfn <- as_sfnetwork(my_roads, directed = FALSE, length_as_weight = TRUE)
})
#>    user  system elapsed 
#>    3.03    0.16    3.28
如您所见,下载 OSM 数据后,只需几秒钟即可运行该过程。
目前我忽略了 my_osm_data$osm_lines 中的所有字段,但如果您需要在 my_osm_data$osm_lines 中添加一些列至 my_roads ,那么可以修改前面的代码如下:my_roads <- my_osm_data$osm_lines[, "relevant columns"] .
关于 sfnetwork 结构的一些细节对象:参数"directed = FALSE"指定我们要构建一个无向图(参见文档,herehere 了解更多详细信息),而参数 length_as_weight = TRUE表示边的长度将存储在名为 "weight" 的列中。并被 igraph 和 tidygraph 算法使用。
这是my_sfn的打印目的:
my_sfn
#> # A sfnetwork with 33179 nodes and 28439 edges
#> #
#> # CRS:  EPSG:4326 
#> #
#> # An undirected multigraph with 6312 components with spatially explicit edges
#> #
#> Registered S3 method overwritten by 'cli':
#>   method     from         
#>   print.boxx spatstat.geom
#> # Node Data:     33,179 x 1 (active)
#> # Geometry type: POINT
#> # Dimension:     XY
#> # Bounding box:  xmin: 11.6757 ymin: 47.74745 xmax: 12.39161 ymax: 48.22025
#>                     x
#>           <POINT [°]>
#> 1 (11.68861 47.90971)
#> 2 (11.68454 47.90937)
#> 3 (11.75216 48.17638)
#> 4 (11.75358 48.17438)
#> 5  (11.7528 48.17351)
#> 6 (11.74822 48.17286)
#> # ... with 33,173 more rows
#> #
#> # Edge Data:     28,439 x 4
#> # Geometry type: LINESTRING
#> # Dimension:     XY
#> # Bounding box:  xmin: 11.6757 ymin: 47.74745 xmax: 12.39161 ymax: 48.22025
#>    from    to                                                           x weight
#>   <int> <int>                                            <LINESTRING [°]>  <dbl>
#> 1     1     2 (11.68861 47.90971, 11.6878 47.90965, 11.68653 47.90954, 1~   306.
#> 2     3     4 (11.75216 48.17638, 11.75224 48.17626, 11.75272 48.17556, ~   246.
#> 3     5     6 (11.7528 48.17351, 11.75264 48.17344, 11.75227 48.17329, 1~   382.
#> # ... with 28,436 more rows
my_sfn根据定义是一个 igraph 对象:
class(my_sfn)
#> [1] "sfnetwork" "tbl_graph" "igraph"
但是,如果你想更明确,那么
as.igraph(my_sfn)
#> IGRAPH 101dcdf U-W- 33179 28439 -- 
#> + attr: x (v/x), x (e/x), weight (e/n)
#> + edges from 101dcdf:
#>  [1]   1--  2   3--  4   5--  6   7--  8   9-- 10  11-- 12  13-- 14  15-- 16
#>  [9]  17-- 18  16-- 19  20-- 21  21-- 22  23-- 24  25-- 26  27-- 28  29-- 30
#> [17]  31-- 32  33-- 34  35-- 36  37-- 38  39-- 40  41-- 42  43-- 44  45-- 46
#> [25]  14-- 47  48-- 49  50-- 51  52-- 53  54-- 55  56-- 57  36-- 58  58-- 59
#> [33]  60-- 61  62-- 63  64-- 65  66-- 67  68-- 69  70-- 71  72-- 73  74-- 75
#> [41]  76-- 77  78-- 79  80-- 81  82-- 83  84-- 85  86-- 87  88-- 89  90-- 91
#> [49]  92-- 93  94-- 95  96-- 97  98-- 99 100--101 102--103 104--105 106--107
#> [57] 108--109 110--111 112--113  80--114 115--116 117--118 119--120 121--122
#> + ... omitted several edges
您可以看到边具有一个权重属性,该属性等于每个 LINESTRING 几何图形的长度:
all.equal(
  target = igraph::edge_attr(as.igraph(my_sfn), "weight"), 
  current = as.numeric(st_length(my_roads))
)
#> [1] TRUE
创建于 2021-03-26 由 reprex package (v1.0.0)
如果您想阅读有关 sfnetworks 的更多详细信息,然后您可以查看 websiteintroductory vignettes .话虽这么说,我不明白你的意思

connection between openstreetmap gps points and their IDs should not be lost


您能否通过评论或对原始问题的编辑添加更多详细信息?为什么需要 OSM id?你说的 OSM id 是什么意思?我想我需要更多细节来扩展这个答案。
编辑
我刚刚重新阅读了@mrhellmann 的回答,我注意到我忘记将 POLYGON 数据转换为行。无论如何,我建议申请 osmdata::osm_poly2line()运行代码后立即通过 Overpass API 下载 OSM 数据。

关于R:如何将 osmdata 的运行时间减少为 igraph 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66760786/

相关文章:

r - 将模型与dplyr和broom::glance: How to continue if error is produced?进行比较

r - 使用带有 xml2 的管道运算符编写 XML

java - 在 JAVA 应用程序中使用 Osmosis 库

installation - 在 Windows 上为 python 3.6 安装 python-igraph

Mac OS X 上的自定义 igraph igraph_get_shortest_paths_dijkstra 函数

来自 Git 存储库的 R studio 项目,自签名证书问题

r - 使用 XMPP 协议(protocol)通过 R 发送 Google Talk 和 Facebook 消息

Javascript地理定位找不到位置信息

java - 如何在 Android Native Activity 中通过 Java 查询 Overpass Turbo 以确定高速公路的分类?

r 从数据框中的列创建邻接矩阵