最近在讀寫 MySQL 數據的過程中,碰到了需要處理 二維矩陣數據 行列轉置 的問題,比如將:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
# 注意:矩陣中每個子序列的長度是相同的
轉化成:
[[1, 5, 9],
[2, 6, 10],
[3, 7, 11],
[4, 8, 12]]
# 行列轉置之后的結果
在研究了一番之后,總結了以下這些方法,做個記錄。
1. 最基礎的 for 循環
def transpose_2d(data):
transposed = []
for i in range(len(data[0])):
new_row = []
for row in data:
new_row.append(row[i])
transposed.append(new_row)
return transposed
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
print(transpose_2d(data))
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# [Finished in 0.1s]
2. 使用列表推導式 List Comprehension
這個其實是第一種方法的高級簡化寫法。
def transpose_2d(data):
transposed = [[row[i] for row in data] for i in range(len(data[0]))]
return transposed
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
print(transpose_2d(data))
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# [Finished in 0.1s]
3. 使用 zip(*iterable) 函數(推薦)
一種高效的寫法,因為 list, map, zip 都是 Python 內建的函數 (Built-ins),所以速度也是相當的快。
def transpose_2d(data):
# transposed = list(zip(*data))
# [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
# 注意 zip 本身返回的數據類型為 tuple 元組
# 其中符號 * 號可以對元素進行解壓或展開
transposed = list(map(list, zip(*data)))
return transposed
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
print(transpose_2d(data))
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# [Finished in 0.1s]
4. 使用 numpy 的 T 轉置
from numpy import transpose
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
transposed = transpose(data).tolist()
print(transposed)
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# [Finished in 0.3s]
# 速度中規中矩,畢竟 numpy 用來處理數學更好
5. 使用 pandas 的 T 轉置
from pandas import DataFrame
data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
transposed = DataFrame(data).T.values.tolist()
print(transposed)
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# [Finished in 0.7s]
# 可能因為 pandas 本身調用了其他的庫,這里明顯感覺偏慢,殺雞用牛刀了
總結
綜上,在一般情況下,我們直接使用 Python 內置的 zip(*) 函數就可以快速實現二維矩陣轉置了,當然使用其他一些專用的庫也是可以的,在性能和便捷程度上做好取舍就可以了,希望對需要的朋友有幫助,感謝支持~
