comment tracer et annoter les dendrogrammes de regroupement hiérarchique dans scipy / matplotlib

j'utilise dendrogram de scipy pour tracer le groupement hiérarchique en utilisant matplotlib comme suit:

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)

mes questions sont les suivantes: Premièrement, pourquoi mat et 1-mat donnent des regroupements identiques ici? et deuxièmement, Comment puis-je annoter la distance le long de chaque branche de l'arbre en utilisant dendrogram pour que les distances entre les paires de noeuds puissent être comparées?

enfin il semble que le drapeau show_leaf_counts est ignoré, est-il un moyen de l'allumer, de sorte que le nombre d'objets dans chaque catégorie est indiqué? grâce. enter image description here

38
demandé sur tjanez 2012-08-12 01:24:11

2 réponses

l'entrée à linkage() est soit un tableau n x m, représentant n points dans m-dimensions de l'espace, ou un tableau à une dimension contenant les condensé matrice de distance . Dans votre exemple, mat est de 3 x 3, donc vous regroupez 3-d points. Le regroupement est basé sur la distance entre ces points.

pourquoi le tapis et le 1-mat donnent des regroupements identiques ici?

les tableaux mat et 1-mat produisent le même clustering parce que le clustering est basée sur les distances entre les points, et ni une réflexion ( -mat ) pas plus qu'une traduction ( mat + offset ) de l'ensemble des données ne change le relatif les distances entre les points.

Comment puis-je annoter la distance le long de chaque branche de l'arbre à l'aide de dendrogramme afin que les distances entre les paires de noeuds puissent être comparées?

dans le code ci-dessous, I montrer comment vous pouvez utiliser les données retournées par dendrogramme pour étiqueter l'horizontale segments du diagramme avec la distance correspondante. Les valeurs associées avec les touches icoord et dcoord donner les coordonnées x et y de chaque trois segments inversés-U de la figure. Dans augmented_dendrogram cette donnée est utilisé pour ajouter une étiquette de la distance (c.-à-d. la valeur y) de chaque horizontale segment de ligne à dendrogramme.

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

pour votre tableau mat , le dendrogramme augmenté est

dendrogram for three points

ainsi, les points " a " et " c "sont à 1,01 unité d'écart et le point" b " est à 1,57 unité d'écart. le cluster ['a','c'].

Il semble que show_leaf_counts est ignoré, il est un moyen pour l'activer de sorte que le nombre d'objets dans chaque catégorie est indiqué?

le drapeau show_leaf_counts s'applique seulement lorsque toutes les données originales les points sont représentés sous forme de feuilles. Par exemple, lorsque trunc_mode = "lastp" , seuls les derniers noeuds p sont affichés.

voici un exemple avec 100 points:

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()

ce sont les points dans l'ensemble de données:

scatter plot of 100 points

avec p=6 et trunc_mode="lastp" , dendrogram montre seulement le " haut" du dendrogramme. Ce qui suit montre l'effet de show_leaf_counts .

Show effect of show_leaf_counts

65
répondu Warren Weckesser 2017-05-23 12:25:42

je pense qu'il y a quelques malentendus quant à l'utilisation de la fonction que vous essayez d'utiliser. Voici un extrait de code entièrement fonctionnel pour illustrer mes points:

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()

tout d'abord, le calcul m -> m - 1 n'a pas vraiment changé votre résultat puisque la matrice de distance, qui décrit essentiellement les distances relatives entre toutes les paires uniques, n'a pas changé dans votre cas spécifique. (Dans mon exemple de code ci-dessus, toutes les distances sont euclidiennes donc toutes sont positifs et cohérents à partir de points sur un plan 2d.)

pour votre deuxième question, vous avez probablement besoin de déployer votre propre routine d'annotation pour faire ce que vous voulez, car je ne pense pas que le dendromgramme le supporte nativement...

pour la dernière question, show_leaf_counts ne semble fonctionner que lorsque vous essayez d'Afficher des noeuds de feuilles non-singleton avec l'option truncate_mode='lastp'. En gros une les feuilles sont repliées de tellement proches qu'ils ne sont pas faciles à voir. Donc, vous avez une option d'affichage d'une feuille, mais ont une option de montrer (entre parenthèses) combien sont bottes dans cette feuille.

Espérons que cette aide.

14
répondu Taro Sato 2012-09-07 04:13:46