基于对角线条目对矩阵进行排序

时间:2016-04-03 03:38:00

标签: python sorting python-3.x numpy matrix

首先,我想指出我的问题与此问题不同:Sort a numpy matrix based on its diagonal

问题如下: 假设我有一个numpy矩阵

A=

5 7 8

7 2 9

8 9 3

我想基于对角线对矩阵进行排序,然后根据它重新排列矩阵元素。这就是现在

sorted_A:

2 9 7

9 3 8

7 8 5

请注意:

(1)。对角线已分类

(2)。其他元素(非对角线)由它重新调整。怎么样? 因为diag(A)= [5,2,3]& DIAG(sorted_A)= [2,3,5] 所以行/列索引A = [0,1,2]在sorted_A中变为[1,2,0]。

到目前为止,我使用蛮力来提取对角线元素,得到指数O(N²)然后重新排列矩阵(另一个O(N²))。我想知道是否有任何有效/优雅的方式来做到这一点。我很感激能得到的所有帮助。

2 个答案:

答案 0 :(得分:2)

根据对角线值对行进行排序很简单:

In [192]: A=np.array([[5,7,8],[7,2,9],[8,9,3]])
In [193]: A
Out[193]: 
array([[5, 7, 8],
       [7, 2, 9],
       [8, 9, 3]])
In [194]: np.diag(A)
Out[194]: array([5, 2, 3])
In [195]: idx=np.argsort(np.diag(A))
In [196]: idx
Out[196]: array([1, 2, 0], dtype=int32)
In [197]: A[idx,:]
Out[197]: 
array([[7, 2, 9],
       [8, 9, 3],
       [5, 7, 8]])

将每行中的元素重新排列到原始对角线后面的对角线将进行一些实验 - 试验和错误。我们可能不得不滚动'每行基于与排序idx相关的某些值。我不记得是否有一个函数可以单独滚动每一行,或者我们是否必须迭代这些行才能做到这一点。

In [218]: A1=A[idx,:]
In [219]: [np.roll(a,-i) for a,i in zip(A1,[1,1,1])]
Out[219]: [array([2, 9, 7]), array([9, 3, 8]), array([7, 8, 5])]
In [220]: np.array([np.roll(a,-i) for a,i in zip(A1,[1,1,1])])
Out[220]: 
array([[2, 9, 7],
       [9, 3, 8],
       [7, 8, 5]])

所以滚动[1,1,1]完成工作。但是,我不知道如何得出这一点。我怀疑我们需要生成几个测试用例,可能还有更大的测试用例,并寻找一种模式。

该卷可能与行移动了多少,原始位置和新位置之间的差异有关。试试吧:

np.arange(3)-idx

In [222]: np.array([np.roll(a,i) for a,i in zip(A1,np.arange(3)-idx)])
Out[222]: 
array([[2, 9, 7],
       [9, 3, 8],
       [7, 8, 5]])

将排序idx应用于行和列似乎也可以解决问题:

In [227]: A[idx,:][:,idx]
Out[227]: 
array([[2, 9, 7],
       [9, 3, 8],
       [7, 8, 5]])

In [229]: A[idx[:,None],idx]
Out[229]: 
array([[2, 9, 7],
       [9, 3, 8],
       [7, 8, 5]])

答案 1 :(得分:1)

在这里,我简化了之前已经陈述的简单解决方案,但很难让您满意。

如果您想对表格进行排序(例如,混淆矩阵的对角线大小,并相应地排列行和列,这很有用。

>>> A=np.array([[5,1,4],[7,2,9],[8,0,3]])
>>> A
array([[5, 1, 4],
   [7, 2, 9],
   [8, 0, 3]])
>>> diag = np.diag(A)
>>> diag
array([5, 2, 3])
>>> idx=np.argsort(diag) # get the order of items that are in diagon
>>> A[idx,:][:,idx]  # reorder rows and arrows based on the order of items on diagon
array([[2, 9, 7],
   [0, 3, 8],
   [1, 4, 5]])

如果您想按降序排序,只需添加idx = idx[::-1] # reverse order

即可