NumPyはPythonで数値計算を行うための基盤ライブラリであり、特に行列操作は機械学習や科学技術計算で必須のスキルです。
今回は、NumPyで行列を操作する際に必要な基本操作から線形代数の計算まで、網羅的にまとめます。
本記事の内容
- 行列の作成(単位行列、零行列、対角行列)
- 行列の結合・分割
- 行列の演算(積、転置、逆行列)
- 固有値分解・特異値分解
単位行列を作成
NumPyで単位行列を作成するには、identity 関数と eye 関数を使います。
import numpy as np
# identity: 正方単位行列
I3 = np.identity(3)
print("identity(3):")
print(I3)
# eye: より柔軟(非正方行列も可、対角オフセット可)
E = np.eye(3, 4)
print("\neye(3, 4):")
print(E)
# 対角をずらした行列
E_k1 = np.eye(4, k=1)
print("\neye(4, k=1):")
print(E_k1)
特殊な行列の作成
import numpy as np
# 零行列
Z = np.zeros((3, 4))
print("zeros(3, 4):")
print(Z)
# 全要素が1の行列
O = np.ones((2, 3))
print("\nones(2, 3):")
print(O)
# 対角行列
D = np.diag([1, 2, 3, 4])
print("\ndiag([1, 2, 3, 4]):")
print(D)
# 既存行列から対角要素を抽出
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
diag_elements = np.diag(A)
print(f"\ndiag(A): {diag_elements}") # [1, 5, 9]
# ランダム行列
R = np.random.randn(3, 3)
print("\nrandom matrix:")
print(R.round(3))
行列同士を結合
NumPyで行列同士を結合するためには、以下の関数を利用します。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# vstack: 縦方向に結合
V = np.vstack([A, B])
print("vstack:")
print(V)
# hstack: 横方向に結合
H = np.hstack([A, B])
print("\nhstack:")
print(H)
# concatenate: axis指定で結合
C0 = np.concatenate([A, B], axis=0) # vstack と同じ
C1 = np.concatenate([A, B], axis=1) # hstack と同じ
print(f"\nconcatenate(axis=0):\n{C0}")
print(f"\nconcatenate(axis=1):\n{C1}")
# block: ブロック行列の作成
block_matrix = np.block([
[A, B],
[B, A]
])
print("\nblock matrix:")
print(block_matrix)
行列の分割
import numpy as np
M = np.arange(12).reshape(3, 4)
print("元の行列:")
print(M)
# 列方向に2分割
left, right = np.hsplit(M, 2)
print(f"\nhsplit left:\n{left}")
print(f"hsplit right:\n{right}")
# 行方向に指定位置で分割
top, bottom = np.vsplit(M, [1])
print(f"\nvsplit top:\n{top}")
print(f"vsplit bottom:\n{bottom}")
行列の転置
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]])
print(f"A:\n{A}")
print(f"A.shape: {A.shape}")
# 転置(3通りの方法)
print(f"\nA.T:\n{A.T}")
print(f"np.transpose(A):\n{np.transpose(A)}")
print(f"A.T.shape: {A.T.shape}")
行列の積
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 行列積(3通りの方法)
print(f"A @ B:\n{A @ B}")
print(f"np.dot(A, B):\n{np.dot(A, B)}")
print(f"np.matmul(A, B):\n{np.matmul(A, B)}")
# 要素ごとの積(アダマール積)
print(f"\nA * B (element-wise):\n{A * B}")
# ベクトルとの積
v = np.array([1, 2])
print(f"\nA @ v: {A @ v}")
@ 演算子と np.dot はどちらも行列積ですが、@ の方が読みやすく推奨されています。* は要素ごとの積(アダマール積)であることに注意してください。
逆行列と行列式
import numpy as np
A = np.array([[2, 1], [5, 3]])
# 逆行列
A_inv = np.linalg.inv(A)
print(f"A:\n{A}")
print(f"\nA_inv:\n{A_inv}")
# 検証: A @ A_inv = I
print(f"\nA @ A_inv:\n{(A @ A_inv).round(10)}")
# 行列式
det = np.linalg.det(A)
print(f"\ndet(A): {det:.4f}")
# ランク
rank = np.linalg.matrix_rank(A)
print(f"rank(A): {rank}")
# トレース
trace = np.trace(A)
print(f"trace(A): {trace}")
連立方程式を解く
$\bm{A}\bm{x} = \bm{b}$ の形の連立方程式を解きます。
$$ \begin{pmatrix} 2 & 1 \\ 5 & 3 \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} 4 \\ 7 \end{pmatrix} $$
import numpy as np
A = np.array([[2, 1], [5, 3]])
b = np.array([4, 7])
# 連立方程式の解
x = np.linalg.solve(A, b)
print(f"解: x = {x}")
print(f"検証: A @ x = {A @ x}")
np.linalg.solve は逆行列を明示的に計算するよりも数値的に安定で高速です。
固有値分解
正方行列 $\bm{A}$ の固有値 $\lambda$ と固有ベクトル $\bm{v}$ は以下を満たします。
$$ \bm{A}\bm{v} = \lambda \bm{v} $$
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[3, 1], [1, 2]])
# 固有値分解
eigenvalues, eigenvectors = np.linalg.eig(A)
print(f"固有値: {eigenvalues}")
print(f"固有ベクトル:\n{eigenvectors}")
# 検証: A @ v = lambda * v
for i in range(len(eigenvalues)):
v = eigenvectors[:, i]
lam = eigenvalues[i]
lhs = A @ v
rhs = lam * v
print(f"\nlambda_{i} = {lam:.4f}")
print(f" A @ v = {lhs.round(4)}")
print(f" lambda * v = {rhs.round(4)}")
# 固有ベクトルの可視化
fig, ax = plt.subplots(figsize=(6, 6))
# 単位円上の点にAをかけて変形を可視化
theta = np.linspace(0, 2 * np.pi, 100)
circle = np.array([np.cos(theta), np.sin(theta)])
ellipse = A @ circle
ax.plot(circle[0], circle[1], 'b-', linewidth=1, alpha=0.3, label='Unit circle')
ax.plot(ellipse[0], ellipse[1], 'r-', linewidth=2, label='A @ circle')
# 固有ベクトル
for i in range(2):
v = eigenvectors[:, i] * eigenvalues[i]
ax.arrow(0, 0, v[0], v[1], head_width=0.1, head_length=0.05,
fc='green', ec='green', linewidth=2)
ax.text(v[0]*1.15, v[1]*1.15, f'lambda={eigenvalues[i]:.2f}', fontsize=11)
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
ax.legend()
ax.set_title("Eigenvalue Decomposition: A transforms unit circle to ellipse")
plt.tight_layout()
plt.show()
特異値分解(SVD)
任意の $m \times n$ 行列 $\bm{A}$ に対して、特異値分解は以下のように分解します。
$$ \bm{A} = \bm{U} \bm{\Sigma} \bm{V}^T $$
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]])
U, S, Vt = np.linalg.svd(A)
print(f"A shape: {A.shape}")
print(f"U shape: {U.shape}")
print(f"S (singular values): {S}")
print(f"Vt shape: {Vt.shape}")
# 復元の検証
Sigma = np.zeros_like(A, dtype=float)
np.fill_diagonal(Sigma, S)
A_reconstructed = U @ Sigma @ Vt
print(f"\nReconstructed A:\n{A_reconstructed.round(10)}")
まとめ
本記事では、NumPyでの行列操作を網羅的に解説しました。
- 行列の作成:
identity,eye,zeros,ones,diagで各種行列を生成 - 結合・分割:
vstack,hstack,concatenate,blockで柔軟に結合 - 行列積:
@演算子が最も推奨される書き方。*は要素ごとの積 - 逆行列・行列式:
np.linalg.inv,np.linalg.detで計算。連立方程式はsolveが安定 - 固有値分解・SVD:
np.linalg.eig,np.linalg.svdで分解。機械学習の基盤