にいくつかのポイントがあり、ポイントをクラスター化して次のようにします。
各クラスターには、等しい数のの要素が含まれます。(クラスターの数が分割すると仮定します。)
各クラスターは、平均のクラスターのように、ある意味で「空間的に凝集」しています。
これらのいずれかを満たす多くのクラスタリング手順を考えるのは簡単ですが、誰もが両方を一度に取得する方法を知っていますか?
にいくつかのポイントがあり、ポイントをクラスター化して次のようにします。
各クラスターには、等しい数のの要素が含まれます。(クラスターの数が分割すると仮定します。)
各クラスターは、平均のクラスターのように、ある意味で「空間的に凝集」しています。
これらのいずれかを満たす多くのクラスタリング手順を考えるのは簡単ですが、誰もが両方を一度に取得する方法を知っていますか?
回答:
2段階のアプローチをお勧めします。
クラスタの中心の適切な初期推定を取得します。たとえば、ハードまたはファジーK平均を使用します。
Global Nearest Neighbor割り当てを使用してポイントをクラスター中心に関連付けます:各ポイントと各クラスター中心間の距離行列を計算し(合理的な距離を計算するだけで問題を少し小さくすることができます)、各クラスター中心をX回複製し、線形を解きます課題問題。各クラスターセンターについて、データポイントと完全にXが一致するため、グローバルにデータポイントとクラスターセンター間の距離が最小化されます。
手順2の後にクラスター中心を更新し、手順2を繰り返して基本的にクラスターごとに固定数のポイントでK-meansを実行できることに注意してください。それでも、最初に適切な初期推測を取得することをお勧めします。
このk-meansバリエーションを試してください。
初期化:
k
データセットからセンターをランダムに選択するか、kmeans ++戦略を使用してさらに良い最終的に、クラスターごとに+ -1個の同じオブジェクト数の要件を満たすパーティションを作成する必要があります(最後のいくつかのクラスターにも正しい数があることを確認してm
ください。最初のクラスターにはceil
オブジェクトがあり、残りは正確にfloor
オブジェクトです)
反復ステップ:
必要条件:「スワップ提案」(異なるクラスターにあることを好むオブジェクト)を持つ各クラスターのリスト。
Eステップ:通常のk-meansのように、更新されたクラスター中心を計算します
Mステップ:すべてのポイントを反復処理する(1つだけ、または1つのバッチですべて)
オブジェクトに最も近いクラスター中心/現在のクラスターより近いすべてのクラスター中心を計算します。別のクラスターの場合:
クラスターサイズは不変(+-天井/床の差)のままであり、オブジェクトは、推定値が改善される限り、あるクラスターから別のクラスターにのみ移動します。したがって、k-meansのようなある点で収束するはずです。ただし、少し遅い(つまり、繰り返しが多い)場合があります。
これが以前に公開または実装されたかどうかはわかりません。それは私が試してみただけです(k-meansを試してみると、はるかに優れたクラスタリングアルゴリズムがあります)。
開始するのに適した場所は、3つの異なる初期化(k-means ++を含む)を既にサポートしているように見えるELKIの k-means実装です。著者は、さまざまな一般的なモジュラー形式のバリアント(たとえば、ロイド、マックイーンなど)。
これは最適化の問題です。この問題を解決するオープンソースのJavaライブラリがあります(クラスタごとの数量が設定範囲内にある必要があるクラスタリング)。ただし、ポイントの合計数は最大で数千である必要があります-5000以下、または10000以下。
ライブラリは次のとおりです。
https://github.com/PGWelch/territorium/tree/master/territorium.core
ライブラリ自体は、地理的/ GISタイプの問題用に設定されているため、XとY、緯度と経度、顧客、距離と時間などへの参照が表示されます。ただし、「地理」要素は無視してもかまいません。クラスター。
それぞれが最小および最大の目標数量を持つ、最初は空の入力クラスターのセットを提供します。クラスタリングは、ヒューリスティックベースの最適化アルゴリズム(スワップ、移動など)を使用して、入力クラスターにポイントを割り当てます。最適化では、最初に各クラスターを最小および最大数量範囲内に維持することを優先し、次にクラスター内のすべてのポイントとクラスターの中心点間の距離を最小化するため、クラスターは空間的に凝集性があります。
このインターフェイスを使用して、ソルバーにポイント間のメトリック関数(距離関数)を与えます。
メトリックは、実際には距離と「時間」の両方を返すように構成されています。これは、旅行ベースの地理的問題用に設計されているためですが、任意のクラスタリング問題では、「時間」をゼロに設定し、距離を実際のメトリックに設定するだけですポイント。
このクラスで問題を設定します:
ポイントは「顧客」であり、その数量は1です。顧客クラスでは、TravelMatrixによって返される「距離」フィールドにメトリック距離を返すと仮定して、costPerUnitTime = 0およびcostPerUnitDistance = 1を設定します。
ソルバーの実行例については、こちらをご覧ください:
最近の論文「正則化された情報の最大化による差別的クラスタリング(およびその中の参考文献)」をお勧めします。具体的には、セクション2ではクラスバランスとクラスターの仮定について説明します。
最近、あまり大きくないデータセットにこれを自分で必要としました。私の答えは、実行時間が比較的長いにもかかわらず、ローカル最適に収束することが保証されています。
def eqsc(X, K=None, G=None):
"equal-size clustering based on data exchanges between pairs of clusters"
from scipy.spatial.distance import pdist, squareform
from matplotlib import pyplot as plt
from matplotlib import animation as ani
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
def error(K, m, D):
"""return average distances between data in one cluster, averaged over all clusters"""
E = 0
for k in range(K):
i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
E += numpy.mean(D[numpy.meshgrid(i,i)])
return E / K
numpy.random.seed(0) # repeatability
N, n = X.shape
if G is None and K is not None:
G = N // K # group size
elif K is None and G is not None:
K = N // G # number of clusters
else:
raise Exception('must specify either K or G')
D = squareform(pdist(X)) # distance matrix
m = numpy.random.permutation(N) % K # initial membership
E = error(K, m, D)
# visualization
#FFMpegWriter = ani.writers['ffmpeg']
#writer = FFMpegWriter(fps=15)
#fig = plt.figure()
#with writer.saving(fig, "ec.mp4", 100):
t = 1
while True:
E_p = E
for a in range(N): # systematically
for b in range(a):
m[a], m[b] = m[b], m[a] # exchange membership
E_t = error(K, m, D)
if E_t < E:
E = E_t
print("{}: {}<->{} E={}".format(t, a, b, E))
#plt.clf()
#for i in range(N):
#plt.text(X[i,0], X[i,1], m[i])
#writer.grab_frame()
else:
m[a], m[b] = m[b], m[a] # put them back
if E_p == E:
break
t += 1
fig, ax = plt.subplots()
patches = []
for k in range(K):
i = numpy.where(m == k)[0] # indeces of datapoints belonging to class k
x = X[i]
patches.append(Polygon(x[:,:2], True)) # how to draw this clock-wise?
u = numpy.mean(x, 0)
plt.text(u[0], u[1], k)
p = PatchCollection(patches, alpha=0.5)
ax.add_collection(p)
plt.show()
if __name__ == "__main__":
N, n = 100, 2
X = numpy.random.rand(N, n)
eqsc(X, G=3)