如果点落在与另一个点一定距离内,如何生成点为 'repelled' 的数据?

How do I generate data where points are 'repelled' if they land within a certain proximity to another point?

我正在使用 runifdisc 在圆盘上绘制随机点,但我不希望这些点落在其他点的某个邻近范围内。这些点目前被解析为正方形和三角形。我正在使用 spatstat 包。

有办法吗? 这是我的代码:

dots = runifdisc(210, radius=1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)

我什至可以接受这些点的均匀分布,例如在我可以设置大小的圆盘内的网格上,以确保没有重叠。

您可以编写自己的函数来执行此操作。它需要三个参数:你想要的点数,包含圆的半径,点与点之间的最小距离。

它只是从 x 和 y 的两个空向量开始,然后生成从均匀分布中抽取的随机 x、y 对。如果此 x, y 对在单位圆之外或在现有点的给定距离内,则将其丢弃并绘制另一对。否则保留该点。重复此过程,直到 x 和 y 向量已满。此时,将创建一个数据框,其中 x 和 y 值乘以所需的圆半径以生成结果。

如果在多次尝试后仍找不到放置新点的位置,则会抛出错误。给出的 210 个点的示例仅在最小距离为 0.1 时才适合:

repelled_points <- function(n, r_circle, r_clash) {
  container_x <- numeric(n)
  container_y <- numeric(n)
  j <- i <- 1
  while(i <= n)
  {
    j <- j + 1
    if(j == 100 * n) stop("Cannot accommodate the points in given space")
    x <- runif(1, -1, 1)
    y <- runif(1, -1, 1)
    if(x^2 + y^2 > 1) next
    if(i > 1) {
     dist <- sqrt((x - container_x[seq(i-1)])^2 + (y - container_y[seq(i-1)])^2)
     if(any(dist < r_clash)) next
    }
    container_x[i] <- x
    container_y[i] <- y
    i <- i + 1
    j <- 1
  }
  `class<-`(list(window = disc(centre = c(0, 0), radius = r_circle),
       n = n, x = container_x * r_circle, 
       y = container_y * r_circle, markformat = "none"), "ppp")
}

其中,当您 运行 您的绘图代码时,returns 结果如下:

dots <- repelled_points(210, 1, 0.1)
plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)

不是最优雅的解决方案,但这是一种方法

# sample_size = 3000
total_points = 210

find_repelled_dots <- function(total_points, radius = 1, min_distance = 0.1, max_iterations = 10000){
  
  # Initialize the first point
  selected_dots = runifdisc(1, radius=1)
  selected_dots = c(selected_dots$x, selected_dots$y)
  
  # Initialize iterators
  picked = 1
  i = 1
  
  while (picked < total_points & i < max_iterations) { # Either enough points or max iterations
    dots_sample = runifdisc(1, radius = radius) # Choose a data points
    selected_dots_temp = rbind(selected_dots, c(dots_sample$x, dots_sample$y)) # Find distance between existing points
    
    if (min(dist(selected_dots_temp)) > min_distance){ # If sufficiently far from all the other points, add to the mix, else try again
      picked = picked + 1 # Keep track of picked points
      selected_dots = selected_dots_temp # Update picked list
    }
    i = i + 1 # Keep track of iterations
  }
  if (i > 10000){
    stop("Max iterations passed! Increase number of iterations")
  }
  
  return(list(x = selected_dots[,1], y = selected_dots[,2]))
  
}

dots = find_repelled_dots(210)

plot(dots, type="n")
points(dots$x[1:45], dots$y[1:45], pch=15, col="red", cex=2)
points(dots$x[46:90], dots$y[46:90], pch=15, col="red", cex=2)
points(dots$x[91:151], dots$y[91:151], pch=17, col="blue", cex=2)
points(dots$x[152:210], dots$y[152:210], pch=17, col="blue", cex=2)

spatstat中有几个函数可以用最小值模拟点 距离。 rHardcore() 这些点在某种意义上独立于每个点 其他,但点数是随机的。 rSSI() 你得到一个固定的 点数(如果可能的话,在算法放弃之前):

library(spatstat)
X <- rSSI(0.1, 210, win = disc(1))

您可以将标记随机附加到点上以绘制它们 不同的字符:

marks(X) <- sample(c(rep("a", 90), rep("b", 120)))
plot(X, main = "", cols = c("red", "blue"))

这不是特别快。

spatstat中有函数可以做到这一点,包括rSSIrMaternIrMaternIIrHardcorerStraussrmh。这取决于你希望点如何“到达”以及它们应该如何“排斥”。

  • rSSI:点数一一到达。每个点都是随机放置的,条件是它不会离现有点太近。当不可能在任何地方放置新点时游戏停止(“简单顺序抑制”)
  • rMaternI:积分同时到达。然后删除太靠近另一点的任何点。 (物质抑制模型 1)
  • rMaternII:积分在一定时间内随机到达。他们的到达时间被记录下来。在此期间结束时,任何与另一点 较早到达的点 太近的点都将被删除。 (物质抑制模型 2)
  • rHardcorermh:点数不断到达,随机时间,永远。如果新到达的点太靠近现有点,则会被拒绝并删除。现有点的生命周期有限,并在其生命周期结束时被删除。这个过程运行好久,然后拍个快照。 (使用空间生灭过程模拟的吉布斯硬核过程)。

spatstat中的函数已经过彻底调试和测试,因此我建议尽可能使用它们而不是编写新代码。

有关文档,请参阅 the spatstat book

的第 5.5 节和第 13 章