Dekomposisi eigen pada Chapter Eigenvalue dan Eigenvector hanya berlaku untuk matriks persegi. Singular Value Decomposition (SVD) jauh lebih umum: setiap matriks, persegi maupun tidak, dapat difaktorkan menjadi perkalian tiga matriks dengan bentuk A = U Σ Vh, di mana U dan V orthogonal dan Σ diagonal berisi nilai singular. Karena berlaku universal, SVD menjadi mesin di balik banyak alat: perhitungan rank, pseudo-inverse, kompresi data, sampai analisis komponen utama.
Di NumPy, satu panggilan np.linalg.svd(A) mengembalikan ketiga komponen tersebut. Bab ini membedah anatomi hasilnya, membuktikan bahwa A dapat direkonstruksi dari potongan-potongannya, lalu menutup dengan ide kompresi: mengapa membuang nilai singular kecil hampir tidak mengubah matriks. Sebagai penghubung dengan section Operasi Matriks, kita tetap memakai matriks A = [[1, 2], [3, 4]].
Anatomi Hasil np.linalg.svd #
np.linalg.svd mengembalikan tuple berisi tiga array. Ada dua konvensi NumPy yang perlu kita kenali sejak awal: matriks V dikembalikan dalam keadaan sudah di-transpose (namanya Vh), dan Σ tidak dikembalikan sebagai matriks, melainkan sebagai array 1-D berisi diagonalnya yang terurut menurun.
import numpy as np
A = np.array([[1, 2],
[3, 4]])
U, S, Vh = np.linalg.svd(A)
print(U)
print(S)
print(Vh)
print(U.shape, S.shape, Vh.shape)Output yang Dihasilkan:
[[-0.40455358 -0.9145143 ]
[-0.9145143 0.40455358]]
[5.4649857 0.36596619]
[[-0.57604844 -0.81741556]
[ 0.81741556 -0.57604844]]
(2, 2) (2,) (2, 2)Bedah baris demi baris:
- Baris 3-4 (
A = np.array(...)): matriks 2x2 yang sama dengan contoh pada section Operasi Matriks, sehingga angkanya mudah dilacak. - Baris 5 (
U, S, Vh = np.linalg.svd(A)): fungsi mengembalikan tuple(U, S, Vh); tiga variabel menampung hasilnya sekaligus. - Baris 6 (
print(U)):Uberordo (2, 2) dengan kolom-kolom orthonormal — panjang tiap kolom 1 dan saling tegak lurus. - Baris 7 (
print(S)):Sadalah array 1-D, bukan matriks:[5.4649857 0.36596619]. Nilainya terurut menurun; nilai singular terbesar selalu berada di indeks 0. - Baris 8 (
print(Vh)):VhadalahVyang sudah di-transpose, sehingga baris-barisnya orthonormal. - Baris 9: bentuk
(2, 2) (2,) (2, 2)menegaskan bahwaSmemang 1-D.
Tabel berikut merangkum peran ketiga hasil terhadap bentuk A = U Σ Vh:
| Hasil | Bentuk | Isi | Peran dalam A = U Σ Vh |
|---|---|---|---|
U | (m, m) | kolom orthonormal | arah-arah di ruang kolom A |
S | (k,) | nilai singular menurun | besaran peregangan tiap arah |
Vh | (n, n) | baris orthonormal | arah-arah di ruang baris A |
Rekonstruksi A dari U, S, dan Vh #
Uji paling meyakinkan bagi sebuah dekomposisi adalah mengalikan kembali potongan-potongannya. Perkalian U @ diag(S) @ Vh harus menghasilkan A — persis secara matematis, dan nyaris persis dalam aritmetika float.
import numpy as np
A = np.array([[1, 2],
[3, 4]])
U, S, Vh = np.linalg.svd(A)
print(np.diag(S))
rekon = U @ np.diag(S) @ Vh
print(rekon)
print(np.allclose(rekon, A))
tol = S.max() * max(A.shape) * np.finfo(S.dtype).eps
print(tol)
print((S > tol).sum())
print(np.linalg.matrix_rank(A))Output yang Dihasilkan:
[[5.4649857 0. ]
[0. 0.36596619]]
[[1. 2.]
[3. 4.]]
True
2.4269411832285226e-15
2
2Mari kita telaah baris-baris barunya:
- Baris 6 (
print(np.diag(S))):np.diag(S)menyusun matriks diagonal 2x2 dari vektorS— inilah wujudΣyang sesungguhnya. - Baris 7-8 (
rekon = ...): perkalianU @ Σ @ Vhmengembalikan susunan asli[[1. 2.] [3. 4.]]. - Baris 9 (
np.allclose(rekon, A)):Trueberarti hasil sama dalam toleransi default; perbedaannya hanya pada digit belakang representasi float. - Baris 10 (
tol = ...): ambang batas rank: nilai singular terbesar dikali dimensi terbesar dikali epsilon mesin (~2.22e-16untuk float64). Rumus inilah yang dipakainp.linalg.matrix_rank. - Baris 12-13: kedua nilai singular berada di atas
tol, sehingga hitungan manual(S > tol).sum()menghasilkan2— sama persis denganmatrix_rank(A).
Dua nilai singular bernilai jauh dari nol berarti A membawa dua dimensi informasi bebas. Bab berikutnya, Matrix Rank, membahas gagasan ini secara khusus.
Ide Kompresi: Simpan k Nilai Singular Teratas #
Karena S terurut menurun, memotong nilai-nilai kecil di ekor hampir tidak mengubah matriks — inilah dasar kompresi berbasis SVD. Kita uji pada matriks gradien 6x6 yang entrinya G[i, j] = i + j:
import numpy as np
G = (np.arange(6).reshape(-1, 1) + np.arange(6).reshape(1, -1)).astype(float)
U, S, Vh = np.linalg.svd(G)
print(S)
print(np.linalg.norm(G))
for k in (1, 2):
Gk = U[:, :k] @ np.diag(S[:k]) @ Vh[:k, :]
err = np.linalg.norm(G - Gk)
print(f"k={k}: error = {err:.2e}")Output yang Dihasilkan:
[3.31659021e+01 3.16590212e+00 1.44782968e-15 4.38184935e-16
1.21584919e-16 2.42274449e-17]
33.31666249791537
k=1: error = 3.17e+00
k=2: error = 1.62e-14- Baris 3: susun gradien 6x6; entri bertambah satu per langkah baris maupun kolom.
- Baris 4: SVD penuh menghasilkan enam nilai singular.
- Baris 5 (
print(S)): hanya dua nilai besar —33.17dan3.17— sedangkan empat sisanya berordo1e-15atau lebih kecil, praktis nol. Secara matematis matriks gradien ini memang ber-rank 2, dan SVD menangkapnya secara numerik. - Baris 6:
np.linalg.norm(G)menghitung ukuran total matriks (norm Frobenius):33.3167. Angka ini menjadi pembanding seberapa besar error pemotongan. - Baris 8 (
Gk = ...): susun ulang memakai hanyakkolom pertamaU,knilai pertamaS, dankbaris pertamaVh— versi terkompresi dariG. - Baris 10: error diukur sebagai jarak Frobenius antara
Gasli dan versi terpotong.
| k dipertahankan | Error | Makna |
|---|---|---|
| 1 | 3.17e+00 | sekitar 9,5% dari ukuran total 33.32; satu komponen belum cukup |
| 2 | 1.62e-14 | praktis nol; matriks memang ber-rank 2 |
Dari tabel terlihat polanya: nilai singular kecil boleh dibuang karena kontribusinya sekecil galat float. Pada data nyata yang besar, pola yang sama dipakai untuk memampatkan gambar dan matriks rekomendasi — simpan sedikit nilai teratas, buang sisanya. Batas antara “kecil” dan “bermakna” inilah yang diukur secara formal oleh rank pada Chapter Matrix Rank.