브로드캐스팅은 shape가 다른 두 배열을 연산할 때, NumPy가 작은 배열을 "복제한 것처럼" 자동 확장해 shape를 맞추는 규칙입니다.
실제로 데이터를 복제하지는 않으므로(메모리 효율적) 반복문 없이 "각 행에서 열 평균 빼기" 같은 연산을 한 줄로 쓸 수 있습니다. 정규화·표준화가 전부 이 원리 위에 있습니다.
import numpy as np두 배열의 shape를 마지막 축부터 앞으로 하나씩 비교합니다. 각 축 쌍이 다음 중 하나면 "호환"입니다:
ValueError입니다. A shape B shape 결과 판정
(3, 4) (4,) (3, 4) OK (4==4; 3은 B에 없음→1로 간주)
(3, 4) (3, 1) (3, 4) OK (4 vs 1 → 4로 확장)
(3, 1) (1, 4) (3, 4) OK (양쪽 다 확장)
(3, 4) (3,) ERROR (뒤 정렬: 4 vs 3 불일치)
(2, 3, 4) (3, 1) (2, 3, 4) OK직관: shape를 오른쪽 끝에 맞춰 세로로 적으십시오. 각 자리에서 숫자가 같거나, 한쪽이 1이거나, 비어 있으면 통과합니다.
a = np.arange(6).reshape(2, 3)
# [[0 1 2]
# [3 4 5]]
a + 10 # 모든 원소에 10 (스칼라 → (2,3)로 확장)
a + np.array([100, 200, 300]) # (3,) → 각 "행"에 [100,200,300] 더함
# [[100 201 302]
# [103 204 305]]
a + np.array([[10], [20]]) # (2,1) → 각 "열"에 [10],[20] 더함
# [[10 11 12]
# [23 24 25]]패턴 기억: (N,) 벡터는 각 행에 더해지고, (N, 1) 벡터는 각 열에 더해집니다.
💡 이럴 때: 특징별 상수(열 평균, 클래스 가중치)를 전체 행렬에 더하거나 뺄 때 벡터 shape로 방향을 정합니다.
x = np.array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
col_mean = x.mean(axis=0) # (3,) - 열별 평균 [4, 5, 6]
col_std = x.std(axis=0) # (3,) - 열별 표준편차
x_std = (x - col_mean) / col_std
# (3,3) - (3,) - (3,) → 각 열에서 그 열의 평균/표준편차 적용x의 shape가 (3, 3), col_mean이 (3,)입니다. 뒤 정렬하면 3 vs 3 통과, 앞 축은 col_mean에 없으니 3으로 확장되어 각 행에 대해 동일한 열 통계가 적용됩니다.
💡 이럴 때: 스케일에 민감한 선형모델·신경망·거리 기반 알고리즘의 입력을 열별로 표준화할 때의 표준 패턴입니다.
row = np.array([1, 2, 3]) # (3,)
col = np.array([10, 20]) # (2,)
col[:, None] * row[None, :] # (2,1) * (1,3) → (2,3)
# [[10 20 30]
# [20 40 60]]ValueError: operands could not be broadcast together with shapes (3,4) (3,)(3, 4) vs (_, 3). 마지막 축 4 vs 3 → 불일치입니다.(3,)을 (3, 1)로 바꿉니다: b[:, None].a = np.arange(12).reshape(3, 4)
b = np.array([10, 20, 30]) # (3,)
a - b # ValueError
a - b[:, None] # OK - (3,4) - (3,1) → 각 행에서 해당 스칼라 빼기💡 이럴 때: "각 행에서 행별 스칼라 하나를 빼기"가 필요한데 broadcast 에러가 나면
[:, None]으로 축을 세웁니다.
브로드캐스팅 자체는 메모리를 늘리지 않습니다. 하지만 연산 결과는 확장된 최종 shape 크기의 새 배열입니다. (10000, 10000) + (10000,)의 결과는 1억 원소짜리 배열이 새로 생깁니다. 큰 배열끼리 브로드캐스팅할 때 메모리 사용량을 염두에 둡니다.
댓글
GitHub 계정으로 의견이나 질문을 남길 수 있습니다.