如何在scipy / matplotlib中绘制和注释层次聚类树状图
我使用scipy
dendrogram
来绘制使用matplotlib
层次聚类,如下所示:
mat = array([[1, 0.5, 0.9], [0.5, 1, -0.5], [0.9, -0.5, 1]]) plt.subplot(1,2,1) plt.title("mat") dist_mat = mat linkage_matrix = linkage(dist_mat, "single") print "linkage2:" print linkage(1-dist_mat, "single") dendrogram(linkage_matrix, color_threshold=1, labels=["a", "b", "c"], show_leaf_counts=True) plt.subplot(1,2,2) plt.title("1 - mat") dist_mat = 1 - mat linkage_matrix = linkage(dist_mat, "single") dendrogram(linkage_matrix, color_threshold=1, labels=["a", "b", "c"], show_leaf_counts=True)
我的问题是:首先,为什么mat
和1-mat
在这里给出相同的聚类? 其次,我怎样才能使用dendrogram
注释沿着树的每个分支的距离,使得节点对之间的距离可以比较?
最后似乎show_leaf_counts
标志被忽略,有没有办法打开它,以便在每个类中的对象数量显示? 谢谢。
linkage()
的input可以是n维数组,表示m维空间中的n个点,也可以是包含浓缩距离matrix的一维数组。 在你的例子中, mat
是3 x 3,所以你正在聚集三个三维点。 聚类基于这些点之间的距离。
为什么垫子和1垫子在这里给出相同的聚类?
arraysmat
和1-mat
产生相同的聚类,因为聚类是基于点之间的距离的,并且整个数据集的reflection( -mat
)和平移( mat + offset
)都不改变点之间的相对距离。
我怎样才能使用树状图注释沿树的每个分支的距离,以便可以比较节点对之间的距离?
在下面的代码中,我将展示如何使用树状图返回的数据来标注图表的水平线段和相应的距离。 与键icoord
和dcoord
相关联的值给出了该图的每个三段倒U的x和y坐标。 在augmented_dendrogram
这个数据被用来添加树状图中每个水平线段的距离(即y值)的标签。
from scipy.cluster.hierarchy import dendrogram import matplotlib.pyplot as plt def augmented_dendrogram(*args, **kwargs): ddata = dendrogram(*args, **kwargs) if not kwargs.get('no_plot', False): for i, d in zip(ddata['icoord'], ddata['dcoord']): x = 0.5 * sum(i[1:3]) y = d[1] plt.plot(x, y, 'ro') plt.annotate("%.3g" % y, (x, y), xytext=(0, -8), textcoords='offset points', va='top', ha='center') return ddata
对于你的mat
arrays,增强的树状图是
因此,点“a”和“c”相距1.01个单位,点“b”为1.57个单位['a','c']。
看来show_leaf_counts
标志被忽略了,有没有办法打开它,使每个类中的对象数显示?
标志show_leaf_counts
仅适用于并非所有原始数据点都显示为叶子的情况。 例如,当trunc_mode = "lastp"
,只显示最后的p
节点。
这里有一个100分的例子:
import numpy as np from scipy.cluster.hierarchy import linkage import matplotlib.pyplot as plt from augmented_dendrogram import augmented_dendrogram # Generate a random sample of `n` points in 2-d. np.random.seed(12312) n = 100 x = np.random.multivariate_normal([0, 0], np.array([[4.0, 2.5], [2.5, 1.4]]), size=(n,)) plt.figure(1, figsize=(6, 5)) plt.clf() plt.scatter(x[:, 0], x[:, 1]) plt.axis('equal') plt.grid(True) linkage_matrix = linkage(x, "single") plt.figure(2, figsize=(10, 4)) plt.clf() plt.subplot(1, 2, 1) show_leaf_counts = False ddata = augmented_dendrogram(linkage_matrix, color_threshold=1, p=6, truncate_mode='lastp', show_leaf_counts=show_leaf_counts, ) plt.title("show_leaf_counts = %s" % show_leaf_counts) plt.subplot(1, 2, 2) show_leaf_counts = True ddata = augmented_dendrogram(linkage_matrix, color_threshold=1, p=6, truncate_mode='lastp', show_leaf_counts=show_leaf_counts, ) plt.title("show_leaf_counts = %s" % show_leaf_counts) plt.show()
这些是数据集中的要点:
当p=6
和trunc_mode="lastp"
, dendrogram
仅显示dendrogram
的“顶部”。 以下显示了show_leaf_counts
的效果。
我想对使用你正在使用的函数有一些误解。 这是一个完整的工作代码片段来说明我的观点:
import matplotlib.pyplot as plt from scipy.cluster.hierarchy import dendrogram, linkage from numpy import array import numpy as np mat = array([184, 222, 177, 216, 231, 45, 123, 128, 200, 129, 121, 203, 46, 83, 83]) dist_mat = mat linkage_matrix = linkage(dist_mat, 'single') print linkage_matrix plt.figure(101) plt.subplot(1, 2, 1) plt.title("ascending") dendrogram(linkage_matrix, color_threshold=1, truncate_mode='lastp', labels=array(['a', 'b', 'c', 'd', 'e', 'f']), distance_sort='ascending') plt.subplot(1, 2, 2) plt.title("descending") dendrogram(linkage_matrix, color_threshold=1, truncate_mode='lastp', labels=array(['a', 'b', 'c', 'd', 'e', 'f']), distance_sort='descending') def make_fake_data(): amp = 1000. x = [] y = [] for i in range(0, 10): s = 20 x.append(np.random.normal(30, s)) y.append(np.random.normal(30, s)) for i in range(0, 20): s = 2 x.append(np.random.normal(150, s)) y.append(np.random.normal(150, s)) for i in range(0, 10): s = 5 x.append(np.random.normal(-20, s)) y.append(np.random.normal(50, s)) plt.figure(1) plt.title('fake data') plt.scatter(x, y) d = [] for i in range(len(x) - 1): for j in range(i+1, len(x) - 1): d.append(np.sqrt(((x[i]-x[j])**2 + (y[i]-y[j])**2))) return d mat = make_fake_data() plt.figure(102) plt.title("Three Clusters") linkage_matrix = linkage(mat, 'single') print "three clusters" print linkage_matrix dendrogram(linkage_matrix, truncate_mode='lastp', color_threshold=1, show_leaf_counts=True) plt.show()
首先,计算m – > m – 1并没有真正改变你的结果,因为距离matrix基本上描述了所有唯一对之间的相对距离,在你的具体情况下并没有改变。 (在我上面的例子代码中,所有的距离都是欧几里得,所以所有的距离都是正的,并且在二维平面上的点是一致的。)
对于你的第二个问题,你可能需要推出自己的注解例程来做你想做的,因为我不认为dendromgram本身支持它…
对于最后一个问题,show_leaf_counts似乎只有当您尝试显示与truncate_mode ='lastp'选项非单身叶节点时工作。 基本上一片叶子聚集在一起,不容易看到。 所以你可以select显示一个叶子,但是可以select显示(在括号中)有多less个叶子聚集在一起。
希望这可以帮助。