소개
브로드캐스팅 (Broadcasting) 은 NumPy 의 기본 개념으로, 서로 다른 모양 (shape) 을 가진 배열 간의 요소별 (element-wise) 산술 연산을 가능하게 합니다. 이 강력한 기능은 명시적인 루프 (loop) 의 필요성을 없애주어 더 간결하고 계산 효율적인 코드를 작성할 수 있게 합니다. 본 실습에서는 브로드캐스팅 규칙을 배우고, Python 스크립트를 작성하고 실행하여 실제 예시에 적용해 볼 것입니다.
브로드캐스팅 (Broadcasting) 은 NumPy 의 기본 개념으로, 서로 다른 모양 (shape) 을 가진 배열 간의 요소별 (element-wise) 산술 연산을 가능하게 합니다. 이 강력한 기능은 명시적인 루프 (loop) 의 필요성을 없애주어 더 간결하고 계산 효율적인 코드를 작성할 수 있게 합니다. 본 실습에서는 브로드캐스팅 규칙을 배우고, Python 스크립트를 작성하고 실행하여 실제 예시에 적용해 볼 것입니다.
브로드캐스팅의 가장 간단한 형태는 배열과 단일 숫자 (스칼라) 간의 연산을 수행할 때 발생합니다. NumPy 는 자동으로 스칼라를 배열의 모양에 맞게 "늘리거나" "브로드캐스팅"합니다.
먼저 화면 왼쪽 파일 탐색기에서 broadcasting.py 파일을 찾으십시오. 해당 파일을 더블 클릭하여 편집기에서 엽니다.
이제 broadcasting.py의 내용을 다음 코드로 바꾸십시오. 이 코드는 1 차원 NumPy 배열을 생성하고 스칼라 값으로 곱합니다.
import numpy as np
## 1 차원 배열 생성
a = np.array([1.0, 2.0, 3.0])
## 스칼라 정의
b = 2.0
## 배열에 스칼라 곱하기
## 스칼라 'b'가 'a'의 모양으로 브로드캐스팅됩니다.
result = a * b
print("배열 'a':", a)
print("스칼라 'b':", b)
print("a * b 결과:", result)
결과를 보려면 스크립트를 실행해야 합니다. 화면 하단의 터미널 패널에 있는 + 아이콘을 클릭하고 Terminal을 선택하여 터미널을 엽니다. 그런 다음 다음 명령을 실행하십시오.
python broadcasting.py
배열 a의 각 요소가 2.0으로 곱해진 다음 출력을 볼 수 있습니다.
Array 'a': [1. 2. 3.]
Scalar 'b': 2.0
Result of a * b: [2. 4. 6.]
두 배열의 모양이 호환될 때도 브로드캐스팅이 작동합니다. 호환성을 위한 일반적인 규칙은 다음과 같습니다. 두 배열의 차원을 오른쪽에서 왼쪽으로 비교할 때, 각 차원 쌍은 같거나 둘 중 하나는 1 이어야 합니다.
1 차원 배열을 2 차원 배열에 더하는 예시를 살펴보겠습니다. 1 차원 배열은 2 차원 배열의 각 행에 브로드캐스팅됩니다.
broadcasting.py 파일을 다음 코드로 업데이트하십시오.
import numpy as np
## 2 차원 배열 생성 (모양: 2, 3)
a = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
## 1 차원 배열 생성 (모양: 3,)
b = np.array([10.0, 20.0, 30.0])
## 두 배열 더하기
## 'b'는 'a'와 일치하도록 모양 (2, 3) 으로 브로드캐스팅됩니다.
## 내부적으로 [[10. 20. 30.], [10. 20. 30.]] 이 됩니다.
result = a + b
print("배열 'a' (모양 {}):\n{}".format(a.shape, a))
print("배열 'b' (모양 {}): {}".format(b.shape, b))
print("a + b 결과:\n", result)
터미널에서 스크립트를 다시 실행하십시오.
python broadcasting.py
출력은 1 차원 배열 b가 2 차원 배열 a의 각 행에 더해졌음을 보여줍니다.
Array 'a' (shape (2, 3)):
[[1. 2. 3.]
[4. 5. 6.]]
Array 'b' (shape (3,)): [10. 20. 30.]
Result of a + b:
[[11. 22. 33.]
[14. 25. 36.]]
배열의 모양이 규칙에 따라 호환되지 않으면 브로드캐스팅이 실패합니다. 이로 인해 ValueError가 발생합니다. 언제 이런 일이 발생하는지 이해하는 것은 디버깅에 매우 중요합니다.
호환되지 않는 모양으로 연산을 시도해 보겠습니다. 여기서는 모양이 (2, 3)인 배열과 모양이 (2,)인 배열을 더하려고 시도할 것입니다. NumPy 는 마지막 차원 (3과 2) 을 비교하고, 같지 않으며 둘 다 1 이 아님을 발견합니다. 이로 인해 오류가 발생합니다.
broadcasting.py 파일을 다음 코드를 포함하도록 수정하십시오.
import numpy as np
## 2 차원 배열 생성 (모양: 2, 3)
a = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
## 호환되지 않는 1 차원 배열 생성 (모양: 2,)
b = np.array([1.0, 2.0])
print("배열 'a' (모양 {}):\n{}".format(a.shape, a))
print("배열 'b' (모양 {}): {}".format(b.shape, b))
## ValueError 발생
try:
result = a + b
except ValueError as e:
print("\n오류:", e)
터미널에서 스크립트를 실행하십시오.
python broadcasting.py
예상대로 프로그램은 ValueError를 잡고 모양이 정렬되지 않았다는 오류 메시지를 출력합니다. 이는 호환되지 않는 모양에 대한 올바르고 예상된 동작입니다.
Array 'a' (shape (2, 3)):
[[1. 2. 3.]
[4. 5. 6.]]
Array 'b' (shape (2,)): [1. 2.]
Error: operands could not be broadcast together with shapes (2,3) (2,)
브로드캐스팅을 실용적인 문제에 적용해 보겠습니다. 벡터 양자화 (Vector Quantization, VQ) 는 데이터 압축 및 분류에 사용되는 기법입니다. 핵심 단계는 주어진 "관측치" 벡터에 대해 "코드북"에서 가장 가까운 "코드" 벡터를 찾는 것입니다. 브로드캐스팅은 이 계산을 효율적으로 만듭니다.
관측치 (예: 운동선수의 체중과 키) 와 다양한 운동선수 유형의 코드북이 있다고 상상해 봅시다. 우리의 관측치가 어떤 유형에 가장 가까운지 찾고 싶습니다.
broadcasting.py의 코드를 다음으로 바꾸십시오.
import numpy as np
## 관측치 벡터 (예: 체중, 키)
observation = np.array([111.0, 188.0])
## 벡터 코드북
codes = np.array([[102.0, 203.0],
[132.0, 193.0],
[45.0, 155.0],
[57.0, 173.0]])
## 브로드캐스팅을 사용하여 관측치를 모든 코드에서 한 번에 빼기
## observation (2,) 는 (4, 2) 로 브로드캐스팅됩니다.
diff = codes - observation
## 제곱 유클리드 거리 계산
dist_sq = np.sum(diff**2, axis=-1)
## 최소 거리의 인덱스 찾기
closest_index = np.argmin(dist_sq)
## 가장 가까운 코드 가져오기
closest_code = codes[closest_index]
print("Observation:", observation)
print("Codebook:\n", codes)
print("Distances squared:", dist_sq)
print("Closest code index:", closest_index)
print("Closest code:", closest_code)
터미널에서 스크립트를 실행하십시오.
python broadcasting.py
출력은 관측치와 각 코드 간의 제곱 거리를 보여주고 가장 가까운 일치하는 코드 벡터를 식별합니다. 브로드캐스팅 덕분에 이 모든 계산이 명시적인 Python 루프 없이 수행되었습니다.
Observation: [111. 188.]
Codebook:
[[102. 203.]
[132. 193.]
[ 45. 155.]
[ 57. 173.]]
Distances squared: [ 306. 466. 5445. 3141.]
Closest code index: 0
Closest code: [102. 203.]
이 실습에서는 NumPy 브로드캐스팅의 기본 사항을 배웠습니다. 스칼라를 배열로 브로드캐스팅하는 간단한 경우부터 시작하여, 호환되는 두 배열 간의 브로드캐스팅으로 진행했으며, 오류를 발생시키는 호환되지 않는 모양을 인식하는 방법을 배웠습니다. 마지막으로 브로드캐스팅을 실제 벡터 양자화 문제에 적용하여, 수치 계산을 위한 깔끔하고 효율적이며 루프가 없는 코드를 작성하는 강력함을 보여주었습니다. 브로드캐스팅을 마스터하는 것은 효과적이고 전문적인 NumPy 코드를 작성하기 위한 핵심 단계입니다.