空间多边形重叠百分比,用于凸包的灵敏度分析

如何解决空间多边形重叠百分比,用于凸包的灵敏度分析

为了重现性,让我们简化我的问题,如下所示:我有100个空间多边形,这些多边形代表从总体中抽取的N个随机样本的凸包(100次),以计算模型对单个值的敏感性。 如何计算这些多边形的重叠百分比?理想的解决方案应该是快速的并引入尽可能小的近似值。

除了我认为这可能是解决问题的最简单方法之外,我没有其他理由使用R的GIS功能。

library(sp)
library(raster)
library(sf)
#> Linking to GEOS 3.8.1,GDAL 3.1.1,PROJ 6.3.1

set.seed(11)

dt <- data.frame(x = rnorm(1e3,10,3) + sample(-5:5,1e3,replace = TRUE))
dt$y <- (rnorm(1e3,3,4) + sample(-10:10,replace = TRUE)) + dt$x

dt <- rbind(dt,data.frame(x = -dt$x,y = dt$y))

plot(dt,asp = 1)

dt.chull <- dt[chull(dt),]
dt.chull <- rbind(dt.chull,dt.chull[1,])

lines(dt.chull,col = "green")

uncert.polys <- lapply(1:100,function(i) {

tmp <- dt[sample(rownames(dt),1e2),]

# points(tmp,col = "red")

tmp <- tmp[chull(tmp),]
tmp <- rbind(tmp,tmp[1,])

tmp <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(tmp)),ID = i)))

sp::SpatialPolygonsDataFrame(tmp,data = data.frame(id = i,row.names = i))

# lines(tmp,col = "red")

})

polys <- do.call(rbind,uncert.polys)

plot(polys,add = TRUE,border = "red")

我最初的尝试是使用sf::st_intersection函数:

sf.polys <- sf::st_make_valid(sf::st_as_sf(polys))
all(sf::st_is_valid(sf.polys))
#> [1] TRUE

sf::st_intersection(sf.polys)
#> Error in CPL_nary_intersection(x): Evaluation error: TopologyException: found non-noded intersection between LINESTRING (-9.80706 -0.619557,-7.66331 -3.55177) and LINESTRING (-9.80706 -0.619557,-9.80706 -0.619557) at -9.8070645468969637 -0.61955676978603658.

该错误很可能与多边形线"that are almost coincident but not identical"有关。建议使用多种解决方案(12)来解决与GEOS相关的问题,但我都没有设法处理数据:

sf.polys <- sf::st_set_precision(sf.polys,1e6) 

sf.polys <- sf::st_snap(sf.polys,sf.polys,tolerance = 1e-4)

sf::st_intersection(sf.polys)
#> Error in CPL_nary_intersection(x): Evaluation error: TopologyException: found non-noded intersection between LINESTRING (-13.7114 32.7341,3.29417 30.3736) and LINESTRING (3.29417 30.3736,3.29417 30.3736) at 3.2941702528617176 30.373627946201278.

因此,我必须使用栅格化来近似多边形重叠:

GT <- sp::GridTopology(cellcentre.offset = c(round(min(dt$x),1),round(min(dt$y),1)),cellsize = c(diff(round(range(dt$x),1))/100,diff(round(range(dt$y),1))/100),cells.dim = c(100,100)
)

SG <- sp::SpatialGrid(GT)

tmp <- lapply(seq_along(uncert.polys),function(i) {
  
  out <- sp::over(SG,uncert.polys[[i]])
  out[!is.na(out)] <- 1
  out[is.na(out)] <- 0
  out
})

tmp <- data.frame(overlapping.n = Reduce("+",lapply(tmp,"[[",1)))
tmp$overlapping.pr <- 100*tmp$overlapping.n/100

uncert.data <- SpatialGridDataFrame(SG,tmp)

## Plot


plot(x = range(dt$x),y = range(dt$y),type = "n"
)

plot(raster::raster(uncert.data),col = colorRampPalette(c("white","red","blue","white"))(100),add = TRUE)
plot(polys,border = adjustcolor("black",alpha.f = 0.2),cex = 0.5)
points(dt,pch = ".",col = "black",cex = 3)
lines(dt.chull,col = "green")

该方法可以得出结果,但是输出是近似值,需要花费很长时间进行处理。必须有一种更好的方法。

出于性能比较的目的,这是我当前的解决方案:

gridOverlap <- function(dt,uncert.polys) {
  GT <- sp::GridTopology(cellcentre.offset = c(round(min(dt$x),100)
  )
  
  SG <- sp::SpatialGrid(GT)
  
  tmp <- lapply(seq_along(uncert.polys),function(i) {
    
    out <- sp::over(SG,uncert.polys[[i]])
    out[!is.na(out)] <- 1
    out[is.na(out)] <- 0
    out
  })
  
  tmp <- data.frame(overlapping.n = Reduce("+",1)))
  tmp$overlapping.pr <- 100*tmp$overlapping.n/100
  
  SpatialGridDataFrame(SG,tmp)
}

system.time(gridOverlap(dt = dt,uncert.polys = uncert.polys))
#   user  system elapsed 
#   3.011   0.083   3.105 

对于较大的数据集,性能至关重要(此解决方案在实际应用中需要花费几分钟的时间。)

reprex package(v0.3.0)于2020-09-01创建

解决方法

这是使用spatstat查找内部而没有任何错误的解决方案 以及基础的polyclip软件包。

library(spatstat)

