26

k << 100 万の k クラスターにグループ化する必要がある 100 万の 5 次元ポイントがあります。各クラスターでは、2 つのポイントが離れすぎてはなりません (たとえば、指定された半径の境界球である可能性があります)。つまり、おそらくサイズ 1 のクラスターが多数存在するはずです。

しかし!実行時間がn ^ 2をはるかに下回る必要があります。n log n 程度で十分です。このクラスタリングを行っている理由は、すべての n ポイントの距離行列を計算するのを避けるためです (n^2 時間または何時間もかかります)。代わりに、クラスター間の距離を計算したいだけです。

pycluster k-means アルゴリズムを試してみましたが、遅すぎることにすぐに気付きました。次の貪欲なアプローチも試しました。

  1. 空間を各次元で 20 個にスライスします。(したがって、合計 20^5 個のピース​​があります)。重心に従って、これらのグリッドボックスにクラスターを格納します。

  2. 各ポイントについて、r (境界球の最大半径) 内にあるグリッドボックスを取得します。十分に近いクラスターがある場合は、そのクラスターに追加し、そうでない場合は新しいクラスターを作成します。

ただし、これにより、必要以上のクラスターが得られるようです。これに似たアプローチも2回実装しましたが、それらは非常に異なる答えを出します。

n^2 時間よりも高速にクラスタリングするための標準的なアプローチはありますか? 確率的アルゴリズムは問題ありません。

4

6 に答える 6

14

おおよその最近傍(ANN) アルゴリズムまたは局所性依存ハッシュ(LSH)を検討してください。クラスタリングの問題を直接解決するわけではありませんが、どのポイントが互いに「近い」かを知ることができます。パラメータを変更することで、close を好きなだけ近づけるように定義できます。そしてそれは速いです。

より正確には、LSH はハッシュ関数 を提供することができ、h2 点xおよびyと距離メトリックdに対して、

d(x,y) <= R1  =>  P(h(x) = h(y)) >= P1
d(x,y) >= R2  =>  P(h(x) = h(y)) <= P2

どこR1 < R2P1 > P2。そうです、それは確率的です。取得したデータを後処理して、真のクラスターに到達できます。

ここでは、 E2LSH マニュアルを含むLSHに関する情報を示します。ANN は精神的に似ています。David Mount がここに情報を持っているか、 FLANNを試してください (Matlab と Python のバインディングがあります)。

于 2010-12-10T03:55:30.083 に答える
6

K-treeと呼ばれる私の研究プロジェクトを試してみてください。これは、k-means に関して大きな入力で適切にスケーリングし、クラスターの階層を形成します。トレードオフは、より高い歪みを持つクラスターを生成することです。O(n log n) の平均的なケースの実行時間と、奇妙なトポロジがある場合にのみ発生する O(n**2) の最悪のケースがあります。複雑性分析の詳細は、私の修士論文にあります。非常に高次元のテキストデータで使用しましたが、問題はありませんでした。

すべてのデータが一方の側 (クラスター) に移動するツリーで、不適切な分割が発生することがあります。SVN のトランクは、現在のリリースとは異なる方法でこれを処理します。分割に問題がある場合は、データをランダムに分割します。前の方法では、不適切な分割がある場合、ツリーが深くなりすぎる可能性があります。

于 2011-01-12T06:04:17.247 に答える
5

R* ツリー (Wikipedia)などのインデックスにデータを配置すると、多くの密度ベースのクラスタリング アルゴリズム ( DBSCAN (Wikipedia)OPTICS (Wikipedia)など) を で実行できますO(n log n)

密度ベースのクラスタリング (ウィキペディア)はまさにあなたが望むものと思われます (「あまり離れていない」)

于 2011-11-25T22:25:29.800 に答える
3

以下は、 scipy.spatial.cKDTree がデータ上でどれだけ高速であるかを確認し、近くのポイント間の距離がどのように分散するかを大まかに把握するための小さなテストベンチ です。

さまざまなKに対してK-clusterを実行する良い方法は、最も近いペアのMSTを構築し、K-1を最長で削除することです。Wayne、GreedyAlgorithmsを参照してください 。

クラスターの視覚化は楽しいでしょう-PCAで2Dに投影しますか?

(ちょうど好奇心が強い、あなたのK 10、100、1000ですか?)

12月17日追加:実際のランタイム:100000 x 5 10秒、500000 x560秒

#!/usr/bin/env python
# time scipy.spatial.cKDTree build, query

from __future__ import division
import random
import sys
import time
import numpy as np
from scipy.spatial import cKDTree as KDTree
    # http://docs.scipy.org/doc/scipy/reference/spatial.html
    # $scipy/spatial/kdtree.py is slow but clean, 0.9 has cython
__date__ = "2010-12-17 dec denis"

