Python/SciPy

SciPy 행렬 연산과 특이값 분해 (SVD)

임베디드 친구 2025. 11. 19. 21:36
728x90
반응형

SciPy 행렬 연산과 특이값 분해 (SVD)

1. 서론

과학 및 공학 분야에서 행렬 연산은 데이터를 처리하고 분석하는 데 필수적인 도구입니다. 특히, 특이값 분해(Singular Value Decomposition, SVD)는 고차원 데이터를 저차원으로 압축하거나 잡음을 제거하는 데 유용하게 사용됩니다. SciPy의 scipy.linalg 모듈은 이러한 행렬 연산을 간편하게 처리할 수 있도록 다양한 기능을 제공합니다.

이 글에서는 SciPy의 linalg 모듈을 활용한 행렬 연산과 특이값 분해(SVD)에 대해 살펴보겠습니다. 기본적인 행렬 연산과 함께 SVD의 이론적 배경과 실제 구현 방법을 예제와 함께 설명드립니다.


2. SciPy에서 행렬 생성과 기본 연산

SciPy는 scipy.linalg 모듈을 통해 행렬을 다루는 다양한 기능을 제공합니다. 먼저, SciPy와 NumPy를 활용해 행렬을 생성하고 기본적인 연산을 수행하는 방법을 살펴보겠습니다.

2.1 행렬 생성

SciPy에서는 NumPy와의 호환성을 통해 행렬을 생성할 수 있습니다. 다음은 3x3 행렬을 생성하는 예제입니다.

import numpy as np
from scipy.linalg import inv, det

# 3x3 행렬 생성
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

print("행렬 A:\n", A)

2.2 행렬의 전치 (Transpose)

행렬의 전치는 행렬의 행과 열을 바꾸는 연산입니다.

# 행렬 전치
A_T = A.T
print("A의 전치 행렬:\n", A_T)

2.3 행렬의 역행렬 (Inverse)

정사각 행렬의 경우, 역행렬이 존재하면 행렬을 역전할 수 있습니다. 그러나 행렬식이 0인 행렬은 역행렬을 가질 수 없습니다.

# 역행렬 계산
try:
    A_inv = inv(A)
    print("A의 역행렬:\n", A_inv)
except np.linalg.LinAlgError:
    print("행렬 A는 역행렬이 존재하지 않습니다.")

2.4 행렬식 (Determinant)

행렬의 행렬식은 행렬의 성질을 결정하는 값으로, 0이면 역행렬이 존재하지 않습니다.

# 행렬식 계산
A_det = det(A)
print("A의 행렬식:", A_det)

3. 특이값 분해 (SVD)란 무엇인가?

특이값 분해(Singular Value Decomposition, SVD)는 임의의 m×n 행렬 $ A $를 세 개의 행렬의 곱으로 표현하는 방법입니다. 다음과 같이 나타낼 수 있습니다.

$$
A = U \Sigma V^T
$$

여기서:

  • $ U $: m×m 직교 행렬 (왼쪽 특이벡터)
  • $ \Sigma $: 대각 행렬 (특이값)
  • $ V^T $: n×n 직교 행렬 (오른쪽 특이벡터의 전치)

특이값 분해는 데이터 압축, 차원 축소, 잡음 제거 등 다양한 분야에서 활용됩니다.

3.1 SVD의 주요 특징

  1. 모든 행렬에 대해 존재: 정방행렬뿐만 아니라 비정방행렬에도 적용 가능
  2. 특이값: 행렬의 선형 독립성을 나타내는 값
  3. 데이터 압축: 큰 데이터를 저차원으로 표현 가능

4. SciPy를 활용한 SVD 구현

SciPy에서는 scipy.linalg.svd()를 이용해 간단하게 SVD를 수행할 수 있습니다.

4.1 기본 SVD 수행

다음은 간단한 3x3 행렬에 대해 SVD를 수행하는 예제입니다.

from scipy.linalg import svd

# 행렬 A
A = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

# SVD 수행
U, S, VT = svd(A)

# 결과 출력
print("U 행렬:\n", U)
print("특이값(벡터 형태):\n", S)
print("V^T 행렬:\n", VT)

4.2 특이값을 대각 행렬로 변환

SciPy의 svd()는 특이값을 벡터 형태로 반환합니다. 이를 대각 행렬로 변환하려면 다음과 같이 수행할 수 있습니다.

# 특이값을 대각 행렬로 변환
Sigma = np.zeros((A.shape[0], A.shape[1]))
np.fill_diagonal(Sigma, S)

print("특이값 대각 행렬:\n", Sigma)

4.3 SVD 복원

SVD의 결과를 통해 원본 행렬을 복원하는 방법은 다음과 같습니다.

# SVD를 통해 원본 행렬 복원
A_reconstructed = np.dot(U, np.dot(Sigma, VT))

print("복원된 행렬:\n", A_reconstructed)

5. SVD의 활용 사례

5.1 이미지 압축

특이값을 활용해 이미지를 압축하는 예제를 살펴보겠습니다.

import matplotlib.pyplot as plt
from scipy.linalg import svd

# 이미지 불러오기
image = plt.imread("example_image.png")
if image.shape[-1] == 3:
    image = np.mean(image, axis=-1)  # 흑백으로 변환

# SVD 수행
U, S, VT = svd(image)

# 특이값 상위 50개만 사용
k = 50
Sigma_k = np.zeros((U.shape[0], VT.shape[0]))
np.fill_diagonal(Sigma_k, S[:k])

# 복원된 이미지 생성
compressed_image = np.dot(U[:, :k], np.dot(Sigma_k[:k, :k], VT[:k, :]))

# 원본과 압축 이미지 비교
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("원본 이미지")
plt.imshow(image, cmap="gray")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.title("압축된 이미지 (k=50)")
plt.imshow(compressed_image, cmap="gray")
plt.axis("off")
plt.show()

5.2 차원 축소와 데이터 분석

SVD는 고차원 데이터를 저차원으로 축소하는 데도 사용됩니다. 이는 주성분 분석(PCA)과 유사한 과정으로, 데이터의 주요 특징을 유지하면서 불필요한 요소를 제거할 수 있습니다.


6. SVD의 한계와 주의사항

  1. 계산 비용: 큰 행렬에서는 계산 비용이 높을 수 있습니다.
  2. 잡음 민감성: 작은 특이값이 잡음의 영향을 받을 수 있습니다.
  3. 역행렬과의 관계: 특이값이 0에 가까우면 역행렬을 구하는 과정에서 수치적 불안정성이 발생할 수 있습니다.

7. 결론

특이값 분해(SVD)는 행렬의 구조를 분석하고 데이터를 압축하거나 차원을 축소하는 데 유용한 기법입니다. SciPy의 scipy.linalg.svd() 함수는 이러한 과정을 간단하게 수행할 수 있도록 지원합니다.

이 포스팅을 통해 SVD의 개념과 SciPy를 활용한 구현 방법을 이해하고, 실제 데이터 분석과 이미지 처리에 어떻게 적용할 수 있는지 살펴보았습니다.


8. 참고 문헌 및 자료

  1. SciPy 공식 문서 - scipy.linalg.svd
  2. [Numerical Linear Algebra (Lloyd N. Trefethen, David Bau)]
  3. [Python for Data Analysis (Wes McKinney)]
반응형