web-dev-qa-db-ja.com

重複を除外して、複数のランダム(x、y)座標を生成しますか?

0〜2500の束(x、y)座標を生成します。この座標は、再帰せずに互いに200以内にあるポイントを除外します。

今は、以前のすべての値のリストをチェックして、他のすべての値から十分に離れているかどうかを確認しています。これは本当に非効率的であり、大量のポイントを生成する必要がある場合、それは永遠にかかります。

だから私はこれをどうやってやろうか?

23
user2901745

これは、特にすべての可能なポイントから比較的少数のポイントを選択している場合、時間とメモリに関してより効率的であるはずのハンク・ディトンの提案の変形です。アイデアは、新しいポイントが生成されるたびに、その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
12
jwodder

ポイントを過剰生成します、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
6
Hooked

いくつかのオプション:

  • アルゴリズムを使用しますが、 kd-tree で実装します。これにより、最近傍の検索が高速化されます
  • [0、2500] ^ 2の正方形に規則的なグリッドを構築し、グリッドの各交点を中心とした二次元正規分布ですべてのポイントをランダムに「振る」
  • 多数のランダムポイントを描画してから、 k-means アルゴリズムを適用し、重心のみを保持します。それらは互いに遠く離れ、アルゴリズムは反復的ではありますが、アルゴリズムよりも速く収束する可能性があります。
3
damienfrancois

これは答えられましたが、それは私の仕事に非常に接線的に関連しているので、私はそれを突きました。 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

2
aganders3

リンクごとに、aganders3のメソッドはポアソンディスクサンプリングとして知られています。ローカルグリッド検索を使用して「重複」を見つけるより効率的な実装を見つけることができる場合があります。たとえば、 ポアソンディスクサンプリング 。システムを制約しているため、完全にランダムにすることはできません。平面内の半径が均一な円の最大パッキングは〜90%で、円が完全な六角形の配列に配置されている場合に達成されます。要求するポイントの数が理論上の制限に近づくと、生成される配置はより六角形になります。私の経験では、このアプローチを使用して均一な円で〜60%を超えるパッキングを得るのは困難です。

0
Ender