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()
No description has been provided for this image

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()
No description has been provided for this image
In [ ]: