0Pricing
Pandas & NumPy Academy · 강의

행렬식, 역행렬, 전치행렬

np.linalg.det으로 행렬식을, np.linalg.inv로 역행렬을, .T로 전치행렬을 계산합니다.

행렬식, 역행렬, 전치행렬은(는) CoddyKit의 무료 Pandas & NumPy Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Pandas & NumPy Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

행렬의 전치

행렬의 전치는 행렬을 주대각선을 기준으로 뒤집는 연산입니다. 행은 열이 되고 열은 행이 됩니다. A의 형태가 (m, n)이면 A.T의 형태는 (n, m)입니다. 전치는 선형 대수의 여러 곳에서 사용됩니다. 예를 들어 공분산 행렬을 계산하고, 경사 역전파를 구현하며, 행 벡터와 열 벡터 표기법 사이를 변환할 때 사용합니다. NumPy에서는 .T 속성으로 전치에 접근합니다. 복사본은 만들어지지 않고, 보폭의 순서만 바꾼 뷰가 생성됩니다.

import numpy as np

A = np.array([[1, 2, 3],
              [4, 5, 6]])
print('A shape:', A.shape)       # (2, 3)
print('A.T shape:', A.T.shape)   # (3, 2)
print(A.T)

전치의 실제 활용

자주 사용하는 패턴 중 하나는 A.T @ A를 계산하는 것입니다. 이 연산은 최소제곱 회귀, PCA, 정규 방정식에 등장하는 대칭 정방 행렬을 만듭니다. A의 형태가 (n, p)이면 A.T @ A의 형태는 (p, p)입니다. 결과가 항상 대칭인 이유는 (A.T @ A)[i,j] == (A.T @ A)[j,i]이기 때문입니다. 많은 수치 해법은 효율성을 위해 이 특성을 활용합니다.

import numpy as np

A = np.array([[1.0, 2.0],
              [3.0, 4.0],
              [5.0, 6.0]])  # shape (3, 2)

ATA = A.T @ A   # shape (2, 2), symmetric
print('A.T @ A:')
print(ATA)
print('Is symmetric:', np.allclose(ATA, ATA.T))

행렬식: 의미

정방 행렬의 행렬식은 기하학적 정보를 담은 스칼라 값입니다. 행렬이 넓이(2차원) 또는 부피(고차원)를 얼마나 배율로 확대하거나 축소하는지를 나타냅니다. 행렬식이 0이면 행렬은 특이합니다. 즉, 공간을 더 낮은 차원의 부분 공간으로 찌그러뜨리므로 역행렬이 없습니다. 0이 아닌 행렬식은 행렬이 가역임을 보장합니다. NumPy에서는 np.linalg.det()로 행렬식을 계산합니다.

import numpy as np

# Non-singular matrix
A = np.array([[3.0, 1.0],
              [2.0, 4.0]])
print('det(A):', np.linalg.det(A))   # 3*4 - 1*2 = 10

# Singular matrix (row 2 = 2 * row 1)
B = np.array([[1.0, 2.0],
              [2.0, 4.0]])
print('det(B):', np.linalg.det(B))   # ~0

np.linalg.inv()로 역행렬 계산하기

행렬 A의 역행렬 A⁻¹은 A @ A⁻¹ = I를 만족합니다. 여기서 I는 단위 행렬입니다. 역행렬은 정방 행렬이면서 비특이 행렬인 경우에만 존재합니다. np.linalg.inv(A)는 역행렬을 수치적으로 계산합니다. 실제로는 수치적으로 불안정하므로 역행렬을 직접 계산하는 일은 거의 없어야 합니다. 대신 연립 방정식에는 np.linalg.solve()를 사용하는 것이 좋습니다. 다만 역행렬의 개념을 이해하는 것은 매우 중요합니다.

import numpy as np

A = np.array([[3.0, 1.0],
              [2.0, 4.0]])

A_inv = np.linalg.inv(A)
print('Inverse:')
print(A_inv)

# Verify: A @ A_inv should be identity
I = A @ A_inv
print('A @ A_inv (should be I):')
print(np.round(I, 10))

직접 역행렬을 계산할 때의 수치적 불안정성

