生成多个随机(x,y)坐标,不包括重复?

时间:2013-10-29 20:30:18

标签: python math random coordinates

我想生成一个从0到2500的束(x,y)坐标,它排除彼此相差200的点而不递归。

现在我查看所有以前的值列表,看看是否有足够远的所有值。这是非常低效的,如果我需要生成大量的点,它需要永远。

那我该怎么做呢?

5 个答案:

答案 0 :(得分:12)

这是Hank Ditton建议的一个变体,它应该在时间和记忆方面更有效,特别是如果你从所有可能的点中选择相对较少的点。这个想法是,每当生成一个新点时,其中200个单位内的所有内容都会被添加到一组要排除的点中,所有新生成的点都会被检查。

import random

radius = 200
rangeX = (0, 2500)
rangeY = (0, 2500)
qty = 100  # or however many points you want

# Generate a set of all points within 200 of the origin, to be used as offsets later
# There's probably a more efficient way to do this.
deltas = set()
for x in range(-radius, radius+1):
    for y in range(-radius, radius+1):
        if x*x + y*y <= radius*radius:
            deltas.add((x,y))

randPoints = []
excluded = set()
i = 0
while i<qty:
    x = random.randrange(*rangeX)
    y = random.randrange(*rangeY)
    if (x,y) in excluded: continue
    randPoints.append((x,y))
    i += 1
    excluded.update((x+dx, y+dy) for (dx,dy) in deltas)
print randPoints

答案 1 :(得分:6)

我会过度生成点target_N < input_N,并使用KDTree过滤它们。例如:

import numpy as np
from scipy.spatial import KDTree
N   = 20
pts = 2500*np.random.random((N,2))

tree = KDTree(pts)
print tree.sparse_distance_matrix(tree, 200)

会给我相互“接近”的分数。从这里开始应用任何过滤器应该很简单:

  (11, 0)   60.843426339
  (0, 11)   60.843426339
  (1, 3)    177.853472309
  (3, 1)    177.853472309

答案 2 :(得分:3)

一些选项:

  • 使用您的算法,但使用kd-tree实施,以加快最近邻居的查找
  • 在[0,2500] ^ 2方格上构建一个规则网格,并以网格中每个交叉点为中心的二维正态分布随机“摇动”所有点
  • 绘制大量随机点,然后应用k-means算法并仅保留质心。它们将相距很远,算法虽然是迭代的,但可以比你的算法更快收敛。

答案 3 :(得分:2)

这已经得到了解答,但它与我的工作非常相关,所以我对它进行了一次尝试。我实现了this note中描述的算法,我在this blog post找到了该算法。不幸的是,它并不比其他提议的方法快,但我确信有优化措施。

import numpy as np
import matplotlib.pyplot as plt

def lonely(p,X,r):
    m = X.shape[1]
    x0,y0 = p
    x = y = np.arange(-r,r)
    x = x + x0
    y = y + y0

    u,v = np.meshgrid(x,y)

    u[u < 0] = 0
    u[u >= m] = m-1
    v[v < 0] = 0
    v[v >= m] = m-1

    return not np.any(X[u[:],v[:]] > 0)

def generate_samples(m=2500,r=200,k=30):
    # m = extent of sample domain
    # r = minimum distance between points
    # k = samples before rejection
    active_list = []

    # step 0 - initialize n-d background grid
    X = np.ones((m,m))*-1

    # step 1 - select initial sample
    x0,y0 = np.random.randint(0,m), np.random.randint(0,m)
    active_list.append((x0,y0))
    X[active_list[0]] = 1

    # step 2 - iterate over active list
    while active_list:
        i = np.random.randint(0,len(active_list))
        rad = np.random.rand(k)*r+r
        theta = np.random.rand(k)*2*np.pi

        # get a list of random candidates within [r,2r] from the active point
        candidates = np.round((rad*np.cos(theta)+active_list[i][0], rad*np.sin(theta)+active_list[i][1])).astype(np.int32).T

        # trim the list based on boundaries of the array
        candidates = [(x,y) for x,y in candidates if x >= 0 and y >= 0 and x < m and y < m]

        for p in candidates:
            if X[p] < 0 and lonely(p,X,r):
                X[p] = 1
                active_list.append(p)
                break
        else:
            del active_list[i]

    return X

X = generate_samples(2500, 200, 10)
s = np.where(X>0)
plt.plot(s[0],s[1],'.')

结果:

Resulting sample pattern

答案 4 :(得分:0)

每个链接上,来自aganders3的方法被称为Poisson Disc Sampling。您也许可以找到更有效的实现,这些实现使用本地网格搜索来查找“重叠”。例如Poisson Disc Sampling。因为您要约束系统,所以它不能完全是随机的。平面中半径均匀的圆的最大堆积约为90%,当圆以理想的六边形排列排列时可达到最大堆积。当您要求的点数接近理论极限时,生成的排列将变得更加六角形。以我的经验,使用这种方法很难使均匀圆圈的填充率达到60%以上。