在Python中转置/旋转矩阵块

8
我是一名能翻译文本的助手,以下是您需要翻译的内容:

我有一个Python中的列表嵌套列表表示的6x6矩阵。该矩阵被分成4个大小为3x3的正方形块。我想找到一种方法只对其中一个块进行转置。我可以使用传统方法遍历每个元素并将其复制到另一个数组中,然后再进行反向操作等等,但我想看看是否有更好的方法(在Python中可以使用zip方法在一行中转置矩阵)。

例如,这是矩阵及其块的表示:

 block 1  block 2
+-------+-------+
| . . . | . . . |
| . . 2 | 1 . . |
| . . . | . . . |
+-------+-------+
| . . . | . . . |
| . . . | . . . |
| . 1 . | . . . |
+-------+-------+
 block 3  block 4

并且使用 rotate(3, right) 应该得到以下结果。
 block 1  block 2
+-------+-------+
| . . . | . . . |
| . . 2 | 1 . . |
| . . . | . . . |
+-------+-------+
| . . . | . . . |
| 1 . . | . . . |
| . . . | . . . |
+-------+-------+
 block 3  block 4

我想找到一种方法,它接收一个块号,并将仅该块向左或向右旋转。是否有简单的方法可以实现?


1
操作是否应该就地进行? - Sven Marnach
是的,它需要就地进行操作,或者至少需要将结果写回原始矩阵。 - randomThought
4个回答

5

在Sven Marnach的思路基础上,使用np.rot90,这里有一个旋转象限顺时针方向(是否符合要求?)的版本。关键步骤如下:

block3[:] = np.rot90(block3.copy(),-1)

copy() 方法用于右侧(RHS)。如果没有使用 copy(),当值被赋给 block3 时,右侧所使用的底层数据也会被更改。这会混淆后续赋值中使用的值。如果没有使用 copy(),多个相同值会分散在 block3 中。

我没有看到不使用拷贝的方法来执行此操作。

import numpy as np
a = np.arange(36).reshape(6, 6)
print(a)
# [[ 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 25 26 27 28 29]
#  [30 31 32 33 34 35]]
block3 = a[3:6, 0:3]

# To rotate counterclockwise
block3[:] = np.rot90(block3.copy())
print(a)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [20 26 32 21 22 23]
#  [19 25 31 27 28 29]
#  [18 24 30 33 34 35]]

# To rotate clockwise
a = np.arange(36).reshape(6, 6)
block3 = a[3:6, 0:3]
block3[:] = np.rot90(block3.copy(),-1)
print(a)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [30 24 18 21 22 23]
#  [31 25 19 27 28 29]
#  [32 26 20 33 34 35]]

4

说实话,使用NumPy非常简单:

>>> a = numpy.arange(36).reshape(6, 6)
>>> a
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, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])
>>> block3 = a[3:6, 0:3]
>>> block3[:] = numpy.rot90(block3, 1).copy()
>>> a
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [20, 26, 32, 21, 22, 23],
       [26, 25, 31, 27, 28, 29],
       [20, 26, 20, 33, 34, 35]])

+1 对于 numpy.rot90。然而,将右侧内容原地复制到 block3[:] 中会产生不良副作用--随着新值被赋给 block3,右侧的基础值也会被覆盖,导致结果中存在多个相同值的副本。 - unutbu
@unutbu:感谢您指出这一点。我甚至没有看结果——我确信numpy.rot90()返回的是一个新数组,而不是视图。 - Sven Marnach

0

将矩阵定义为块的字典和块定义为列表的列表是否是一种解决方案? 在您的示例中(用您用于转置的函数替换transpose()):

Matrix={1:block1,2:block2,3:block3,4:block4}
block3=transpose(block3)
Matrix[3]=block3

并不是因为我需要执行其他矩阵操作,而这种结构无法实现或会使问题过于复杂。 - randomThought

0

这里有一种方法可以从您提供的矩阵中旋转一个“块”:

matrix = [[0,1,2],[3,4,5],[6,7,8]]

def rotate(m, right):
    rm = []
    for i in range(0,len(m)):
        if right:
            rm.append([row[i] for row in reversed(m)])
        else:
            rm.append([row[i] for row in m])
    return rm

right 是一个 Bool 类型
这将返回一个 列表的列表

你也可以使用:

def rotate(m, right):
    if right:
        return list(zip(*reversed(m)))
    else:
        return list(zip(*m))

但是这将返回一个元组列表


编辑:

如果我们谈论的是类型为矩阵的内容:

matrix = [[[1,2,3],[4,5,6],[7,8,9]], # block 1
          [[1,2,3],[4,5,6],[7,8,9]], # block 2
          [[1,2,3],[4,5,6],[7,8,9]], # block 3
          [[1,2,3],[4,5,6],[7,8,9]]  # block 4
         ]

要访问块3,您可以使用matrix[2]

因此,旋转函数将如下使用:
rotate(matrix[2], True) #向右旋转块3


我提供的矩阵是一个数字列表的列表。如果它是数字列表的列表的列表,你可以通过简单地执行 rotate(matrix[2], True/False) 来选择第3个块。 - Serdalis
但是如何仅提取块并将其传递到函数中呢? - randomThought
这只是一个数字列表的列表,而不是三个嵌套列表。 - randomThought
我不明白如果你只有一个数字的列表的列表(我将其定义为单个矩阵),那怎么可能会有“块”。请在你的问题中定义“块”。除非你把一个'块'全部放在一个列表中,而不是分行...否则你需要使用“列表切片”来访问你的块。 - Serdalis
块指的是矩阵的一部分,而不是矩阵的单个元素。在这种情况下,可能需要使用列表切片。 - randomThought
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接