행렬의 역행렬을 계산한 다음 곱셈을 수행하면 부동소수점 오류가 누적됩니다. 예를 들어 A_inv @ b로 푸는 것보다 np.linalg.solve(A, b)를 직접 호출하는 편이 더 정확합니다. 조건이 좋은 행렬(행렬식이 0에서 멀리 떨어진 행렬)은 이러한 오류에 덜 민감합니다. 조건수(np.linalg.cond(A))는 행렬이 특이 행렬에 얼마나 가까운지를 수치화합니다. 조건수가 높으면 수치적으로 문제가 생길 가능성이 큽니다.

import numpy as np

A = np.array([[1.0, 2.0],
              [1.0001, 2.0]])
print('Condition number:', np.linalg.cond(A))
# Very high condition number -> near-singular, unstable inversion

b = np.array([3.0, 3.0001])
# Prefer solve over inv @ b
print('Solution via solve:', np.linalg.solve(A, b))

직교 행렬과 전치

직교 행렬은 특별한 종류의 행렬로, A.T @ A = I를 만족합니다. 이는 전치가 역행렬과 같다는 뜻이므로 직교 행렬은 역행렬을 매우 저렴하게 계산할 수 있습니다. 회전 행렬과 QR 분해의 Q 인자는 직교 행렬입니다. 직교 행렬의 열은 정규 직교 기저를 이룹니다. 각 열의 길이는 1이고 다른 모든 열과 수직입니다.

import numpy as np

# 90-degree rotation matrix is orthogonal
theta = np.pi / 2
R = np.array([[np.cos(theta), -np.sin(theta)],
              [np.sin(theta),  np.cos(theta)]])

print('R.T @ R (should be identity):')
print(np.round(R.T @ R, 10))
print('Is orthogonal:', np.allclose(R.T @ R, np.eye(2)))

정방 행렬이 아닌 행렬의 의사역행렬

일반적인 역행렬은 정방 행렬에서만 존재하지만, Moore-Penrose 의사역행렬은 모든 행렬에 대해 역행렬 개념을 일반화합니다. np.linalg.pinv(A)는 SVD를 사용해 이를 계산합니다. 의사역행렬은 과잉 결정 시스템(미지수보다 방정식이 많은 시스템)의 최소제곱 해를 구하는 기반이며, 이는 선형 회귀가 정확히 해결하는 문제입니다. A가 정방 행렬이고 가역이면 pinv(A)는 inv(A)와 같습니다.

import numpy as np

# Over-determined system: 3 equations, 2 unknowns
A = np.array([[1.0, 1.0],
              [1.0, 2.0],
              [1.0, 3.0]])
b = np.array([2.0, 3.0, 5.0])

# Least-squares solution using pseudo-inverse
x = np.linalg.pinv(A) @ b
print('Best-fit solution:', x)
# Or use lstsq directly
x2, _, _, _ = np.linalg.lstsq(A, b, rcond=None)
print('lstsq solution:', x2)

행렬식의 부호와 부피 배율

행렬식의 부호는 변환이 방향을 보존하는지 뒤집는지를 나타냅니다. 행렬식이 양수이면 방향이 보존되고(회전과 같음), 음수이면 방향이 뒤집힙니다(반사와 같음). 절댓값은 부피 배율을 나타냅니다. 2×2 행렬 [[a,b],[c,d]]의 경우 det = a*d - b*c입니다. NumPy는 임의 크기의 정방 행렬을 효율적으로 처리합니다.

import numpy as np

# Identity: det = 1 (no scaling, no flip)
I = np.eye(3)
print('det(I):', np.linalg.det(I))    # 1.0

# Scaling by 2 in all directions: det = 8 = 2^3
S = 2 * np.eye(3)
print('det(2I):', np.linalg.det(S))   # 8.0

# Reflection: det = -1
F = np.array([[-1.0, 0.0],
              [ 0.0, 1.0]])
print('det(reflection):', np.linalg.det(F))

안정성을 위한 np.linalg.slogdet() 사용

큰 행렬에서는 행렬이 비특이 행렬인 경우에도 행렬식이 오버플로되거나 0으로 언더플로될 수 있습니다. np.linalg.slogdet(A)는 (sign, log_abs_det)를 반환합니다. 이는 행렬식의 부호와 절댓값의 자연 로그를 나타내며, 수치적 오버플로를 방지합니다. 이 방법은 확률 모델(가우시안 우도)에서 널리 사용됩니다. 이러한 모델에서는 수를 다루기 쉬운 크기로 유지하기 위해 로그 공간에서 계산합니다.