def clumpiness( X, nbin=10 ):
    """ how clumpy is X ? histogramdd av, max """
        # effect on kdtree time ? not much
    N, dim = X.shape
    histo = np.histogramdd( X, nbin )[0] .astype(int)  # 10^dim
    n0 = histo.size - histo.astype(bool).sum()  # uniform: 1/e^lambda
    print "clumpiness: %d of %d^%d data bins are empty  av %.2g  max %d" % (
        n0, nbin, dim, histo.mean(), histo.max())

#...............................................................................
N = 100000
nask = 0  # 0: ask all N
dim = 5
rnormal = .9
    # KDtree params --
nnear = 2  # k=nnear+1, self
leafsize = 10
eps = 1  # approximate nearest, dist <= (1 + eps) * true nearest
seed = 1

exec "\n".join( sys.argv[1:] )  # run this.py N= ...
np.random.seed(seed)
np.set_printoptions( 2, threshold=200, suppress=True )  # .2f
nask = nask or N
print "\nkdtree:  dim=%d  N=%d  nask=%d  nnear=%d  rnormal=%.2g  leafsize=%d  eps=%.2g" % (
    dim, N, nask, nnear, rnormal, leafsize, eps)

if rnormal > 0:  # normal point cloud, .9 => many near 1 1 1 axis
    cov = rnormal * np.ones((dim,dim)) + (1 - rnormal) * np.eye(dim)
    data = np.abs( np.random.multivariate_normal( np.zeros(dim), cov, N )) % 1
        # % 1: wrap to unit cube
else:
    data = np.random.uniform( size=(N,dim) )
clumpiness(data)
ask = data if nask == N  else random.sample( data, sample )
t = time.time()

#...............................................................................
datatree = KDTree( data, leafsize=leafsize )  # build the tree
print "%.1f sec to build KDtree of %d points" % (time.time() - t, N)

t = time.time()
distances, ix = datatree.query( ask, k=nnear+1, eps=eps )
print "%.1f sec to query %d points" % (time.time() - t, nask)

distances = distances[:,1:]  # [:,0] is all 0, point to itself
avdist = distances.mean( axis=0 )
maxdist = distances.max( axis=0 )
print "distances to %d nearest: av" % nnear, avdist, "max", maxdist

# kdtree:  dim=5  N=100000  nask=100000  nnear=2  rnormal=0.9  leafsize=10  eps=1
# clumpiness: 42847 of 10^5 data bins are empty  av 1  max 21
# 0.4 sec to build KDtree of 100000 points
# 10.1 sec to query 100000 points
# distances to 2 nearest: av [ 0.07  0.08] max [ 0.15  0.18]

# kdtree:  dim=5  N=500000  nask=500000  nnear=2  rnormal=0.9  leafsize=10  eps=1
# clumpiness: 2562 of 10^5 data bins are empty  av 5  max 80
# 2.5 sec to build KDtree of 500000 points
# 60.1 sec to query 500000 points
# distances to 2 nearest: av [ 0.05  0.06] max [ 0.13  0.13]
# run: 17 Dec 2010 15:23  mac 10.4.11 ppc 
于 2010-12-14T15:01:30.047 に答える
3

人々は k-means が遅いという印象を持っていますが、実際には EM アルゴリズム (Lloyd's) だけの問題です。k-means の確率的勾配法は、EM より桁違いに高速です (www.eecs.tufts.edu/~dsculley/papers/fastkmeans.pdf を参照)。

実装はこちら: http://code.google.com/p/sofia-ml/wiki/SofiaKMeans

于 2012-07-14T13:49:49.177 に答える
2

Algorithm::ClusterPointsを正確に実行する Perl モジュールがあります。

まず、投稿で説明したアルゴリズムを使用して多次元セクターのポイントを分割し、次にブルートフォースを使用して隣接するセクターのポイント間のクラスターを見つけます。

非常に劣化した場合、複雑さは O(N) から O(N**2) まで変化します。

更新:

@Denis:いいえ、もっと悪いです:

次元の場合d、セクター (または小さな超立方体) のサイズsは、その対角線が異なるクラスター内の 2 点間で許容されるl最小距離になるように決定されます。c

l = c
l = sqrt(d * s * s)
s = sqrt(c * c / d) = c / sqrt(d)

r = 2c + l次に、ピボット セクターを中心とする直径を持つ超球に接するすべてのセクターを考慮する必要があります。

ceil(r/s)大まかに言えば、あらゆる方向のセクターの行を考慮する必要があり、それはn = pow(2 * ceil(r/s) + 1, d).

たとえばd=5、、、およびc=1_l=2.236s=0.447r=3.236n=pow(9, 5)=59049

実際には、ここではサイズの超立方体に接触するものを考慮しているため、チェックする必要がある隣接セクターは少なくなり(2r+1)/s、外接超球に接触するもののみをチェックする必要があります。

「同じクラスター上にある」という関係の全単射の性質を考慮すると、チェックする必要があるセクターの数を半分にすることもできます。

具体的には、Algorithm::ClusterPoints でd=53903 セクターをチェックします。

于 2010-12-10T12:13:16.983 に答える