2009-04-15 6 views
3

Javaで凝集クラスタリングアルゴリズムを作成していますが、削除操作に問題があります。クラスタの数が最初の数の半分に達すると、常に失敗するようです。HashSetから反復処理しても失敗します。

以下のサンプルコードでは、clustersCollection<Collection<Integer>>です。ループを通るいくつか実行した後

 while(clusters.size() > K){ 
      // determine smallest distance between clusters 
      Collection<Integer> minclust1 = null; 
      Collection<Integer> minclust2 = null; 
      double mindist = Double.POSITIVE_INFINITY; 

      for(Collection<Integer> cluster1 : clusters){ 
       for(Collection<Integer> cluster2 : clusters){ 
        if(cluster1 != cluster2 && getDistance(cluster1, cluster2) < mindist){ 
          minclust1 = cluster1; 
          minclust2 = cluster2; 
          mindist = getDistance(cluster1, cluster2); 
        } 
       } 
      } 

      // merge the two clusters 
      minclust1.addAll(minclust2); 
      clusters.remove(minclust2); 
     } 

clusters.remove(minclust2)は、最終的にはfalseを返しますが、私は理由を理解していません。

最初に10個のクラスターを作成し、それぞれのクラスターを1から10の整数で作成しました。距離は0から1の間の乱数です。ここにはprintlnステートメントをいくつか追加した後の出力があります。多数のクラスタの後に、実際のクラスタ、マージ操作、およびclusters.remove(minclust2)の結果を出力します。

Clustering: 10 clusters 
[[3], [1], [10], [5], [9], [7], [2], [4], [6], [8]] 
[5] <- [6] 
true 
Clustering: 9 clusters 
[[3], [1], [10], [5, 6], [9], [7], [2], [4], [8]] 
[7] <- [8] 
true 
Clustering: 8 clusters 
[[3], [1], [10], [5, 6], [9], [7, 8], [2], [4]] 
[10] <- [9] 
true 
Clustering: 7 clusters 
[[3], [1], [10, 9], [5, 6], [7, 8], [2], [4]] 
[5, 6] <- [4] 
true 
Clustering: 6 clusters 
[[3], [1], [10, 9], [5, 6, 4], [7, 8], [2]] 
[3] <- [2] 
true 
Clustering: 5 clusters 
[[3, 2], [1], [10, 9], [5, 6, 4], [7, 8]] 
[10, 9] <- [5, 6, 4] 
false 
Clustering: 5 clusters 
[[3, 2], [1], [10, 9, 5, 6, 4], [5, 6, 4], [7, 8]] 
[10, 9, 5, 6, 4] <- [5, 6, 4] 
false 
Clustering: 5 clusters 
[[3, 2], [1], [10, 9, 5, 6, 4, 5, 6, 4], [5, 6, 4], [7, 8]] 
[10, 9, 5, 6, 4, 5, 6, 4] <- [5, 6, 4] 
false 

[10、9、5、6、4、5、6、4、...]セットがそこから無限に成長します。

編集:明確にする、私は(クラスタ内の各クラスタについてHashSet<HashSet<Integer>>)をを使用してい

+0

[10,9,5,6,4,5,6,4、...]は明らかに1組ではありません。それはリストですか? –

+0

ええ、良い点。 HashSetは重複したオブジェクトを含むことはできません。ここには何か変だ。 –

答えて

5

ああ。すでにSet(またはMapキー)にある値を変更すると、必ずしも正しい位置にあるとは限らず、ハッシュコードがキャッシュされます。それを削除して変更し、再度挿入する必要があります。

+1

はい、あなたはそれを持っています!解決策は、新しいクラスタを作成し、minclust1とminclust2のすべての要素を追加し、minclust1とminclust2をクラスタから削除し、新しいクラスタを追加することです。 HashSetのオブジェクトを変更するのは悪い考えです。 – weiyin

+1

優れています。不変性は揺るがす。技術的には、equalsとhashCodeを動かさない限り、要素をHashSetに変更することができますが、それらはデータの全部または一部に依存する必要があります。 HashSet を持っていれば、恐れなくコンポーネントを変更できます。 –

0

clusters.removeはおそらく削除する要素を見つけるために、equalsを使用していることがある明らかな問題は、残念ながらequals。コレクションでは、同じコレクションであるかどうかではなく、要素が同じであるかどうかを比較します(この点についてはC#がより良い選択となると思います)。をCollections.newSetFromMap(new IdentityHashMap<Collection<Integer>, Boolean>())思う)。

+0

equalsについての良い点はありますが、equalsを使用していたとしても、削除が失敗するのはなぜですか? – weiyin

1

示されたテストでは、複数のIntegerを含むコレクションを初めて削除しようとすると、removeが失敗します。これはいつものケースですか?

具体的なコレクションの種類は何ですか?

+0

はい、あなたは正しい方向にあります。複数の整数を持つコレクションを最初に削除しようとすると、常に失敗します。クラスタ内の各クラスタにHashSet を使用します(HashSet >)。 – weiyin

+0

それは奇妙です。 HashSetを使用している場合、なぜセット内に複数の値が入っていますか? –

+0

上記のように、HashSetは重複したオブジェクトを含むことができません。私はここに深い問題があると思う。 –