【问题标题】:Permute rows and columns of a matrix置换矩阵的行和列
【发布时间】:2016-03-30 00:45:08
【问题描述】:

假设我有以下矩阵/数组:

array([[0, 0, 1, 1, 1],
       [0, 0, 1, 0, 1],
       [1, 1, 0, 1, 1],
       [1, 0, 1, 0, 0],
       [1, 1, 1, 0, 0]])

我想应用以下排列:

1 -> 5
2 -> 4

结果应该是最后的:

array([[1, 1, 1, 0, 0],
       [1, 0, 1, 0, 0],
       [1, 1, 0, 1, 1],
       [0, 0, 1, 0, 1],
       [0, 0, 1, 1, 1]])

现在,一种非常幼稚(而且耗费大量内存)的方法可能是:

a2 = deepcopy(a1)
a2[0,:] = a1[4,:]
a2[4,:] = a1[0,:]
a = deepcopy(a2)
a2[:,0] = a[:,4]
a2[:,4] = a[:,0]

a3 = deepcopy(a2)
a2[1,:] = a3[3,:]
a2[3,:] = a3[1,:]
a = deepcopy(a2)
a2[:,1] = a[:,3]
a2[:,3] = a[:,1]

但是,我想知道是否有更有效的方法可以做到这一点。 numpy.shuffle 和 numpy.permutation 似乎只置换矩阵的行(而不是同时置换列)。这对我不起作用,因为矩阵是邻接矩阵(表示图),我需要进行排列,这将给我一个与原始图同构的图。此外,我需要进行任意数量的排列(不止一个)。

谢谢!

【问题讨论】:

  • 您发布的示例结果与您的输入相同。请修复。
  • 另外,你没有置换任何东西,只是交换元素。
  • 现在修复它!好吧,我需要做的是根据交换顺序 (1 -> 5, 2 ->4) 来交换那些行和列。如果您将矩阵视为图的邻接矩阵,那么这样做将给出另一个图,该图与第一个图具有同构。
  • 如果你对数组不做任何事情,你将匹配你的预期输出

标签: python-2.7 numpy matrix permutation adjacency-matrix


【解决方案1】:

您可以使用integer array indexing 在单行中执行交换:

a = np.array([[0, 0, 1, 1, 1],
              [0, 0, 1, 0, 1],
              [1, 1, 0, 1, 1],
              [1, 0, 1, 0, 0],
              [1, 1, 1, 0, 0]])
b = a.copy()

# map 0 -> 4 and 1 -> 3 (N.B. Python indexing starts at 0 rather than 1)
a[[4, 3, 0, 1]] = a[[0, 1, 4, 3]]

print(repr(a))
# array([[1, 1, 1, 0, 0],
#        [1, 0, 1, 0, 0],
#        [1, 1, 0, 1, 1],
#        [0, 0, 1, 0, 1],
#        [0, 0, 1, 1, 1]])

请注意,数组索引总是返回一个副本而不是一个视图 - 没有办法在不生成副本的情况下交换数组的任意行/列。


在这种特殊情况下,您可以通过使用切片索引来避免复制,这会返回视图而不是副本:

b = b[::-1] # invert the row order

print(repr(b))
# array([[1, 1, 1, 0, 0],
#        [1, 0, 1, 0, 0],
#        [1, 1, 0, 1, 1],
#        [0, 0, 1, 0, 1],
#        [0, 0, 1, 1, 1]])

更新:

您可以使用相同的索引方法来交换列。

c = np.arange(25).reshape(5, 5)
print(repr(c))
# array([[ 0,  1,  2,  3,  4],
#        [ 5,  6,  7,  8,  9],
#        [10, 11, 12, 13, 14],
#        [15, 16, 17, 18, 19],
#        [20, 21, 22, 23, 24]])

c[[0, 4], :] = c[[4, 0], :]     # swap row 0 with row 4...
c[:, [0, 4]] = c[:, [4, 0]]     # ...and column 0 with column 4

print(repr(c))

# array([[24, 21, 22, 23, 20],
#        [ 9,  6,  7,  8,  5],
#        [14, 11, 12, 13, 10],
#        [19, 16, 17, 18, 15],
#        [ 4,  1,  2,  3,  0]])

在这种情况下,我使用了不同的示例数组 - 您的版本在执行行/列交换后会产生相同的输出,这使得很难理解发生了什么。

【讨论】:

  • 感谢您的回复。但是,您只是更改了行的顺序。我需要的是更改行和列的顺序(第一行与第五行交换,第一列与第五列交换)。我通过我在此处发布的代码实现了这一点 - 目前就在您的帖子下方 - 但在我看来它非常昂贵(每次交换行/列时都进行深度复制)。
  • 查看我的更新。您的问题很难理解,因为您的示例数组在执行行/列交换后会产生相同的结果。
  • 这正是我所需要的。它给出了与我发布的代码相同的结果,但它不需要在每次交换时都对矩阵进行深度复制。谢谢!
  • 请注意,它将复制正在交换的行/列,因为整数数组索引将始终返回副本而不是视图(尽管这是不可避免的)。附带说明一下,您可以使用 a.copy() 而不是 deepcopy 来强制复制数组中的数据。
【解决方案2】:

我找到了一个解决方案来做我想做的事(虽然它很贵):

a2 = deepcopy(a1)
first = randint(0, 5, 10)
second = randint(0, 5, 10)
for i in range(len(first)):
    a = deepcopy(a2)
    a2[first[i],:] = a[second[i],:]
    a2[second[i],:] = a[first[i],:]
for i in range(len(first)):
    a = deepcopy(a2)
    a2[:,first[i]] = a[:,second[i]]
    a2[:,second[i]] = a[:,first[i]] 

基本上,我正在做 10 次随机切换。但是,我需要多次复制矩阵。无论如何,a2 现在表示一个与 a1 同构的图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-27
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 2021-04-29
    • 2021-11-09
    • 2016-05-03
    • 1970-01-01
    相关资源
    最近更新 更多