微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

查找R中多边形的最近邻居

如何解决查找R中多边形的最近邻居

我有一个数据框,其坐标已这样转换为R中的sf对象:

> head(df1)
  Cell_ID   Spot_ID       X       Y
1       0 600000000 193.722 175.733
2       0 600000001 192.895 176.727
3       0 600000002 193.828 177.462
4       8 600000003 178.173 178.220
5       7 600000004 187.065 178.285
6       0 600000005 190.754 178.186

> df1_sf <- st_as_sf(df1,coords = c('X','Y')) %>%
    group_by(Cell_ID) %>%
    summarise() %>%
    ungroup() %>%  
    st_convex_hull()
>plot(st_geometry(df1_sf),border = "red")

然后我可以绘制所有多边形,看起来像这样:

enter image description here

现在,我想获取每个多边形的邻居的ID。为此,我正在做

n = st_set_geometry(st_intersection(df1_sf,df1_sf),NULL)
head(n)
# A tibble: 6 x 2
  Cell_ID Cell_ID.1
    <int>     <int>
1       0         0
2       7         0
3      51         0
4       1         1
5       4         1
6       5         1

但是这做得很平庸,因为它需要一个交集,而我也对它们是否是最接近的交集感兴趣(接近,尽管没有像下面的图所示那样触摸,但Cell_ID 1将作为邻居单元3-6,但是也将检测像元7,因为它在给定的半径内)。 有人可以帮我解决这个问题吗?

谢谢!

enter image description here

解决方法

为说明在每个多边形周围使用缓冲区的绝佳建议 (每个多边形的数学膨胀)在这里是一种快速而肮脏的spatstat 解决方案。

首先加载软件包并制作一些示例数据:

library(spatstat)
dat <- tiles(dirichlet(cells))
ii <- seq(2,42,by=2)
dat[ii] <- lapply(dat[ii],erosion,r = .01)
dat <- lapply(seq_along(dat),function(i) cbind(Cell_ID = i,as.data.frame(dat[[i]])))
dat <- Reduce(rbind,dat)
df1 <- cbind(Spot_ID = 1:nrow(dat),dat)
head(df1)
#>   Spot_ID Cell_ID         x         y
#> 1       1       1 0.4067780 0.0819020
#> 2       2       1 0.3216680 0.1129640
#> 3       3       1 0.1967080 0.0000000
#> 4       4       1 0.4438430 0.0000000
#> 5       5       2 0.5630909 0.1146781
#> 6       6       2 0.4916145 0.1649979

为每个Cell_ID拆分,找到凸包并绘制数据:

dat <- split(df1[,c("x","y")],df1$Cell_ID)
dat <- lapply(dat,convexhull)
plot(owin(),main = "")
for(i in seq_along(dat)){
  plot(dat[[i]],add = TRUE,border = "red")
}

扩大每个多边形:

bigdat <- lapply(dat,dilation,r = 0.0125)

进行天真的for循环分配,以指定哪些膨胀多边形重叠(即完全 n ^ 2个成对相交):

neigh <- list()
for(i in seq_along(bigdat)){
  overlap <- sapply(bigdat[-i],function(x) !is.empty(intersect.owin(x,bigdat[[i]])))
  neigh[[i]] <- which(overlap)
}

绘制具有邻居数量的膨胀多边形(邻居的ID在 列表neigh):

plot(owin(),main = "")
for(i in seq_along(bigdat)){
  plot(bigdat[[i]],border = "red")
}
text.ppp(cells,labels = sapply(neigh,length))

基于细分的解决方案

是否需要使用凸包作为单元格的定义 地区?我很想简单地用质心表示每个单元 采样点,然后使用Dirichlet / Voronoi镶嵌作为 地区。这些到处都有明确定义的邻居,唯一的问题是 如何定义细胞集合的边界区域。

对每个Cell_ID进行拆分,找到质心,细分并绘制数据:

dat <- split(df1[,df1$Cell_ID)
dat <- t(sapply(dat,colMeans))
X <- as.ppp(dat,W = ripras)
D <- dirichlet(X)
plot(D)

用于查找邻居ID的其他代码:

eps <- sqrt(.Machine$double.eps) # Epsilon for numerical comparison below
tilelist <- tiles(D)
v_list <- lapply(tilelist,vertices.owin)
v_list <- lapply(v_list,function(v){ppp(v$x,v$y,window = Window(X),check = FALSE)})
neigh <- list()
dd <- safedeldir(X)
for(i in seq_len(npoints(X))){
  ## All neighbours from deldir (infinite border tiles)
  all_neigh <- c(dd$delsgs$ind1[dd$delsgs$ind2==i],dd$delsgs$ind2[dd$delsgs$ind1==i])
  ## The remainder keeps only neighbour tiles that share a vertex with tile i:
  true_neigh <- sapply(v_list[all_neigh],function(x){min(nncross.ppp(v_list[[i]],x))}) < eps
  neigh[[i]] <- sort(all_neigh[true_neigh])
}
plot(D,main = "Tessellation with Cell_ID")
text(X)

neigh[[1]] # Neighbours of tile 1
#> [1] 2 7 8
neigh[[10]] # Neighbours of tile 10
#> [1]  3  4  5  9 15 16 20
,

从您的问题来看,您似乎对通用的最近邻居类型方法更感兴趣。如果这过于简单,请纠正我。

只需考虑中心坐标并使用任何knn类型算法将k nearest neighbours分类到给定坐标即可,而不是考虑每个多边形及其边界。

由于我无权访问您的数据,因此创建了一些虚拟坐标。 使用软件包RANN和函数nn2 see here

install.packages('RANN')
library(RANN)

# Make dummy coordinates
df <- 
  data.frame(   X = runif(100),Y = runif(100)
               )

# Find closest 5 points between df and itself
closest <- nn2(data = df,query = df,k = 5)

closest$nn.idx # Index of Closest neigbours
closest$nn.dists # Euclidean distance of Closest neigbours

# Note the first colum is a reference to itself,so real 5 nearest neighbours (not including itself) would mean you select k = 6.

> head(closest$nn.idx) # Euclidean distance of Closest neigbours
     [,1] [,2] [,3] [,4] [,5]
[1,]    1   82   31   86   49
[2,]    2   22   41   34   91
[3,]    3   96   20   55   32
[4,]    4   65   53   77   14
[5,]    5   38   48   59   30
[6,]    6   36   43   97   61

> head(closest$nn.dists) # Euclidean distance of Closest neigbours
     [,1]       [,2]       [,3]       [,4]       [,]    0 0.04971692 0.06305752 0.08597908 0.09485483
[2,]    0 0.03668956 0.05248395 0.09570358 0.10489092
[3,]    0 0.07257007 0.10263107 0.11204297 0.13275642
[4,]    0 0.07209561 0.07227328 0.07259919 0.07326718
[5,]    0 0.02842711 0.06003873 0.08930219 0.12286905
[6,]    0 0.08018734 0.09312385 0.10844622 0.11368332

您还可以根据问题中提到的半径方法,使用searchtype = "radius"radius进行此操作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。