scipy.cluster.hierarchyモジュール関数に関連してfastclusterパッケージを使用して凝集クラスタークラスタリング(AHC) Python 3
にあり、私はcut_tree()機能の困惑している動作を見つけました。Scipyのcut_tree()は、要求された数のクラスタを返さず、scipyとfastclusterで得られたリンケージ行列は一致しません
私は問題なしでデータをクラスタ化し、を使用してmethod=ward
を使用してZ
を取得します。次に、一定の数のクラスター(例えば、33)を得るために樹状図ツリーを切断したいと思って、これを適切にcut_tree(Z, n_clusters=33)
を使用して行います。 (AHCは、ツリーのリーフにあるすべてのデータポイントを結ぶバイナリツリーを生成する決定論的な方法であることを覚えておいてください。このツリーをどのレベルで見ても、最後に必要なクラスタの数を見ることができます。 cut_tree()は、 'n_cluster'整数ラベルのセットを0からn_clusters - 1に戻すことです。
私はこれを他の実験で何度もやっていますが、私はいつも私が要求するクラスタの数。問題は、この1つのデータセットでは、cut_tree()
に33クラスタを依頼すると、私には32だけが与えられます。なぜこれが当てはまるのかわかりません。それはバグでしょうか? cut_tree()
のバグを認識していますか?私はこの動作をデバッグしようとし、scipyのlinkage()機能を使って同じクラスタリング実験を行った。得られたリンケージマトリックスをcut_tree()
に入力すると、予想外の数のクラスタが出力として取得されませんでした。私はまた、2つの方法で出力されたリンケージ行列が等しくないことを確認しました。
私が使用している[dataset]は、それぞれが20次元の10680個のベクトルで構成されています。以下の実験を確認:あなたはデータセットが少なくとも正確なコピーで37個のベクトルが含まれて気づいたかもしれません
import numpy as np
import fastcluster as fc
import scipy.cluster.hierarchy as hac
from scipy.spatial.distance import pdist
### *Load dataset (10680 vectors, each with 20 dimensions)*
X = np.load('dataset.npy')
### *Hierarchical clustering using traditional scipy method*
dists = pdist(X)
Z_1 = hac.linkage(dists, method='ward')
### *Hierarchical clustering using optimized fastcluster method*
Z_2 = fc.linkage_vector(X, method='ward')
### *Comparissons*
## Are the linkage matrices equal?
print("Z_1 == Z_2 ? ", np.allclose(Z_1, Z_2))
## Is scipy's cut_tree() returning the requested number of clusters when using Z_2?
print("Req.\tGot\tequal?")
for i in range(1,50):
cut = hac.cut_tree(Z_2, i)
uniq = len(np.unique(cut))
print(i,"\t",uniq,"\t",i==uniq)
## The same as before, but in condensed form. When requesting cut_tree() for clusters
# in the range [1,50] does it return wrong results at some point?
print("Any problem cutting Z_1 for n_clusters in [1,50]? ", not np.all([len(np.unique(
hac.cut_tree(Z_1, i)))==i for i in range(1,50)]))
print("Any problem cutting Z_2 for n_clusters in [1,50]? ", not np.all([len(np.unique(
hac.cut_tree(Z_2, i)))==i for i in range(1,50)]))
#Output:
#
#Z_1 == Z_2 ? False
#
#Req. Got equal?
#1 1 True
#2 2 True
#3 3 True
#4 4 True
#5 5 True
#6 6 True
#7 7 True
#8 8 True
#9 9 True
#10 10 True
#11 11 True
#12 12 True
#13 13 True
#14 14 True
#15 15 True
#16 16 True
#17 17 True
#18 18 True
#19 19 True
#20 20 True
#21 21 True
#22 22 True
#23 23 True
#24 24 True
#25 25 True
#26 26 True
#27 27 True
#28 28 True
#29 29 True
#30 30 True
#31 31 True
#32 32 True
#33 32 False
#34 33 False
#35 34 False
#36 35 False
#37 36 False
#38 37 False
#39 38 False
#40 39 False
#41 40 False
#42 41 False
#43 42 False
#44 43 False
#45 44 False
#46 45 False
#47 46 False
#48 47 False
#49 48 False
#
#Any problem cutting Z_1 for n_clusters in [1,50]? False
#Any problem cutting Z_2 for n_clusters in [1,50]? True
を、そしてすべてのコピーをカウントすることは、データセット内の少なくともコピーで、合計55個のベクトルがあります。
検査のために、私は2つのリンケージマトリックスの浅い深さレベルまでプロットすることに決めました。画像は下の図のようにZ_1
、下にはZ_2
です。括弧内の数字は、そのブランチの蛇腹を含む集団を示します。かっこのない数字はツリーのリーフです(数値はXマトリックスのベクトルのインデックスです)。 (プロットされたレベルでの)唯一の違いは、赤い四角でマークされた枝にあり、重なり合ったベクトルを含んでいるので0の距離で合体していることが分かります。
だから、私は再び、前のコードに示すように、クラスタリング手順を実行したが、少なくともコピーが55のベクターを含むデータのサブセットのみを使用してこの時間。したがって、fastclusterとscipyのダウンロードは、同じ結果を返すされていません
#Z_1 == Z_2 ? False
#Req. Got equal?
#1 1 True
#2 2 True
#3 2 False
#4 3 False
#5 4 False
#6 5 False
#7 6 False
#8 7 False
#9 8 False
#10 9 False
#11 10 False
#12 11 False
#13 12 False
#14 13 False
#15 14 False
#16 15 False
#17 16 False
#18 17 False
#19 18 False
#20 20 True
#21 21 True
#22 22 True
#23 23 True
#24 24 True
#25 25 True
#26 26 True
#27 27 True
#28 28 True
#29 29 True
#30 30 True
#31 31 True
#32 32 True
#33 33 True
#34 34 True
#35 35 True
#36 36 True
#37 37 True
#38 38 True
#39 39 True
#40 40 True
#41 41 True
#42 42 True
#43 43 True
#44 44 True
#45 45 True
#46 46 True
#47 47 True
#48 48 True
#49 49 True
#Any problem cutting Z_1 for n_clusters in [1,50]? False
#Any problem cutting Z_2 for n_clusters in [1,50]? True
、それが唯一の原因重複の点にある場合、これは可能性:この時間に
uniqs, uniqs_indices, uniqs_count = np.unique(X, axis=0, return_index=True, return_counts=True)
duplicate_rows_indices = list(set(range(len(X))) - set(uniqs_indices))
number_of_duplicate_rows = len(X)-len(uniqs) # 37
all_duplicate_rows = set()
for i in duplicate_rows_indices:
_rows = set(np.where(X == X[i])[0])
for j in _rows:
all_duplicate_rows.add(j)
rows_with_at_least_a_copy = list(all_duplicate_rows)
number_of_rows_with_at_least_a_copy = len(rows_with_at_least_a_copy) # 55
X_subset = X[rows_with_at_least_a_copy]
と私の出力ました:私はX_subset
を得ましたそのクラスタリング状況のあいまいさのために受け入れられるべきである。しかし、問題はcut_tree()
であり、linkage_vector()
によって得られた連結マトリックスが与えられた場合、これらの場合に要求された数のクラスターを返さないことがある。どのようにこれを修正することができますか?使用
ライブラリのバージョン:scipyのダウンロード '0.19.1'、numpyの '1.13.3'、fastcluster '1.1.24'
編集:はまた、ここに掲載されます:https://github.com/scipy/scipy/issues/7977。
ありがとうございます。この「不完全な解決策」をすばやく確認すると、「病棟」の方法では機能しますが、「重心」と「中央値」では機能しません。私はこれが元の質問ではないことを知っていますが、あなたもそれを修正できますか?これらの2つのメソッドでは、重複したベクトルを削除した同じデータセットを使って、この調整の有無にかかわらず 'cut_tree()'の出力をチェックしましたが、それでも正しい数のクラスタは返されません。あなたのポイントに追加すると、 'single 'メソッドで得られたリンケージ行列に' cut_tree() 'を適用することは永遠に完了します。 – PDRX
[GitHub](https://github.com/scipy/scipy/issues/7977)に関する議論を続けましょう。 – Daniel