web-dev-qa-db-ja.com

彼らの座標を与えて、最も遠いポイントを得る方法?

10000行ages (float), titles (enum/int), scores (float), ...のボーリングCSVがあります。

  • テーブル内のint/float値を持つn列があります。
  • これをND空間のポイントとして想像することができます
  • 私たちは互いに最大化された距離があるだろうkポイントを選びたいです。

だから私たちが厳密に詰まったクラスターに100ポイントを持っていて、距離の1つのポイントの場合、私たちは3つのポイントのようなものを手に入れるでしょう: enter image description here またはこれを enter image description here

4点の場合、それはより面白くなり、真ん中にある点を選ぶでしょう。

それで、nから最も遠い行(ポイント)を選択する方法(複雑さと一緒に)? 3Dポイントではなく、特定の解像度を持つND点群の「三角測量」のように見えます。

K = 200およびn = 100000およびNd = 6(KDTreeベース、SOMまたは三角測量に基づく)のために、かなり速いアプローチを検索します(おそらく、KDTreeベース、SOMまたは三角測量)..誰もが知っていますか?

10
DuckQueen

私はおおよその解を提案する。このアイデアは、以下に説明する方法で選択されたkポイントのセットから始めて、これらの点を繰り返しループして、現在のものをセットに属していないn-k + 1ポイントのうち、現在のものは、セットの点からの距離の合計を最大にします。この手順は、任意の単一点の置き換えがセットの点間の距離の合計を減少させるようなk点のセットをもたらす。

プロセスを開始するには、すべてのポイントの平均に最も近いKポイントを取ります。このようにして、最初のループでは、k点のセットが最適に近づくように拡散されることをお勧めします。その後の反復は、n、k、およびndの現在の値に対して数秒で到達可能であるように見えるように見えるように見えるように見えるように見える。エッジケースで過度のループを防ぐために、それにもかかわらずループの数を制限します。

繰り返しがKポイントの間の合計距離を向上させない場合は繰り返します。もちろん、これは極大値です。他の地元の最大値は、初期の条件で、または一度に複数の交換を可能にすることによって達成されますが、私はそれが価値があるとは思わない。

ユークリッドの距離が意味のあるものであるために、各次元における単位変位のために、すなわち、データを調整する必要があります。例えば、あなたの寸法が給与と子供の数であるならば、未調整されていない、アルゴリズムはおそらく極度の給与地域に集中した結果をもたらすでしょう。より現実的な出力を得るためには、子供の標準偏差によって、または子供の数の違いに匹敵する給与の違いがある他の見積もりによって、給料と数を分けることができます。

ランダムなガウス分布の出力をプロットできるようにするには、コードに_ND = 2_を設定しましたが、要求に従って_ND = 6_を設定しますが、問題ありません(プロットできないことを除く)。

_import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial as spatial

N, K, ND = 100000, 200, 2
MAX_LOOPS = 20

SIGMA, SEED = 40, 1234
rng = np.random.default_rng(seed=SEED)
means, variances = [0] * ND, [SIGMA**2] * ND
data = rng.multivariate_normal(means, np.diag(variances), N)

def distances(ndarray_0, ndarray_1):
    if (ndarray_0.ndim, ndarray_1.ndim) not in ((1, 2), (2, 1)):
        raise ValueError("bad ndarray dimensions combination")
    return np.linalg.norm(ndarray_0 - ndarray_1, axis=1)

# start with the K points closest to the mean
# (the copy() is only to avoid a view into an otherwise unused array)
indices = np.argsort(distances(data, data.mean(0)))[:K].copy()
# distsums is, for all N points, the sum of the distances from the K points
distsums = spatial.distance.cdist(data, data[indices]).sum(1)
# but the K points themselves should not be considered
# (the trick is that -np.inf ± a finite quantity always yields -np.inf)
distsums[indices] = -np.inf
prev_sum = 0.0
for loop in range(MAX_LOOPS):
    for i in range(K):
        # remove this point from the K points
        old_index = indices[i]
        # calculate its sum of distances from the K points
        distsums[old_index] = distances(data[indices], data[old_index]).sum()
        # update the sums of distances of all points from the K-1 points
        distsums -= distances(data, data[old_index])
        # choose the point with the greatest sum of distances from the K-1 points
        new_index = np.argmax(distsums)
        # add it to the K points replacing the old_index
        indices[i] = new_index
        # don't consider it any more in distsums
        distsums[new_index] = -np.inf
        # update the sums of distances of all points from the K points
        distsums += distances(data, data[new_index])
    # sum all mutual distances of the K points
    curr_sum = spatial.distance.pdist(data[indices]).sum()
    # break if the sum hasn't changed
    if curr_sum == prev_sum:
        break
    prev_sum = curr_sum

if ND == 2:
    X, Y = data.T
    marker_size = 4
    plt.scatter(X, Y, s=marker_size)
    plt.scatter(X[indices], Y[indices], s=marker_size)
    plt.grid(True)
    plt.gca().set_aspect('equal', adjustable='box')
    plt.show()
_

出力: output for Gaussian distribution

データを3つの等距離ガウス分布に分割する出力はこれです: output for 3 equidistant Gaussian distributions

3
Walter Tross

N(10000)行とDディメンション(または機能)を_N*D_ MARTIX Xに読み込む場合は、各点間の距離を計算し、次のように距離行列に保存できます。

_import numpy as np
X = np.asarray(X) ### convert to numpy array
distance_matrix = np.zeros((X.shape[0],X.shape[0]))
for i in range(X.shape[0]):
    for j in range(i+1,X.shape[0]): 
    ## We compute triangle matrix and copy the rest. Distance from point A to point B and distance from point B to point A are the same. 
        distance_matrix[i][j]= np.linalg.norm(X[i]-X[j]) ## Here I am calculating Eucledian distance. Other distance measures can also be used.

        #distance_matrix = distance_matrix + distance_matrix.T - np.diag(np.diag(distance_matrix)) ## This syntax can be used to get the lower triangle of distance matrix, which is not really required in your case.
        K = 5 ## Number of points that you want to pick

        indexes = np.unravel_index(np.argsort(distance_matrix.ravel())[-1*K:], distance_matrix.shape)

        print(indexes)
_
2