import numpy as np

A = np.random.rand(100, 100)

# Direct det might underflow for large matrices
sign, logdet = np.linalg.slogdet(A)
print('Sign:', sign)
print('Log|det|:', logdet)
print('Actual det (may be ~0 due to float):', np.linalg.det(A))
print('Reconstructed |det|:', np.exp(logdet))

실전: 손으로 2x2 풀기와 NumPy 비교

2×2 행렬 [[a, b], [c, d]]의 역행렬은 (1/det) * [[d, -b], [-c, a]]이며, 여기서 det = ad - bc입니다. 이 공식을 알고 있으면 NumPy의 결과를 간단히 검산할 수 있습니다. 더 큰 행렬은 해석적으로 역행렬을 계산하기가 비현실적이며, 바로 그렇기 때문에 np.linalg.inv()를 사용합니다. 수치 결과는 항상 np.allclose(A @ A_inv, np.eye(n))로 확인하세요.

import numpy as np

a, b, c, d = 3.0, 1.0, 2.0, 4.0
A = np.array([[a, b], [c, d]])
det = a*d - b*c

# Manual inverse
A_inv_manual = (1/det) * np.array([[d, -b], [-c, a]])
print('Manual inv:')
print(A_inv_manual)

# NumPy inverse
print('np.linalg.inv:')
print(np.linalg.inv(A))
print('Match:', np.allclose(A_inv_manual, np.linalg.inv(A)))

파이프라인에서 전치와 역행렬 결합하기

선형 대수에서 흔히 사용하는 패턴은 전치와 역행렬을 결합하는 것입니다. (A.T @ A)⁻¹ @ A.T를 계산하면 통상 최소제곱에 사용되는 사영 행렬을 얻습니다. NumPy에서는 이를 np.linalg.inv(A.T @ A) @ A.T로 작성할 수 있지만, 다시 말해 np.linalg.lstsq가 수치적으로 더 적합합니다. 이러한 기본 패턴을 알면 해법이 내부적으로 무엇을 하는지 이해하고, 행렬이 거의 특이할 때 문제를 해결하는 데 도움이 됩니다.

import numpy as np

# Design matrix for simple linear regression (with bias)
X = np.column_stack([np.ones(5), np.array([1., 2., 3., 4., 5.])])
y = np.array([2.1, 3.9, 6.2, 8.1, 9.8])

# OLS via normal equations: beta = (X.T @ X)^-1 @ X.T @ y
beta = np.linalg.inv(X.T @ X) @ X.T @ y
print('Coefficients (intercept, slope):', np.round(beta, 3))

# Verify with lstsq
beta2, _, _, _ = np.linalg.lstsq(X, y, rcond=None)
print('lstsq result:', np.round(beta2, 3))

빠른 확인

이번 레슨의 데이터 분석 개념에 대한 이해도를 확인해 보세요.

레슨 요약

이번 레슨에서는 다음을 배웠습니다. A.T는 행과 열을 바꾸는 전치입니다. np.linalg.inv()는 행렬의 역행렬을 계산하지만 직접 사용하는 일은 거의 없어야 하며(solve 또는 lstsq를 사용하세요), np.linalg.det()는 특이 행렬에서 0이 되는 행렬식을 반환합니다. 다음으로 np.linalg.solve를 사용해 선형 시스템을 직접 푸는 방법을 살펴보겠습니다.

자주 묻는 질문

“행렬식, 역행렬, 전치행렬” 강의는 무료인가요?

네 — “행렬식, 역행렬, 전치행렬” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Pandas & NumPy Academy 강의 전체를 잠금 해제할 수 있습니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“행렬식, 역행렬, 전치행렬”에서 뭘 배우나요?

np.linalg.det으로 행렬식을, np.linalg.inv로 역행렬을, .T로 전치행렬을 계산합니다. 브라우저에서 직접 실행하는 실습 코드로 Pandas & NumPy Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Pandas & NumPy Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Pandas & NumPy Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“행렬식, 역행렬, 전치행렬” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Pandas & NumPy Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Pandas & NumPy Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. np.matmul과 @를 사용한 행렬 곱셈
  2. 행렬식, 역행렬, 전치행렬
  3. 선형 시스템 풀기
  4. 고윳값과 SVD 개요
← Pandas & NumPy Academy(으)로 돌아가기