# Data from OP
set.seed(11)
dt <- data.frame(x = rnorm(1e3,10,3) + sample(-5:5,1e3,replace = TRUE))
dt$y <- (rnorm(1e3,3,4) + sample(-10:10,replace = TRUE)) + dt$x
dt <- rbind(dt,data.frame(x = -dt$x,y = dt$y))

# Converted to spatstat classes (`ppp` not strictly necessary -- just a habit)
X <- as.ppp(dt,W = owin(c(-25,25),c(-15,40)))
p1 <- owin(poly = dt[rev(chull(dt)),])

# Plot of data and convex hull
plot(X,main = "")
plot(p1,add = TRUE,border = "green")

# Convex hulls of sampled points in spatstat format
polys <- lapply(1:100,function(i) {
  tmp <- dt[sample(rownames(dt),1e2),]
  owin(poly = tmp[rev(chull(tmp)),])
})

# Plot of convex hulls
for(i in seq_along(polys)){
  plot(polys[[i]],border = "red")
}

# Intersection of all convex hulls plotted in transparent blue
interior <- do.call(intersect.owin,polys)
plot(interior,col = rgb(0,1,0.1))

我不清楚您要从这里做什么,但至少是这种方法 避免了多边形裁剪的错误。

要在spatstat中执行基于网格的解决方案,我会将Windows转换为 二进制图像蒙版,然后从那里开始工作:

Wmask <- as.im(Window(X),dimyx = c(200,200))
masks <- lapply(polys,as.im.owin,xy = Wmask,na.replace = 0)
maskmean <- Reduce("+",masks)/100
plot(maskmean)

速度取决于您选择的分辨率,但是我想这可能很多 比使用sp / raster的当前建议更快(这可能可以 使用与此处相同的逻辑进行了很多改进,因此这将是另一种 坚持使用raster)。

,

编辑在下面进一步改进了一个可能更好的解决方案。

对这个问题稍作思考,我的想法是三角剖分和动态编程方法可以很好地工作。

  1. 考虑每个凸包的点和线。将它们标记为它们所属的船体(可能存储在查找中)
  2. 从所有直线上取点并进行三角测量,这些三角形将被记为它们内有多少个凸包。
  3. 在这一点上,有很多方法可以确定三角形中有多少个凸包。您显示的示例倾向于一些可能的优化,但是作为一般解决方案,最佳方法可能是在每个三角形上循环并查看其中的船体O(T*H)
  4. 应该有可能记下点/边/三角形,并找出每个其中的船体(特别是每个边沿的左侧和右边是哪些船体,然后可以用来确定每个三角形中的船体(设置其中船体位于行的内侧的并集),然后从中获得三角形所在的船体数的计数。棘手的一点是如何不带O(T*H)来级联信息。并在稍后回复。

采用更好的方法进行编辑

是否应将它们的交点添加到要进行三角测量的点列表中? 减少歧义。该技术是一种线扫描算法,尤其是用于在O(Nlog(N))时间内检测交点的算法,例如https://en.wikipedia.org/wiki/Bentley%E2%80%93Ottmann_algorithm

所以这是一个更新的方法,它更直接一些包括下面的示例图像(看起来比预期的要小...) 3 convex hulls example

上图显示了3个凸包,并具有从左到右横穿每个点的扫掠线编号。尽管实际上Andrew's Algorithm for convex hulls避免了实际扫描线的需要,因为其中一个是算法的一部分。基本上,您可以使用安德鲁(Andrew)的算法一次性构建所有船体,但是具有重复性。

因此基本过程如下:

  1. 为每个已知船体(G / R / B:绿色,红色,黑色),上,下船体设置空列表。因此,每个点到它们所在的外壳的映射(初始化为空列表)。
  2. 使用安德鲁算法的排序顺序对所有点(在凸包内)进行排序。
  3. 使用与安德鲁算法相同的排序顺序,将每个点添加到每个船体(上下)。
  4. 然后,我们使用安德鲁的算法来考虑点。但诀窍在于,我们已经知道船体将是什么。考虑红色的船体,点2,7和8。其他点4和5(5实际上是2点,忘记了标签)。将添加4作为船体点,但是由于我们专注于红色船体,因此我们将忽略4(因为它不在灰色船体之内)。如果多个船体使用同一个点,则同样适用,因为从技术上讲该点不在任何一个船体之内(除非您要考虑这一点,在这种情况下,所有船体点均在至少1个船体之内,所以这样做可能会有用为了视觉上的好处,我认为这是使交点着色实用的唯一方法。但是,这两个5点都在灰色船体之内,因此我们注意到它们都在红色船体之内。总体表现为O(N * C),其中N是点数,C是船体数。我想这可能可以降为O(C log N + N log C)之类的东西,或者付出足够的努力,但可能不值得。

您可以运行设置的相交找到所有相交,然后使用它们来构建多边形以获得更精确的着色。但是,这使事情变得更加混乱,而且我仍在尝试制定一个好的解决方案。但是,我怀疑,将一个点数计算为“在其自身的船体之内”可能会对此有所帮助。在这种情况下,您可能只需取组成多边形的点的最小值。因此,如果点在1/2/2/2船壳内,则该区域在1船壳内。

我将首先在没有多个壳体的情况下对此进行测试。然后调整逻辑以支持多个船体。

为了获得最佳性能,我只会在实际的船体点上运行此算法,然后根据需要将结果(如果使用线段路线,则将颜色编码的多边形)覆盖在实际数据集的顶部。如果您没有采用颜色编码的多边形路线,那么我可能会根据它们所在的平均船体数量为多边形着色,或者使用所有点(不仅是船体点)运行算法,但这将是一个巨大的过程性能受到打击。仅对线段进行处理可能更好。

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

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res