web-dev-qa-db-fra.com

Comment donner à sns.clustermap une matrice de distance précalculée?

Habituellement, quand je fais des dendrogrammes et des heatmaps, j'utilise une matrice de distance et je fais un tas de choses SciPy. Je veux essayer Seaborn mais Seaborn veut mes données sous forme rectangulaire (lignes = échantillons, cols = attributs, pas une matrice de distance)?

Je veux essentiellement utiliser seaborn comme backend pour calculer mon dendrogramme et le coller sur ma carte thermique. Est-ce possible? Sinon, cela peut-il être une fonctionnalité à l'avenir.

Peut-être qu'il y a des paramètres que je peux ajuster pour qu'il puisse prendre une matrice de distance au lieu d'une matrice rectangulaire?

Voici l'utilisation:

seaborn.clustermap¶
seaborn.clustermap(data, pivot_kws=None, method='average', metric='euclidean',
 z_score=None, standard_scale=None, figsize=None, cbar_kws=None, row_cluster=True,
 col_cluster=True, row_linkage=None, col_linkage=None, row_colors=None,
 col_colors=None, mask=None, **kwargs)

Mon code ci-dessous:

from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
DF = pd.DataFrame(X, index = ["iris_%d" % (i) for i in range(X.shape[0])], columns = iris.feature_names)

enter image description here

Je ne pense pas que ma méthode soit correcte ci-dessous car je lui donne une matrice de distance précalculée et PAS une matrice de données rectangulaire comme elle le demande. Il n'y a aucun exemple d'utilisation d'une matrice de corrélation/distance avec clustermap mais il y en a pour https://stanford.edu/~mwaskom/software/seaborn/examples/network_correlations.html mais la commande n'est pas groupée avec la plaine sns.heatmap func.

DF_corr = DF.T.corr()
DF_dism = 1 - DF_corr
sns.clustermap(DF_dism)

enter image description here

22
O.rka

Vous pouvez passer la matrice de distance précalculée en tant que lien vers clustermap():

import pandas as pd, seaborn as sns
import scipy.spatial as sp, scipy.cluster.hierarchy as hc
from sklearn.datasets import load_iris
sns.set(font="monospace")

iris = load_iris()
X, y = iris.data, iris.target
DF = pd.DataFrame(X, index = ["iris_%d" % (i) for i in range(X.shape[0])], columns = iris.feature_names)

DF_corr = DF.T.corr()
DF_dism = 1 - DF_corr   # distance matrix
linkage = hc.linkage(sp.distance.squareform(DF_dism), method='average')
sns.clustermap(DF_dism, row_linkage=linkage, col_linkage=linkage)

Pour clustermap(distance_matrix) (c'est-à-dire sans lien passé), le lien est calculé en interne sur la base des distances par paires des lignes et des colonnes dans la matrice de distance (voir la note ci-dessous pour plus de détails) au lieu d'utiliser les éléments de la distance matrice directement (la bonne solution). Par conséquent, la sortie est quelque peu différente de celle de la question: clustermap

Remarque: si aucun row_linkage N'est transmis à clustermap(), le lien entre les lignes est déterminé en interne en considérant chaque ligne comme un "point" (observation) et en calculant les distances par paire entre les points. Le dendrogramme des lignes reflète donc la similitude des lignes. Analogue à col_linkage, Où chaque colonne est considérée comme un point. Cette explication devrait probablement être ajoutée à docs . Voici le premier exemple de la documentation modifié pour rendre le calcul de liaison interne explicite:

import seaborn as sns; sns.set()
import scipy.spatial as sp, scipy.cluster.hierarchy as hc
flights = sns.load_dataset("flights")
flights = flights.pivot("month", "year", "passengers")
row_linkage, col_linkage = (hc.linkage(sp.distance.pdist(x), method='average')
  for x in (flights.values, flights.values.T))
g = sns.clustermap(flights, row_linkage=row_linkage, col_linkage=col_linkage) 
  # note: this produces the same plot as "sns.clustermap(flights)", where
  #  clustermap() calculates the row and column linkages internally
24
Ulrich Stern