我不知道大家看到這天會不會驚訝一下,不是應該接續 List 家族這是什麼? Matrix 就是 Array 只是我單獨抽出來說明,如果你沒有在學習或處理資料科學相關的,應該不會使用到 Matrix,但是我認為這是一個蠻常被忽略的部分,也就花一點篇幅來介紹它。
Matrix 是由數字、符號或表達式排列成的長方形陣列。從數學的角度來看,對於 m*n 矩陣的形式,可以描述一個電腦中 A(m,n) 二維陣列。
一個 $m$ 行 $n$ 列的矩陣通常寫作:
$$
A = \begin{pmatrix}
a_{11} & a_{12} & \cdots & a_{1n} \
a_{21} & a_{22} & \cdots & a_{2n} \
\vdots & \vdots & \ddots & \vdots \
a_{m1} & a_{m2} & \cdots & a_{mn}
\end{pmatrix}
$$
其中 $a_{ij}$ 表示第 $i$ 行第 $j$ 列的元素。
名稱 | 定義說明 |
---|---|
行矩陣 | 只有一行的矩陣 ($1 \times n$) |
列矩陣 | 只有一列的矩陣 ($m \times 1$) |
方陣 | 行數與列數相同的矩陣 ($n \times n$) |
零矩陣 | 所有元素皆為 0 的矩陣 |
單位矩陣 | 對角線為 1,其餘為 0 的方陣 |
如果你使用資料科學常見的函式庫 (e.g. Numpy),對於 Matrix 的支援非常的強大,常見的基本運算可能調用一個屬性或方法就能直接處理完成,但是本系列是著重底層知識的理解,所以不會使用到這些高階 API,但是在實務上一定是直接使用這些高階 API。
Matrix 常見的操作沒有很多,接下來會逐一說明,期望各位讀者可以更好的理解,常見的操作如下:
矩陣的加法定義非常直觀: 兩個形狀相同 (同樣的行數與列數) 的矩陣,對應位置的元素相加,就得到一個新矩陣,這種操作在影像處理 (像素加權)、線性代數的向量空間運算中都很常見,代碼演示如下:
def add_matrices(a, b):
rows = len(a)
cols = len(a[0])
c = []
for y in range(rows):
row = []
for x in range(cols):
row.append(0) # 加入一個 0
c.append(row) # 把這列加進外層 list
for i in range(rows):
for j in range(cols):
c[i][j] = a[i][j] + b[i][j]
return c
A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
print(add_matrices(A, B))
矩陣相乘則稍微複雜,A (m×n) 與 B (n×p) 可相乘,得到 C (m×p)。定義是:
$$
C[i][j] = \sum_{k=1}^{n} A[i][k] \times B[k][j]
$$
也就是「A 的第 i 行 × B 的第 j 列」。這種運算是線性代數的核心,在電腦科學、機器學習、圖像轉換、甚至圖神經網路中無處不在。雖然實務上一定用 Numpy、BLAS 等庫來計算,但理解這個三層迴圈的結構很重要,代碼演示如下:
def multiply_matrices(A, B):
rows_A = len(A)
cols_A = len(A[0])
rows_B = len(B)
cols_B = len(B[0])
# 檢查是否可以相乘 (A 的欄數必須等於 B 的列數)
if cols_A != rows_B:
raise ValueError("A 的欄數必須等於 B 的列數")
# 建立結果矩陣 (初始化為 0)
C = [[0 for _ in range(cols_B)] for _ in range(rows_A)]
# 三層迴圈:i=row_A, j=col_B, k=col_A/row_B
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
return C
# 測試
A = [[1, 2, 3], [4, 5, 6]]
B = [[7, 8], [9, 10], [11, 12]]
C = multiply_matrices(A, B)
for row in C:
print(row)
轉置 (Transpose) 是將矩陣沿著對角線翻轉,行變列、列變行:
$$
A^T[i][j] = A[j][i]
$$
轉置操作在數學中用途廣泛,例如:
程式實作上,就是把 $A[i][j]$ 賦值給 $T[j][i]$,代碼演示如下:
def transpose_matrix(A):
rows = len(A)
cols = len(A[0])
# 建立轉置後的矩陣 (cols × rows)
T = [[0 for _ in range(rows)] for _ in range(cols)]
for i in range(rows):
for j in range(cols):
T[j][i] = A[i][j]
return T
# 測試
A = [
[1, 2, 3],
[4, 5, 6]
]
T = transpose_matrix(A)
for row in T:
print(row)
稀疏矩陣是指大部分元素為 0,只少部分有非零值的矩陣。如果直接用二維陣列存放,會浪費大量空間,所以常用「壓縮存儲」方式。
一種常見的表示法是三元組表示法 (COO, Coordinate List):
代碼演示如下:
from typing import List, Tuple
Triplet = List[Tuple[int, int, float]] # [(row, col, val), ...]
Header = Tuple[int, int, int] # (rows, cols, nnz)
def dense_to_triplet(A: List[List[float]], index_base: int = 1) -> Tuple[Header, Triplet]:
"""
將稀疏矩陣的 dense 形式 (list of lists) 壓縮成三元組 (COO)。
index_base: 1 → 輸出 1-based 座標;0 → 輸出 0-based 座標。
"""
if not A or not A[0]:
raise ValueError("矩陣不可為空")
m, n = len(A), len(A[0])
for r in A:
if len(r) != n:
raise ValueError("各列長度需一致 (矩形矩陣)")
triplet: Triplet = []
for i in range(m):
for j in range(n):
v = A[i][j]
if v != 0:
triplet.append((i + index_base, j + index_base, v))
header: Header = (m, n, len(triplet))
return header, triplet
def triplet_to_dense(header: Header, triplet: Triplet, index_base: int = 1) -> List[List[float]]:
"""
將三元組 (COO) 還原為 dense 矩陣。
index_base 要與壓縮時一致。
"""
m, n, nnz = header
if nnz != len(triplet):
raise ValueError("header 的 nnz 與 triplet 長度不一致")
A = [[0 for _ in range(n)] for _ in range(m)]
for r, c, v in triplet:
i = r - index_base
j = c - index_base
if not (0 <= i < m and 0 <= j < n):
raise IndexError(f"索引超界: ({r}, {c}) for shape=({m},{n}) with index_base={index_base}")
A[i][j] = v
return A
def print_dense(A: List[List[float]]) -> None:
for row in A:
print(" ".join(str(x) for x in row))
def print_triplet(header: Header, triplet: Triplet) -> None:
print(header[0], header[1], header[2])
for r, c, v in triplet:
print(r, c, v)
# ----------------------- 範例 -----------------------
if __name__ == "__main__":
# 8x9 的稀疏矩陣(自行示範,可換成你的資料)
A = [
[0,0,0,0,0,0,0,0,0],
[0,0,8,1,0,0,0,0,0],
[0,0,0,0,0,7,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,9,0,0,0,0,0,0,0],
[0,0,0,0,3,0,0,0,4],
[2,0,5,0,0,0,0,3,0],
[0,0,0,0,0,0,0,0,0],
]
print("【原矩陣】")
print_dense(A)
header, trip = dense_to_triplet(A, index_base=1) # 1-based 座標 (與很多教科書顯示一致)
print("\n【三元組壓縮】(rows cols nnz / row col val)")
print_triplet(header, trip)
A_back = triplet_to_dense(header, trip, index_base=1)
print("\n【還原矩陣】")
print_dense(A_back)
矩陣是現代數學與科學不可或缺的工具,掌握其基本概念與運算,將為後續學習打下堅實基礎。矩陣雖然看似只是二維陣列的延伸,但它的運算承載了線性代數的核心思想。
理解矩陣的加法、乘法、轉置與稀疏表示,不僅能幫助你在程式設計上打好基礎,更是日後進入機器學習、圖形處理、科學運算等領域的必備知識。