2×2行列の固有値分解¶
In [ ]:
# !pip install japanize-matplotlib
In [ ]:
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
In [ ]:
from google.colab import drive
drive.mount('/content/drive')
固有値
In [ ]:
# 行列
A = np.array([[5.0, 2.0],
[2.0, 8.0]])
In [ ]:
# 固有値・固有ベクトル(対称行列なので np.linalg.eigh を使用)
w, V = np.linalg.eigh(A)
In [ ]:
print("固有値 w =", w)
固有値 w = [4. 9.]
固有ベクトル
In [ ]:
# 正規化済みの固有ベクトル
v1 = V[:, 0] # λ=4
v2 = V[:, 1] # λ=9
In [ ]:
# ---- 正規化を解除(整数比に丸める) ----
# 固有値4の固有ベクトル → [-0.894, 0.447] ≈ (-2, 1)
v1_unscaled = np.round(v1 / np.min(np.abs(v1[v1 != 0]))).astype(int)
# 固有値9の固有ベクトル → [0.447, 0.894] ≈ (1, 2)
v2_unscaled = np.round(v2 / np.min(np.abs(v2[v2 != 0]))).astype(int)
In [ ]:
print("λ=4 の固有ベクトル(整数比):", v1_unscaled)
print("λ=9 の固有ベクトル(整数比):", v2_unscaled)
λ=4 の固有ベクトル(整数比): [-2 1] λ=9 の固有ベクトル(整数比): [1 2]
In [ ]:
# ---- 正規化 ----
v1_norm = v1_unscaled / np.linalg.norm(v1_unscaled)
v2_norm = v2_unscaled / np.linalg.norm(v2_unscaled)
In [ ]:
# ---- 直交確認 ----
dot = np.dot(v1_norm, v2_norm)
In [ ]:
print("正規化後 v1 =", v1_norm)
print("正規化後 v2 =", v2_norm)
print("内積 v1・v2 =", dot) # ほぼ 0 → 直交している
正規化後 v1 = [-0.89442719 0.4472136 ] 正規化後 v2 = [0.4472136 0.89442719] 内積 v1・v2 = 0.0
直交行列・対角行列¶
In [ ]:
# 正規化(列ごと)→ 直交行列 P、対角行列 D
P = V / np.linalg.norm(V, axis=0, keepdims=True) # 正規化(直交は維持)
D = np.diag(w)
In [ ]:
# 検算:P^T P = I, A = P D P^T
I_check = P.T @ P
recon = P @ D @ P.T
In [ ]:
print("P^T P =\n", I_check) # ≈ 単位行列
print("P D P^T =\n", recon) # ≈ A
P^T P = [[1.00000000e+00 8.73987071e-19] [8.73987071e-19 1.00000000e+00]] P D P^T = [[5. 2.] [2. 8.]]
グラフ化¶
正規直交固有ベクトル¶
In [ ]:
def draw_vec(ax, v, label, style=None):
kw = dict(arrowstyle="->", linewidth=2)
if style: kw.update(style)
ax.annotate("", xy=(v[0], v[1]), xytext=(0, 0), arrowprops=kw)
ax.text(v[0] + 0.05, v[1] + 0.05, label, fontsize=11)
In [ ]:
fig, ax = plt.subplots(figsize=(6, 6))
ax.set_aspect('equal', adjustable='box')
ax.axhline(0, linewidth=1)
ax.axvline(0, linewidth=1)
ax.grid(True, linewidth=0.5, alpha=0.5)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("正規直交固有ベクトル")
v1, v2 = P[:, 0], P[:, 1]
draw_vec(ax, v1, f"v1(λ={w[0]:.0f})")
draw_vec(ax, v2, f"v2(λ={w[1]:.0f})", style={"linestyle": "dashdot"})
lims = 1.2 * np.max(np.abs(np.column_stack([v1, v2])))
ax.set_xlim(-lims, lims)
ax.set_ylim(-lims, lims)
plt.tight_layout()
plt.show()
2×2:単位円→楕円(主軸=固有ベクトル)可視化+ 𝜆 𝑣 λv¶
In [ ]:
# 単位円 → A を作用 → 楕円
theta = np.linspace(0, 2*np.pi, 400)
circle = np.vstack([np.cos(theta), np.sin(theta)]) # 2xN
ellipse = A @ circle
v1, v2 = P[:,0], P[:,1] # 正規直交固有ベクトル
lam1, lam2 = w[0], w[1]
In [ ]:
fig, ax = plt.subplots(figsize=(6,6))
ax.set_aspect('equal', adjustable='box')
ax.axhline(0, lw=1, c='0.5'); ax.axvline(0, lw=1, c='0.5')
ax.grid(True, lw=0.5, alpha=0.4)
ax.plot(circle[0], circle[1], lw=2, label='単位円')
ax.plot(ellipse[0], ellipse[1], lw=2, label='Aで変換後(楕円)')
# 固有ベクトル(主軸)と λv(伸び具合)
ax.plot([0, v1[0]],[0, v1[1]], lw=3, label=f'v1(λ={lam1:.0f})')
ax.plot([0, v2[0]],[0, v2[1]], lw=3, label=f'v2(λ={lam2:.0f})')
ax.plot([0, (lam1*v1)[0]],[0, (lam1*v1)[1]], ls='--', label='λ v1')
ax.plot([0, (lam2*v2)[0]],[0, (lam2*v2)[1]], ls='--', label='λ v2')
ax.set_title("単位円→楕円(主軸=固有ベクトル)")
ax.legend(loc='upper right')
plt.tight_layout(); plt.show()
In [ ]: