2010-03-16 56 views
24

我正在寻找一种方法来分别在矩阵行和列上执行聚类,重新排列矩阵中的数据以反映聚类并将它们放在一起。聚类问题很容易解决,树状图创建也很容易解决(例如在this blog"Programming collective intelligence"中)。但是,如何重新排序数据仍然不清楚。最终,我正在寻找一种使用朴素Python(使用任何“标准”库(如numpy,matplotlib等),但没有using R或其他外部工具)创建类似于下图的图表。重新排序矩阵元素,以反映列和行聚类naiive python

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

澄清

有人问我,我的意思的重新排序。当您首先按照矩阵行对矩阵中的数据进行聚类时,那么通过其列可以通过两个树形图中的位置来识别每个矩阵单元。如果您对原始矩阵的行和列进行重新排序,使得树状图中彼此靠近的元素在矩阵中彼此靠近,然后生成热图,则数据的聚类对于观察者可能变得明显(如上图所示)

+0

你说的重新排序是什么意思?用另一个n交换n个相邻行/列? – 2010-03-16 15:45:21

+0

你想在处理矩阵时使用numpy/scipy。 Matplotlib也很好地模拟了Matlab。这是一个交易:如果你可以在Matlab中做到这一点,你也可以在scipy中做到这一点(如果有的话,简单的语法差异)。 – 2010-03-16 15:50:22

+1

哦,+1的漂亮图片;-) – 2010-03-21 16:58:27

回答

36

查看我的recent answer,部分复制到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

哇,很好的解决方案,你让matplotlib看起来很简单,我认为这是一个很棒的技术,但是你怎样才能把标签添加到x和y轴上呢?你需要使用twinx和twiny,还是有一个更直接的方法 – conradlee 2011-09-28 16:04:38

+1

Thank you。我喜欢matplotlib,我使用它很多。iPython可以帮助你进一步探索matplotlib和pylab。为距离矩阵的轴添加标签(图中心),你可以使用'set_xticks'和'set_xticklabels'。参见http:// ma tplotlib.sourceforge.net/api/axes_api.html?highlight=set_xticklabels#matplotlib.axes.Axes.set_xticklabels – 2011-09-28 18:58:21

5

我不确定是否完全理解,但看起来您正试图根据树状图标记的种类重新对数组中的每个轴进行索引。我想这是假定每个分支划分都有一些比较逻辑。如果是这样的话,那么将这项工作(?):

>>> 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_idxsy_idxs是树状indicies。 a是未排序的矩阵。 xiyi是您的新行/列阵列标记。 a2是排序矩阵,而x_idxs2y_idxs2是新的排序树状图标记。这假设当树形图被创建时,分支列/行总是比1分支更大/更小。

如果你的y_idxs和x_idxs不是列表,而是numpy数组,那么你可以用类似的方式使用np.argsort

+0

“zip(* sorted ...”)做什么? – 2010-03-24 07:29:25

+0

每当我看到'zip(*',我认为是“转置”。 请参阅这里了解使用'*'进行拆包:http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists – Paul 2010-03-25 02:30:48

+0

和一些更多的讨论在这里:http://stackoverflow.com/questions/19339/a-transpose-unzip-function-in -python – Paul 2010-03-25 02:39:48