如何排除R中一条线以外的点

How to exclude points beyond a line in R

我在 R 中使用两个数据帧:一个“红色”数据帧和一个“黑色”数据帧。两者都有两列代表坐标。
我用了一个情节来解释我想做什么。

我想select“红色”数据框中超出“黑色”线的所有点。例如。从由黑点分隔的多边形区域中排除的所有点。

您可以使用 sf 包来定义一个凸包并将您的目标点与该多边形相交。

根据black定义一个凸包:

library(sf)

set.seed(99)
red <- data.frame(x = runif(100,-10,10), y = runif(100,-4,4))
black <- data.frame(x = runif(100,-8,8), y = runif(100,-4,3))

# Convert df to point feature
blk <- st_as_sf(black, coords = c("x", "y"))
# Convert to multipoint
blk_mp <- st_combine(blk)
# Define convex hull
blk_poly <- st_convex_hull(blk_mp)

plot(black)
points(red, col = "red")
plot(blk_poly, add = TRUE)

在该多边形内 red 与凸包 returns red 相交:

rd <- st_as_sf(red, coords = c("x", "y"))
rd_inside <- st_intersection(rd, blk_poly)

plot(black)
points(red)
plot(blk_poly, add = TRUE)
plot(rd_inside, pch = 24, col = "red", bg = "red", add = TRUE)

一种可能的解决方案是在点之后绘制多边形并将其外部区域填充为白色。这不能直接用 polygonpolypath 完成,因为这些函数只能填充多边形的内部。但是,您可以用 polypath 填充两个多边形 之间 的区域。因此,您可以添加第二个包含(或超出)绘图边界的多边形。

这是一个在 base R 中工作的例子:

p.outer <- list(x=c(0,100,100,0), y=c(0,0,100,100))
p.inner <- list(x=c(20,40,80,50,40,30), y=c(30,20,70,80,50,60))
plot(p.outer, type="n")
points(runif(100, min=0, max=100), runif(100, min=0, max=100))
polypath(x=c(p.outer$x, NA, p.inner$x), y = c(p.outer$y, NA, p.inner$y), col ="white", rule="evenodd")

似乎您可以通过简单地将每个点连接到它的最近邻点和它在相反方向上的最近邻点来重建黑色多边形的边缘。然后执行 point-in-polygon 测试。

我之前的回答只说明了如何不绘制多边形外的点。要实际 识别 多边形外的点,您可以使用包 ptinpoly 中的函数 pip2d。它 returns 多边形外的点的负值。

示例:

library(ptinpoly)
poly.vertices <- data.frame(x=c(20,40,80,50,40,30), y=c(30,20,70,80,50,60))
p <- data.frame(x=runif(100, min=0, max=100), y=runif(100, min=0, max=100))

outside <- (pip2d(as.matrix(poly.vertices), as.matrix(p)) < 0)

plot(p$x, p$y, col=ifelse(outside, "red", "black"))
polygon(poly.vertices$x, poly.vertices$y, border="blue", col=NA)

DescTools 中的函数 PtInPoly 也可以实现同样的效果,对于多边形外的点,returns 为零。然而,ptinpoly 的实施具有实施

中描述的特别有效算法的优势

J. Liu, Y.Q. Chen, J.M. Maisog, G. Luta: "A new point containment test algorithm based on preprocessing and determining triangles." Computer-Aided Design, Volume 42, Issue 12, December 2010, Pages 1143-1150

编辑: 出于好奇,我将 ptinpoly::pip2dDescTools::PtInPoly 的运行时间与微基准和 N=50000 点进行了比较,并且 pip2d 结果要快得多:

> microbenchmark(outside.pip2d(), outside.PtInPoly())
Unit: milliseconds
              expr       min        lq      mean   median        uq      max
   outside.pip2d()  3.375084  3.421631  4.459051  3.48939  4.251395 65.97793
outside.PtInPoly() 27.537927 27.666688 28.739288 27.97984 28.514595 90.11313

尼瓦尔 100 100

按照@cdalitz 的建议,使用 DescTools 包的 PtInPoly 函数,我解决了这个问题。此函数返回点坐标的数据框(在我的例子中为红色坐标)和第三列“pip”1(如果点在多边形内)和 0s(如果在多边形外)。

我将使用另一个数据集向您展示结果:

 try <- DescTools::PtInPoly(pnts = red[,c("x","y")], poly.pnts = black[,c("x","y")])

 ggplot()+
      geom_point(try, mapping = aes(x = x, y = y, color = as.character(pip))) +
      geom_polygon(data = black, mapping = aes(x,y))