生成具有最小距离的随机x和y坐标

5

在R中,是否有一种方法可以生成具有最小距离的随机坐标?

例如,我想避免以下情况

x <- c(0,3.9,4.1,8)
y <- c(1,4.1,3.9,7)
plot(x~y)

2
你如何定义“最小距离”? - LAP
1
最小欧几里得距离?例如,生成的点之间至少有1的距离。 - unknown
5个回答

7
这是一个关于随机几何的经典问题。在空间中完全随机的点,其中落入不相交区域的点数彼此独立,对应于均匀泊松点过程(在这种情况下是在R^2中,但几乎可以是在任何空间中)。
一个重要特征是,在你有不相交区域中的点数之前,总点数必须是随机的才能获得独立性。
对于泊松过程,点可以任意靠近。如果你通过对泊松过程进行抽样,直到没有任何太靠近的点为止,那么你就得到了所谓的Gibbs Hardcore过程。这在文献中得到了广泛的研究,并且有不同的模拟方法。R包spatstat有用于执行此操作的函数。rHardcore是一个完美的采样器,但如果你想要高强度的点和大硬核距离,它可能无法在有限时间内终止...该分布可以作为马尔可夫链的极限得到,rmh.default让您运行具有给定Gibbs模型作为其不变分布的马尔可夫链。这将在有限时间内完成,但仅提供近似分布的实现。
rmh.default中,您还可以在固定点数的条件下模拟。请注意,在有限的框中进行采样时,对于给定的硬核半径,能够适合多少个点当然是有上限的,而且越接近这个极限,从分布中正确地采样就越成问题。
例子:
library(spatstat)
beta <- 100; R = 0.1
win <- square(1) # Unit square for simulation
X1 <- rHardcore(beta, R, W = win) # Exact sampling -- beware it may run forever for some par.!
plot(X1, main = paste("Exact sim. of hardcore model; beta =", beta, "and R =", R))

minnndist(X1) # Observed min. nearest neighbour dist.
#> [1] 0.102402

Approximate simulation

model <- rmhmodel(cif="hardcore", par = list(beta=beta, hc=R), w = win)
X2 <- rmh(model)
#> Checking arguments..determining simulation windows...Starting simulation.
#> Initial state...Ready to simulate. Generating proposal points...Running Metropolis-Hastings.
plot(X2, main = paste("Approx. sim. of hardcore model; beta =", beta, "and R =", R))

minnndist(X2) # Observed min. nearest neighbour dist.
#> [1] 0.1005433

基于点数的近似模拟条件

X3 <- rmh(model, control = rmhcontrol(p=1), start = list(n.start = 42))
#> Checking arguments..determining simulation windows...Starting simulation.
#> Initial state...Ready to simulate. Generating proposal points...Running Metropolis-Hastings.
plot(X3, main = paste("Approx. sim. given n =", 42))

minnndist(X3) # Observed min. nearest neighbour dist.
#> [1] 0.1018068

谢谢您的出色回答!您知道我如何实现这个问题的一维版本吗?即在一维空间中随机选择点,使得每个点与相邻点之间的距离至少为r单位。 - tyumru
一个简单的方法是按顺序生成点之间的距离,其中 X 是指数分布,公式为 r+X。可能需要一个新的问题来提供更多细节。 - Ege Rubak

2

好的,那么这样怎么样?你只需生成没有限制的随机数对,然后删除那些太接近的数。这可以是一个很好的开始:

minimumDistancePairs <- function(x, y, minDistance){
    i <- 1
    repeat{
        distance <- sqrt((x-x[i])^2 + (y-y[i])^2) < minDistance # pythagorean theorem
        distance[i] <- FALSE # distance to oneself is always zero
        if(any(distance)) { # if too close to any other point
            x <- x[-i] # remove element from x
            y <- y[-i] # and remove element from y
        } else { # otherwise...
            i = i + 1 # repeat the procedure with the next element
        }
        if (i > length(x)) break
    }
    data.frame(x,y)
}

minimumDistancePairs(
    c(0,3.9,4.1,8)
    , c(1,4.1,3.9,7)
    , 1
)

会导致

x   y
1 0.0 1.0
2 4.1 3.9
3 8.0 7.0

需要注意的是,无论您如何解决问题,这些数字都不再是随机的。


1
你可以使用拒绝抽样https://en.wikipedia.org/wiki/Rejection_sampling
原理很简单:重复抽样,直到数据符合条件。
> set.seed(1)
> 
> x <- rnorm(2)
> y <- rnorm(2)
> (x[1]-x[2])^2+(y[1]-y[2])^2
[1] 6.565578
> while((x[1]-x[2])^2+(y[1]-y[2])^2 > 1) {
+   x <- rnorm(2)
+   y <- rnorm(2)
+ }
> (x[1]-x[2])^2+(y[1]-y[2])^2
[1] 0.9733252
> 

谢谢。我认为这是我见过的最好的方法建议。 - unknown
我不这么认为。这种方法只适用于2个点。它不会检查一个点是否与先前生成的点具有足够的距离。要么我误解了问题,要么这不是答案。 - Georgery

1
以下是一种天真的试错方法,对于某些参数选择(在问题中未指定)效果很好。如果性能成为问题,您可以尝试使用 gpuR 包,该包具有 GPU 加速的距离矩阵计算功能。
rand.separated <- function(n,x0,x1,y0,y1,d,trials = 1000){
  for(i in 1:trials){
    nums <- cbind(runif(n,x0,x1),runif(n,y0,y1))
    if(min(dist(nums)) >= d) return(nums)
  }
  return(NA) #no luck
}

这个程序会在区间[x0,x1]x[y0,y1]中重复抽取大小为n的样本,并且如果样本不符合要求就会被抛弃。作为安全措施,trials可以防止无限循环。如果难以找到解决方案或者n很大,您可能需要增加或减少trials
例如:
> set.seed(2018)
> nums <- rand.separated(25,0,10,0,10,0.2)
> plot(nums)

该段文字的英译中文如下:

几乎瞬间运行并生成: 在此输入图片描述

保留了HTML格式,没有进行解释。

1
更改如下:您需要使用1:trials而不是seq_along(trials)。 目前它只执行一次复制。 - unknown
@DomBurns 尴尬的错误 -- 感谢您的纠正 - John Coleman
@JohnColeman,这似乎是我感兴趣的解决方案(在此So Q here中)。是否可以将坐标设置为两个组,使它们分别位于左侧和右侧?任何线索都会有所帮助。 - user5249203

-3

我不确定你在问什么。

如果你想要随机坐标,可以在这里找到。

c(
runif(1,max=y[1],min=x[1]),
runif(1,max=y[2],min=x[2]),
runif(1,min=y[3],max=x[3]),
runif(1,min=y[4],max=x[4])
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接