2010-03-16 14 views
24

Estoy buscando una forma de realizar agrupamientos por separado en filas de matriz y en sus columnas, reordenar los datos en la matriz para reflejar el agrupamiento y ponerlo todo junto . El problema del agrupamiento se puede resolver fácilmente, así como la creación del dendograma (por ejemplo, en this blog o en "Programming collective intelligence"). Sin embargo, cómo reordenar los datos sigue sin estar claro para mí.Reordenar elementos de la matriz para reflejar el clúster de columnas y filas en python ingenuo

Finalmente, estoy buscando una forma de crear gráficos similares a los que se muestran a continuación utilizando Python ingenuo (con cualquier biblioteca "estándar" como numpy, matplotlib, etc., pero sin using R u otras herramientas externas).

dendogram http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/r/heatmap/no_scaling.png

Aclaraciones

me preguntaron qué quería decir con reordenamiento. Cuando agrupa los datos en una matriz primero por filas de matriz, luego por sus columnas, cada celda matriz puede identificarse por la posición en los dos dendrogramas. Si reordena las filas y las columnas de la matriz original de modo que los elementos que se cierran entre sí en los dendrogramas se acerquen uno al otro en la matriz y generen un mapa de calor, la agrupación de los datos puede ser evidente para el espectador. (como en la figura anterior)

+0

¿Qué quiere decir reordenando? Intercambiando n filas/columnas vecinas con otra n? –

+0

Desea usar numpy/scipy cuando se trata de matrices con seguridad. Matplotlib también imita a Matlab. Aquí hay un trato: si puedes hacer esto en Matlab, también puedes hacerlo en scipy (diferencia de sintaxis trivial, si la hay). –

+1

Ooh, +1 para la bonita foto ;-) –

Respuesta

36

Ver mi recent answer, copiado en la parte inferior, a this related question.

import scipy 
import pylab 
import scipy.cluster.hierarchy as sch 

# Generate features and distance matrix. 
x = scipy.rand(40) 
D = scipy.zeros([40,40]) 
for i in range(40): 
    for j in range(40): 
     D[i,j] = abs(x[i] - x[j]) 

# Compute and plot dendrogram. 
fig = pylab.figure() 
axdendro = fig.add_axes([0.09,0.1,0.2,0.8]) 
Y = sch.linkage(D, method='centroid') 
Z = sch.dendrogram(Y, orientation='right') 
axdendro.set_xticks([]) 
axdendro.set_yticks([]) 

# Plot distance matrix. 
axmatrix = fig.add_axes([0.3,0.1,0.6,0.8]) 
index = Z['leaves'] 
D = D[index,:] 
D = D[:,index] 
im = axmatrix.matshow(D, aspect='auto', origin='lower') 
axmatrix.set_xticks([]) 
axmatrix.set_yticks([]) 

# Plot colorbar. 
axcolor = fig.add_axes([0.91,0.1,0.02,0.8]) 
pylab.colorbar(im, cax=axcolor) 

# Display and save figure. 
fig.show() 
fig.savefig('dendrogram.png') 

Dendrogram and distance matrix http://up.stevetjoa.com/dendrogram.png

+1

Wow, buena solución. Haces que matplotlib luzca sencillo, lo que creo que es toda una hazaña. Pero, ¿cómo se pueden agregar las etiquetas a los ejes xey? ¿Necesitas usar twinx y twiny, o hay un método más directo. – conradlee

+1

Gracias. Me encanta matplotlib y lo uso mucho. iPython te ayuda a explorar matplotlib y pylab más. Para agregar etiquetas a los ejes de la matriz de distancia (centro de la imagen), puedes usar 'set_xticks' y 'set_xticklabels'. Ver http: // ma tplotlib.sourceforge.net/api/axes_api.html?highlight=set_xticklabels#matplotlib.axes.Axes.set_xticklabels –

5

No estoy seguro de que comprenda completamente, pero parece que está tratando de volver a indexar cada eje de la matriz en función del tipo de indicios de dendrograma. Supongo que eso supone que hay alguna lógica comparativa en cada delineación de ramas. Si este es el caso, entonces sería este trabajo (?):

>>> x_idxs = [(0,1,0,0),(0,1,1,1),(0,1,1),(0,0,1),(1,1,1,1),(0,0,0,0)] 
>>> y_idxs = [(1,1),(0,1),(1,0),(0,0)] 
>>> a = np.random.random((len(x_idxs),len(y_idxs))) 
>>> x_idxs2, xi = zip(*sorted(zip(x_idxs,range(len(x_idxs))))) 
>>> y_idxs2, yi = zip(*sorted(zip(y_idxs,range(len(y_idxs))))) 
>>> a2 = a[xi,:][:,yi] 

x_idxs y y_idxs son los índices del dendrograma. a es la matriz no ordenada. xi y yi son sus nuevas indices de matriz de fila/columna. a2 es la matriz ordenada, mientras que x_idxs2 y y_idxs2 son las nuevas indices de dendrograma ordenadas. Esto supone que cuando se creó el dendograma, una columna/fila de rama 0 siempre es comparativamente más grande/más pequeña que una rama 1.

Si sus y_idxs y x_idxs no son listas, pero son matrices numpy, entonces podría usar np.argsort de manera similar.

+0

qué es exactamente * en "zip (* ordenados ..." do? –

+0

cada vez que veo 'zip (*', creo que "transpone". Vea aquí para el uso de '*' para desempacar : http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists – Paul

+0

y un poco más de discusión aquí: http://stackoverflow.com/questions/19339/a-transpose-unzip-function-in -python – Paul

2

Sé que esto es muy tarde para el juego, pero me hizo un objeto de trazado basado en el código del poste en esta página. Está registrada en el PIP, por lo que la instalación sólo tiene que llamar

pip install pydendroheatmap 

la salida página GitHub del proyecto aquí: https://github.com/themantalope/pydendroheatmap

Cuestiones relacionadas