Python中的矩阵转置

161

我想为Python创建一个矩阵转置函数,但似乎无法使其工作。 假设我有一个

theArray = [['a','b','c'],['d','e','f'],['g','h','i']]

我希望我的函数能够产生

newArray = [['a','d','g'],['b','e','h'],['c', 'f', 'i']]

换句话说,如果我要将这个二维数组按列和行打印出来,我希望行变成列,列变成行。

我已经做了这个,但它不起作用。

def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        for tt in range(len(anArray[t])):
            transposed[t] = [None]*len(anArray)
            transposed[t][tt] = anArray[tt][t]
    print transposed
19个回答

347

Python 2:

>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> zip(*theArray)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

Python 3:

>>> [*zip(*theArray)]
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]

16
如果你需要遍历结果,使用itertoolsizip可以节省大数组的内存消耗。 - Antony Hatchkins
1
你如何让它返回子列表的列表,例如[['a', 'b', 'g'], ['d', 'e', 'h'], ['c', 'f', 'i']]而不是 [('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')] - acollection_
20
这段代码的作用是将二维列表theArray进行转置,即行变成列,列变成行。其中,map函数用于对theArray进行映射操作,list函数将zip函数返回的元组序列转化为列表形式。而zip(*theArray)则将二维列表进行解压缩,相当于把每一列分别打包为一个元组,再把所有元组组成一个序列。 - jfs
1
@AntonyHatchkins 在 Python 3.0 及以上版本中不需要这样做。在那里,zip 已经返回一个迭代器:https://docs.python.org/3.0/whatsnew/3.0.html#views-and-iterators-instead-of-lists - xuiqzy
1
@xuiqzy 我并不是没有意识到,但那是真的。 - Antony Hatchkins
显示剩余4条评论

68
>>> theArray = [['a','b','c'],['d','e','f'],['g','h','i']]
>>> [list(i) for i in zip(*theArray)]
[['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']]

列表生成器创建一个新的二维数组,其中包含列表项而不是元组。


这是正确的方式,如果你想将结果分配给一个变量(而不是直接遍历它),假设你想要列表而不是元组,如前所述。 - ASL
另一个选项(正如接受答案中的评论所暗示的那样)是:list(map(list, zip(*theArray))) - ASL

42
如果你的行不相等,你也可以使用 map:
>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> map(None,*uneven)
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

编辑:在Python 3中,map的功能发生了变化,可以使用itertools.zip_longest代替:
来源:Python 3.0新特性

>>> import itertools
>>> uneven = [['a','b','c'],['d','e'],['g','h','i']]
>>> list(itertools.zip_longest(*uneven))
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', None, 'i')]

20

使用numpy会更加容易:

>>> arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> arr
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> arr.T
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
>>> theArray = np.array([['a','b','c'],['d','e','f'],['g','h','i']])
>>> theArray 
array([['a', 'b', 'c'],
       ['d', 'e', 'f'],
       ['g', 'h', 'i']], 
      dtype='|S1')
>>> theArray.T
array([['a', 'd', 'g'],
       ['b', 'e', 'h'],
       ['c', 'f', 'i']], 
      dtype='|S1')

9
您原来的代码出现问题是因为您每个元素都初始化了transpose[t],而不是每行只初始化一次:
def matrixTranspose(anArray):
    transposed = [None]*len(anArray[0])
    for t in range(len(anArray)):
        transposed[t] = [None]*len(anArray)
        for tt in range(len(anArray[t])):
            transposed[t][tt] = anArray[tt][t]
    print transposed

这个方法是可行的,但有更多Pythonic的方法来完成相同的事情,包括@J.F.的zip应用程序。


1
请注意,此实现不适用于具有不同行列数的矩阵。 - Vector

5
为了补充J.F. Sebastian的回答,如果你有一个长度不同的列表嵌套列表,请查看ActiveState的这篇很好的帖子。简而言之:
内置函数zip完成类似的工作,但是结果被截断为最短列表的长度,因此原始数据中的一些元素可能会丢失。
要处理长度不同的列表嵌套列表,请使用:
def transposed(lists):
   if not lists: return []
   return map(lambda *row: list(row), *lists)

def transposed2(lists, defval=0):
   if not lists: return []
   return map(lambda *row: [elem or defval for elem in row], *lists)

这是一个很好的发现。然而,矩阵没有不同长度的列表。 - Olli
这取决于它们是如何存储的。 - Franck Dernoncourt

5
已经提交了“最佳”答案,但我想补充一下,您可以使用嵌套列表推导式,就像在Python教程中所看到的那样。
以下是获取转置数组的方法:
def matrixTranspose( matrix ):
    if not matrix: return []
    return [ [ row[ i ] for row in matrix ] for i in range( len( matrix[ 0 ] ) ) ]

2
这个将保留矩形形状,这样后续的转置才能得到正确的结果:
import itertools
def transpose(list_of_lists):
  return list(itertools.izip_longest(*list_of_lists,fillvalue=' '))

2
你可以尝试使用列表推导式来实现,代码如下: matrix = [['a','b','c'],['d','e','f'],['g','h','i']] n = len(matrix) transpose = [[row[i] for row in matrix] for i in range(n)] print (transpose) 这段代码可以将一个二维矩阵进行转置。

1

您可以使用Python的推导式来简单地完成它。

arr = [
    ['a', 'b', 'c'], 
    ['d', 'e', 'f'], 
    ['g', 'h', 'i']
]
transpose = [[arr[y][x] for y in range(len(arr))] for x in range(len(arr[0]))]

虽然这可能是一个正确的答案,但如果没有解释它是如何解决原问题的,两行代码并不是非常有用。请提供您的答案细节。 - RyanNerd
1
当回答一个旧问题时,期望值很高。请不要发布低劣的解决方案,尤其是已经有其他更好的解决方案存在的情况下。 - Jean-François Fabre

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