개요
Python에서 행렬의 무어-펜로즈(Moore-Penrose) 유사역행렬(pseudo-inverse)을 계산하려면 numpy.linalg.pinv() 메서드를 사용합니다. 이 메서드는 특이값 분해(SVD, Singular Value Decomposition)를 기반으로 행렬의 일반화된 역행렬을 계산하며, 크기가 충분히 큰 특이값들은 모두 포함시킵니다.
일반적인 역행렬은 정방행렬이면서 가역적일 때만 존재하지만, 유사역행렬은 그렇지 않은 행렬(9×6처럼 행과 열의 개수가 다른 직사각형 행렬 포함)에도 적용할 수 있습니다. 따라서 선형 회귀의 최소제곱 문제나 데이터 과학 분야에서 널리 활용됩니다.
numpy.linalg.pinv()의 주요 매개변수
- a: 유사역행렬을 구하고자 하는 행렬 또는 행렬의 스택(stack).
- rcond: 작은 특이값에 대한 컷오프(cutoff) 값. 최대 특이값에 rcond를 곱한 값보다 작거나 같은 특이값은 0으로 처리됩니다. 행렬 스택에 대해서는 브로드캐스팅되어 적용됩니다.
- hermitian: True로 설정하면 행렬 a가 에르미트(Hermitian) 행렬이라고 간주하여, 더 효율적인 알고리즘으로 특이값을 계산합니다. 기본값은 False입니다.
구현 단계
먼저 필요한 라이브러리를 임포트합니다.
import numpy as np
randn() 함수를 사용해 난수 값으로 채워진 배열을 생성합니다.
arr = np.random.randn(9, 6)
생성된 배열을 화면에 출력합니다.
print("Our Array...\n", arr)배열의 차원(ndim)을 확인합니다.
print("\nDimensions of our Array...\n", arr.ndim)배열의 데이터 타입(dtype)을 확인합니다.
print("\nDatatype of our Array object...\n", arr.dtype)배열의 형태(shape)를 확인합니다.
print("\nShape of our Array object...\n", arr.shape)numpy.linalg.pinv() 메서드를 호출해 행렬의 무어-펜로즈 유사역행렬을 계산합니다.
print("\nResult...\n", np.linalg.pinv(arr))전체 예제 코드
import numpy as np
# randn()을 사용해 난수 값으로 채운 배열 생성
arr = np.random.randn(9, 6)
# 배열 출력
print("Our Array...\n", arr)
# 차원 확인
print("\nDimensions of our Array...\n", arr.ndim)
# 데이터 타입 확인
print("\nDatatype of our Array object...\n", arr.dtype)
# 형태(shape) 확인
print("\nShape of our Array object...\n", arr.shape)
# numpy.linalg.pinv() 메서드로 무어-펜로즈 유사역행렬 계산
print("\nResult...\n", np.linalg.pinv(arr))실행 결과
Our Array... [[ 2.14644893 -0.14757929 0.14252834 0.54433625 -0.21374741 0.08804508] [-0.05644831 -0.75323572 -1.95304923 0.17167461 -0.64155798 -1.38576017] [-1.40043868 -0.62073383 -0.13501655 0.79788858 -1.47284176 1.03076414] [ 0.52384943 -0.51581571 -0.35674166 1.32374059 -0.31340491 0.26292693] [-0.28434997 0.07384262 1.62577397 -0.54059147 -1.02090985 2.36613533] [-0.22025823 -1.07203572 1.30598633 0.39122889 2.05180917 1.59262088] [-2.53455261 0.79274529 0.1822599 1.11345144 0.54343454 0.27523291] [-1.11915817 1.21435385 0.87345865 0.85541497 1.90349169 -0.05778244] [ 0.99636776 0.83682256 -0.03753307 -0.11389184 1.14089214 0.11317533]] Dimensions of our Array... 2 Datatype of our Array object... float64 Shape of our Array object... (9, 6) Result... [[ 0.19229685 -0.03266066 -0.05913054 0.0990068 0.01377734 -0.02829296 -0.11340774 -0.02715551 0.13106032] [ 0.01242764 -0.03612164 -0.0019295 0.00090135 0.15372234 -0.31686534 0.16305901 0.09059529 0.45836714] [ 0.23344397 -0.46295399 -0.17382325 -0.0801975 -0.10227208 -0.04366331 -0.14434698 0.2615106 -0.84357154] [ 0.28299012 -0.06772757 0.11355691 0.31272279 -0.11283442 -0.0361218 0.12165585 0.17999476 -0.14682526] [-0.11148768 0.11063486 -0.07823299 -0.03096356 -0.07104466 0.24122668 0.02395283 0.01890529 0.26797921] [-0.13235983 0.21188986 0.20340676 0.09081754 0.31058622 0.13372814 0.11417357 -0.20740154 0.71096452]]
정리
위 예제에서 볼 수 있듯이, 9×6 크기의 직사각형 행렬에 대해 pinv() 메서드를 적용하면 전치 형태인 6×9 크기의 유사역행렬이 반환됩니다. 원본 행렬 A에 유사역행렬을 곱한 결과는 항등행렬에 가장 가까운 사영(projection) 행렬이 되며, 이러한 성질 덕분에 역행렬이 존재하지 않는 시스템에서도 안정적으로 최소제곱 해를 구할 수 있습니다. 참고로 rcond 값을 조절하면 노이즈가 많은 데이터에서 작은 특이값을 제거해 수치 안정성을 높일 수 있으며, 행렬이 대칭(또는 에르미트)임이 확실한 경우 hermitian=True 옵션을 활용하면 계산 속도를 개선할 수 있습니다.