IMO 有几种方法可以为类似于输出的空间线创建邻域列表对象spdep::poly2nb
。spdep::poly2nb
不幸的是,我将在这里尝试解释一些假设(类似于 的皇后参数)。
首先我们加载一些包和数据
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(sfnetworks)
library(igraph)
#>
#> Attaching package: 'igraph'
#> The following objects are masked from 'package:stats':
#>
#> decompose, spectrum
#> The following object is masked from 'package:base':
#>
#> union
第一个解决方案是基于sf::st_touches
函数:
roxel_touches <- stplanr::geo_projected(roxel, st_touches)
roxel_touches
#> Sparse geometry binary predicate list of length 851, where the predicate was `touches'
#> first 10 elements:
#> 1: 101, 146, 493, 577, 742
#> 2: 149, 285, 294, 354, 521
#> 3: 268, 269, 270, 376, 431
#> 4: 8, 9, 276, 735
#> 5: 8, 94, 95, 108, 590
#> 6: 272, 728, 732
#> 7: 274, 275, 276, 734
#> 8: 4, 5, 95, 108, 735
#> 9: 4, 276, 281, 728
#> 10: 273, 281, 729, 733
输出是根据谓词sgbp
汇总空间线之间关系的对象。touches
例如输出的第一行表示roxel
对象的第一行接触到第 101、146、493、577 和 742 行。该stplanr::geo_projected
函数用于应用几何二元谓词函数而不重新投影数据(否则我们会得到一些警告信息)。
touches
谓词在相应的帮助页面 ( )?sf::st_touches
和此处定义。简而言之,当该点位于其边界的联合中时(即线的第一个和最后一个点) ,该sf::st_touches
函数匹配共享一个公共点的几何图形。LINESTRING
例如,以下线彼此相交,但它们不相交,因为公共点不在它们的边界内。
es_1 <- st_sfc(
st_linestring(rbind(c(0, -1), c(0, 1))),
st_linestring(rbind(c(-1, 0), c(1, 0)))
)
par(mar = rep(1, 4))
plot(es_1, col = c("red", "blue"), lwd = 2)
legend("topright", legend = c(1, 2), col = c("red", "blue"), lty = 1, lwd = 2)
![](https://i.imgur.com/u2n1t9U.png)
st_intersects(es_1)
#> Sparse geometry binary predicate list of length 2, where the predicate was `intersects'
#> 1: 1, 2
#> 2: 1, 2
st_touches(es_1)
#> Sparse geometry binary predicate list of length 2, where the predicate was `touches'
#> 1: (empty)
#> 2: (empty)
另一个稍有不同的解决方案是使用以下sf::st_relate
函数创建的:
roxel_relate <- stplanr::geo_projected(roxel, st_relate, pattern = "FF*FT****")
roxel_relate
#> Sparse geometry binary predicate list of length 851, where the predicate was `relate_pattern'
#> first 10 elements:
#> 1: 101, 146, 493, 577, 742
#> 2: 149, 285, 294, 354, 521
#> 3: 268, 269, 270, 376, 431
#> 4: 8, 9, 276, 735
#> 5: 8, 94, 95, 108, 590
#> 6: 272, 732
#> 7: 274, 275, 276, 734
#> 8: 4, 5, 95, 108, 735
#> 9: 4, 276, 281, 728
#> 10: 273, 281, 729, 733
输出(再次)是一个sgbp
对象,它根据带有 pattern 的“相关”谓词总结空间线之间的关系"FF*FT****"
。这种类型的模式用于匹配LINESTRINGS
当且仅当它们在其边界中共享至少一个点,它们的内部不相交并且内部和边界之间没有共享点。例如,以下两行是接触的,但根据模式它们不相关"FF*FT****"
。
es_2 <- st_sfc(
st_linestring(rbind(c(0, -1), c(0, 1)), "red"),
st_linestring(rbind(c(0, 0), c(1, 0)), "blue"),
crs = 32632
)
plot(es_2, col = c("red", "blue"), lwd = 2)
legend(x = "topright", legend = c(1, 2), lty = 1, col = c("red", "blue"), lwd = 2)
![](https://i.imgur.com/OZdJfsw.png)
st_touches(es_2)
#> Sparse geometry binary predicate list of length 2, where the predicate was `touches'
#> 1: 2
#> 2: 1
st_relate(es_2, pattern = "FF*FT****")
#> Sparse geometry binary predicate list of length 2, where the predicate was `relate_pattern'
#> 1: (empty)
#> 2: (empty)
您可以sf::st_relate
在sf::st_relate
. 当我们比较两个谓词的输出时,我们可以理解为什么st_touches
和之间的这种区别很重要。st_relate
roxel_touches
#> Sparse geometry binary predicate list of length 851, where the predicate was `touches'
#> first 10 elements:
#> 1: 101, 146, 493, 577, 742
#> 2: 149, 285, 294, 354, 521
#> 3: 268, 269, 270, 376, 431
#> 4: 8, 9, 276, 735
#> 5: 8, 94, 95, 108, 590
#> 6: 272, 728, 732
#> 7: 274, 275, 276, 734
#> 8: 4, 5, 95, 108, 735
#> 9: 4, 276, 281, 728
#> 10: 273, 281, 729, 733
roxel_relate
#> Sparse geometry binary predicate list of length 851, where the predicate was `relate_pattern'
#> first 10 elements:
#> 1: 101, 146, 493, 577, 742
#> 2: 149, 285, 294, 354, 521
#> 3: 268, 269, 270, 376, 431
#> 4: 8, 9, 276, 735
#> 5: 8, 94, 95, 108, 590
#> 6: 272, 732
#> 7: 274, 275, 276, 734
#> 8: 4, 5, 95, 108, 735
#> 9: 4, 276, 281, 728
#> 10: 273, 281, 729, 733
我们可以看到它们几乎相同,但在少数情况下(例如,参见第 6 行)。如果我们绘制相应的线,我们可以更好地理解这种情况:
plot(st_geometry(roxel[c(6, 272, 728, 732), ]), col = c("red", "orange", "blue", "darkgreen"), lwd = 2)
legend(x = "topright", legend = c(6, 272, 728, 732), lty = 1, col = c("red", "orange", "blue", "darkgreen"), lwd = 2)
![](https://i.imgur.com/Yj4R3B6.png)
我们可以看到第 6 行与所有其他行接触,但根据模式,它与第 728 行“无关” "FF*FT****"
。这意味着如果您从 开始创建邻居列表st_relate
,那么您(至少)缺少一个现有链接。我明确选择了这种模式,因为用于sfnetworks
从对象推断图形结构的默认算法sf
与那种模式非常相似(可能相同)。我们可以检查这个事实,创建line graph
关联到由创建的图as_sfnetwork
:
roxel_sfnetworks <- as_sfnetwork(roxel, directed = FALSE)
roxel_line_graph <- make_line_graph(roxel_sfnetworks)
roxel_adj_list <- as_adj_list(roxel_line_graph)
str(roxel_adj_list[1:10], give.attr = FALSE)
#> List of 10
#> $ : 'igraph.vs' int [1:5] 101 146 493 577 742
#> $ : 'igraph.vs' int [1:5] 149 285 294 354 521
#> $ : 'igraph.vs' int [1:5] 268 269 270 376 431
#> $ : 'igraph.vs' int [1:4] 8 9 276 735
#> $ : 'igraph.vs' int [1:5] 8 94 95 108 590
#> $ : 'igraph.vs' int [1:2] 272 732
#> $ : 'igraph.vs' int [1:4] 274 275 276 734
#> $ : 'igraph.vs' int [1:5] 4 5 95 108 735
#> $ : 'igraph.vs' int [1:4] 4 276 281 728
#> $ : 'igraph.vs' int [1:4] 273 281 729 733
并测试它们的相等性:
all(unlist(mapply(function(x, y) unique(x) == unique(y), roxel_adj_list, roxel_relate)))
#> [1] TRUE
我不得不使用该unique
函数,因为igraph
当两个顶点之间有多个边时,输出可能会返回重复的索引,即
is.simple(roxel_sfnetworks)
#> [1] FALSE
无论如何,我们可以看到输出与 相同,这意味着如果不特别考虑底层街道网络对象roxel_relate
,我们不能总是安全地使用st_relate
或运行。make_line_graph
我不想在这里添加太多细节,因为示例太复杂了,但是我们不能总是使用该st_touches
函数来推断邻居列表对象(但如果你想阅读更多关于这个主题的内容,我最近写了一个有关该主题的论文,目前正在审查中)。
无论如何,那篇论文的总结是,我认为只有在使用函数转换对象之后,我们才能安全地使用st_touches
或st_relate
函数来生成邻居列表。(实际上这两种方法之间仍然存在一些非常小的差异,但我仍然必须正确弄清楚如何解决它们。目前我会使用 st_touches)。roxel
stplanr::rnet_breakup_vertices
# 1 - Transform the input roxel object
roxel2 <- stplanr::rnet_breakup_vertices(roxel)
#> Splitting rnet object at the intersection points between nodes and internal vertexes
# 2- Apply st_touches function
roxel2_touches <- stplanr::geo_projected(roxel2, st_touches)
roxel2_touches
#> Sparse geometry binary predicate list of length 876, where the predicate was `touches'
#> first 10 elements:
#> 1: 105, 150, 504, 591, 765
#> 2: 153, 291, 300, 363, 533
#> 3: 274, 275, 276, 386, 441
#> 4: 8, 9, 282, 758
#> 5: 8, 98, 99, 112, 604
#> 6: 278, 750, 751, 755
#> 7: 280, 281, 282, 757
#> 8: 4, 5, 99, 112, 758
#> 9: 4, 282, 287, 750
#> 10: 279, 287, 752, 756
然后,如果需要,可以将结果转换为 nb 对象:
as.nb.sgbp <- function(x) {
attrs <- attributes(x)
x <- lapply(x, function(i) { if(length(i) == 0L) 0L else i } )
attributes(x) <- attrs
class(x) <- "nb"
x
}
roxel2_nb <- as.nb.sgbp(roxel2_touches)
roxel2_lw <- spdep::nb2listw(roxel2_nb)
roxel2_lw
#> Characteristics of weights list object:
#> Neighbour list object:
#> Number of regions: 876
#> Number of nonzero links: 3318
#> Percentage nonzero weights: 0.4323826
#> Average number of links: 3.787671
#>
#> Weights style: W
#> Weights constants summary:
#> n nn S0 S1 S2
#> W 876 767376 876 494.4606 3580.933
我们还可以使用“线图”选项:
str(as_adj_list(make_line_graph(as_sfnetwork(roxel2, directed = FALSE)))[1:10], give.attr = FALSE)
#> List of 10
#> $ : 'igraph.vs' int [1:5] 105 150 504 591 765
#> $ : 'igraph.vs' int [1:5] 153 291 300 363 533
#> $ : 'igraph.vs' int [1:5] 274 275 276 386 441
#> $ : 'igraph.vs' int [1:4] 8 9 282 758
#> $ : 'igraph.vs' int [1:5] 8 98 99 112 604
#> $ : 'igraph.vs' int [1:4] 278 750 751 755
#> $ : 'igraph.vs' int [1:4] 280 281 282 757
#> $ : 'igraph.vs' int [1:5] 4 5 99 112 758
#> $ : 'igraph.vs' int [1:4] 4 282 287 750
#> $ : 'igraph.vs' int [1:4] 279 287 752 756
由reprex 包(v0.3.0)于 2020 年 6 月 1 日创建
我知道我写了很多(可能是不必要的)信息,但我认为它们对于正确提供有关建议解决方案的上下文很有用。如果不清楚,请添加更多问题。