np.matmul과 @를 사용한 행렬 곱셈
np.matmul과 @ 연산자로 행렬을 올바르게 곱하고, 요소별 곱셈인 *와 실제 행렬 곱셈을 구분합니다.
np.matmul과 @를 사용한 행렬 곱셈은(는) CoddyKit의 무료 Pandas & NumPy Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Pandas & NumPy Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
행렬 곱셈이 중요한 이유
행렬 곱셈은 데이터 과학과 머신 러닝의 핵심입니다. 신경망, 차원 축소, 선형 변환을 뒷받침하는 연산입니다. 파이썬에서 NumPy는 행렬을 곱하는 두 가지 간결한 방법을 제공합니다. np.matmul() 함수와 Python 3.5에서 도입된 @ 연산자입니다. 두 방법 모두 빠르고 벡터화되어 있으며, 중첩된 파이썬 반복문보다 훨씬 효율적입니다.
행렬 곱셈의 규칙
두 행렬 A와 B에 대해 곱 A @ B가 유효하려면 A의 열 개수와 B의 행 개수가 같아야 합니다. A의 형태가 (m, n)이고 B의 형태가 (n, k)라면 결과의 형태는 (m, k)입니다. 이 규칙을 내부 차원 제약이라고 하며, 어떤 NumPy 함수를 사용하는지와 관계없이 적용됩니다.
import numpy as np
A = np.array([[1, 2], [3, 4]]) # shape (2, 2)
B = np.array([[5, 6], [7, 8]]) # shape (2, 2)
C = A @ B
print(C) # [[19 22] [43 50]]np.matmul과 @ 연산자 비교
np.matmul(A, B)와 A @ B는 2차원 배열에서 동일한 결과를 만듭니다. @ 연산자는 단순한 문법적 편의 기능입니다. 내부적으로는 __matmul__을 호출하고, NumPy는 이를 동일한 C 수준의 BLAS 루틴으로 구현합니다. 일반적인 코드에서는 가독성을 위해 @을 사용하고, 함수를 호출 가능한 객체로 전달하거나 특수한 경우를 명시적으로 처리하려면 np.matmul을 사용합니다.
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(np.matmul(A, B)) # same as A @ B
print(A @ B) # same result@, * 및 np.dot 구분하기
NumPy에는 혼동하기 쉬운 세 가지 곱셈 방식이 있습니다. A * B는 요소별 곱셈(하다마드 곱)입니다. np.dot(A, B)는 2차원 배열에서는 np.matmul처럼 동작하지만 고차원 배열에서는 의미가 다릅니다. A @ B는 엄밀한 행렬 곱셈이며 수학적 정의를 정확히 따릅니다. 따라서 행렬 연산에서는 np.dot보다 @을 사용하는 것이 좋습니다.
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print('element-wise:', A * B) # [[5 12] [21 32]]
print('matmul:', A @ B) # [[19 22] [43 50]]행렬 곱셈은 교환법칙이 성립하지 않습니다
스칼라 곱셈과 달리 행렬 곱셈은 교환법칙이 성립하지 않습니다. 일반적으로 A @ B와 B @ A는 서로 다릅니다. 두 방향 모두에서 형태가 호환되지 않을 수도 있습니다. 이는 변환을 작성할 때 중요합니다. 연산 순서가 결과를 바꾸기 때문입니다. 항상 어떤 행렬이 왼쪽에 있고 어떤 행렬이 오른쪽에 있는지 확인해야 합니다.
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[0, 1], [1, 0]])
print('A @ B:', A @ B) # [[2 1] [4 3]]
print('B @ A:', B @ A) # [[3 4] [1 2]] -- different!배치 행렬 곱셈
배열의 차원이 2보다 클 때 np.matmul과 @은 앞쪽의 추가 차원을 배치 차원으로 취급하고 행렬을 병렬로 곱합니다. 예를 들어 형태가 (32, 3, 4)인 배열에 형태가 (32, 4, 5)인 배열을 곱하면 형태가 (32, 3, 5)인 결과가 나옵니다. 즉, 3×4와 4×5 행렬의 곱셈 32개를 한 번에 독립적으로 수행하는 것입니다. 딥 러닝 프레임워크는 이 방식으로 미니 배치를 효율적으로 처리합니다.
import numpy as np
batch_A = np.random.rand(32, 3, 4)
batch_B = np.random.rand(32, 4, 5)
result = batch_A @ batch_B
print(result.shape) # (32, 3, 5)행렬-벡터 곱셈
행렬에 벡터를 곱하는 것은 흔한 특수한 경우입니다. A의 형태가 (m, n)이고 v가 길이 n인 1차원 배열이라면 A @ v는 길이 m인 1차원 배열을 만듭니다. NumPy가 형태 정렬을 자동으로 처리하므로 v를 열 벡터로 변환할 필요가 없습니다. 이 패턴은 선형 회귀에서 가중치를 적용하거나 특성을 투영하고 각 행의 내적을 동시에 계산하는 등 다양한 곳에서 사용됩니다.
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]]) # (2, 3)
v = np.array([1, 0, -1]) # (3,)
print(A @ v) # [1-3, 4-6] = [-2, -2]성능: @와 파이썬 반복문 비교
NumPy의 행렬 곱셈은 최적화된 BLAS/LAPACK 루틴을 호출하고 컴파일된 C 코드로 실행됩니다. 같은 연산을 순수 파이썬의 중첩 반복문으로 구현하면 대규모 행렬에서 일반적으로 100~1,000배 느립니다. 데이터 파이프라인에서 특성 변환, PCA 투영, 가중치 업데이트처럼 행렬 곱을 반복해서 수행해야 한다면 항상 @ 또는 np.matmul을 사용하고 내부 반복문을 직접 구현하지 마십시오.
import numpy as np, time
A = np.random.rand(500, 500)
B = np.random.rand(500, 500)
t0 = time.time()
C = A @ B
print(f'NumPy: {(time.time()-t0)*1000:.1f} ms') # single-digit ms여러 행렬 곱 연결하기
하나의 표현식에서 여러 @ 연산을 연결할 수 있습니다. A @ B @ C는 왼쪽에서 오른쪽 순서로 평가됩니다. NumPy는 곱셈 순서를 자동으로 최적화하지 않으므로(MATLAB의 mtimes와 다름), 행렬 크기가 크게 다르면 순서가 속도에 영향을 줄 수 있습니다. 행렬이 세 개 이상이라면 가장 효율적인 묶음을 자동으로 선택하는 np.linalg.multi_dot([A, B, C]) 사용을 고려하십시오.
import numpy as np
A = np.random.rand(100, 20)
B = np.random.rand(20, 50)
C = np.random.rand(50, 10)
result = np.linalg.multi_dot([A, B, C])
print(result.shape) # (100, 10)일반적인 형태 오류와 해결 방법
행렬 곱셈에서 가장 흔한 오류는 형태 불일치입니다. ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0이 그 예입니다. 이 문제를 해결하려면 A.shape로 형태를 확인하고 내부 차원이 일치하는지 확인해야 합니다. 형태가 (n,)인 행 벡터를 형태가 (n, 1)인 열 벡터로 취급해야 한다면 v.reshape(-1, 1)을 사용합니다. 전치가 필요하다면 A.T를 사용합니다.
import numpy as np
A = np.ones((3, 4))
B = np.ones((3, 4)) # wrong -- inner dims 4 != 3
try:
A @ B
except ValueError as e:
print('Error:', e)
print('Fix:', (A @ B.T).shape) # (3, 3)실전 예제: 특성 변환
전형적인 데이터 과학 활용 사례를 살펴보겠습니다. 형태가 (n_samples, n_features)인 데이터 세트 X와 형태가 (n_features, n_outputs)인 가중치 행렬 W가 있다고 하겠습니다. 행렬 곱 X @ W는 모든 샘플에 동시에 선형 변환을 적용하여 형태가 (n_samples, n_outputs)인 결과를 만듭니다. 이는 신경망의 선형 층과 선형 회귀 예측에서 핵심이 되는 계산입니다.
import numpy as np
n_samples, n_features, n_outputs = 200, 10, 3
X = np.random.rand(n_samples, n_features)
W = np.random.rand(n_features, n_outputs)
b = np.zeros(n_outputs)
predictions = X @ W + b # shape (200, 3)
print(predictions.shape)빠른 확인
NumPy 행렬 곱셈에 대한 이해도를 확인해 보세요.
레슨 요약
이번 레슨에서는 다음을 배웠습니다. np.matmul과 @는 요소별 곱셈이 아닌 실제 행렬 곱셈을 구현합니다. 또한 두 행렬의 내부 차원은 일치해야 하며, @는 선행 차원에 걸쳐 묶음 곱셈을 지원합니다. 다음으로 행렬을 '되돌릴' 수 있는지 알려 주는 연산인 행렬식, 역행렬, 전치를 살펴보겠습니다.
AI 튜터와 함께 Python을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 30
- 레슨
- 120
자주 묻는 질문
“np.matmul과 @를 사용한 행렬 곱셈” 강의는 무료인가요?
네 — “np.matmul과 @를 사용한 행렬 곱셈” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Pandas & NumPy Academy 강의 전체를 잠금 해제할 수 있습니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“np.matmul과 @를 사용한 행렬 곱셈”에서 뭘 배우나요?
np.matmul과 @ 연산자로 행렬을 올바르게 곱하고, 요소별 곱셈인 *와 실제 행렬 곱셈을 구분합니다. 브라우저에서 직접 실행하는 실습 코드로 Pandas & NumPy Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Pandas & NumPy Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Pandas & NumPy Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“np.matmul과 @를 사용한 행렬 곱셈” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Pandas & NumPy Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Pandas & NumPy Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- np.matmul과 @를 사용한 행렬 곱셈
- 행렬식, 역행렬, 전치행렬
- 선형 시스템 풀기
- 고윳값과 SVD 개요