EDA with Python - NumPy Broadcasting
강의 홍보
- 취준생을 위한 강의를 제작하였습니다.
- 본 블로그를 통해서 강의를 수강하신 분은 게시글 제목과 링크를 수강하여 인프런 메시지를 통해 보내주시기를 바랍니다.
스타벅스 아이스 아메리카노를 선물로 보내드리겠습니다.
- [비전공자 대환영] 제로베이스도 쉽게 입문하는 파이썬 데이터 분석 - 캐글입문기

공지
제 수업을 듣는 사람들이 계속적으로 실습할 수 있도록 강의 파일을 만들었습니다. 늘 도움이 되기를 바라며. 참고했던 교재 및 Reference는 꼭 확인하셔서 교재 구매 또는 관련 Reference를 확인하시기를 바랍니다.

I. 개요
NumPy는 C언어로 구성되었으며, 고성능의 수치계산을 위해 나온 패키지이며,Numerical Python의 약자이다.Python을 활용한 데이터 분석을 수행할 때, 그리고 데이터 시각화나 전처리를 수행할 때,NumPy는 매우 자주 사용되기 때문에 한번쯤은 꼭 다듬고 가는 것이 중요하다.- 이전 포스트에서는 Python - NumPy 소개 및 다양한 객체 생성에 대해 다루었으니, 본 포스트 읽기에 앞서서 기본적인 개념에 대해 확인하기를 바란다.
II. 모듈 Import
- 패키지 설치방법은 설치 문서를 확인한다.
import numpy as np
print(np.__version__)
1.18.4
III. NumPy 기본 활용법
- NumPy 객체 생성을 한 뒤에, 파일 저장, 서로 다른 배열끼리의 사칙연산 등을 수행할 수 있다.
(1) NumPy 객체 파일 저장 및 불러오기
savetxt,loadtxt, 그리고genfromtxt함수를 활용하여 객체를 불러오는 예제를 실습한다.
# 객체 생성 후 저장하기
x = np.arange(0.0, 50.0, 1.0)
print(x)
np.savetxt('data.out', x, delimiter=',')
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35.
36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49.]
!ls
data.out sample_data
- 현재 폴더에
data.out파일이 생성된 것을 확인할 수 있다.
# `data.out` 불러오기
z = np.loadtxt('data.out', unpack=True)
print(z)
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35.
36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49.]
- 정상적으로
data.out을 불러와서z객체에 저장된 것을 확인할 수 있다.
# genfromtxt 활용
my_array2 = np.genfromtxt('data.out',
skip_header=1,
filling_values=-999)
print(my_array2)
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49.]
-
z객체와 마찬가지로my_array2도 객체가 정상적으로 생성된 것을 확인할 수 있다. -
loadtxt와genfromtxt의 차이점이 있기는 하다. 결론부터 말하면,genfromtxt가 다양한 옵션을 제공한다. 간단한 예를 들면,genfromtxt의 경우 열들의 자료형을 자동으로 결정해주어 사용자들이 좀 더 편안하게 사용할 수 있도록 도와준다 (Clinton, 2016, p. 281-2).
(2) 2차원 배열 Inspection
ndim,size,flags,itemsize,nbytes를 활용하여 배열의 정보를 획득한다.- 특히, 딥러닝 모형 정의 및 학습할 때, NumPy 배열 에러 등이 종종 발생하기 때문에 기본 개념은 학습하는 것을 추천한다.
my2D_Array = np.array([[1,2,3,4], [2,4,6,8], [3,6,9,12]])
print(my2D_Array)
[[ 1 2 3 4]
[ 2 4 6 8]
[ 3 6 9 12]]
# ndim
print(my2D_Array.ndim)
2
# size (각 item의 개수를 의미)
print(my2D_Array.size)
12
# 2차원 배열의 memory layout 확인
print(my2D_Array.flags)
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
# 1차원의 길이 in bytes (예. 숫자는 2bytes)
print(my2D_Array.itemsize)
8
# 전체 bytes
print(my2D_Array.nbytes)
96
IV. Broadcasting(=브로드 캐스팅)

- 개념 설명은 다음과 같다.
Broadcasting is a mechanism that permits NumPy to operate with arrays of different shapes when performing arithmetic operations:
간단하게 해석하면 브로드캐스팅(Broadcasting)은 모양이 다른 배열들 간의 사칙연산도 가능하게끔 도와주는 일종의 mechanism이다. 그런데, 여기에는 기본적인 Rule이 있다.
(1) Rule 1. Eqaul Dimensions between A and B
- 우선 모양이 같은
A와BNumPy 객체를 생성한다. - A + B를 연산하여 출력한다.
# A 객체
A = np.ones((5,3))
print(A)
print(A.shape)
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
(5, 3)
# B 객체
B = np.random.random((5,3))
print(B)
print(B.shape)
[[0.13526155 0.07276429 0.25635867]
[0.74909147 0.09515243 0.20379472]
[0.33115034 0.13771662 0.61417221]
[0.79164803 0.72754531 0.29071265]
[0.36780642 0.50456743 0.19266307]]
(5, 3)
print(A+B)
[[1.13526155 1.07276429 1.25635867]
[1.74909147 1.09515243 1.20379472]
[1.33115034 1.13771662 1.61417221]
[1.79164803 1.72754531 1.29071265]
[1.36780642 1.50456743 1.19266307]]
- 정상적으로 덧셈이 연산된 것을 확인할 수 있다.
(2) Rule 2. Compatible Dimensions when one of them is 1
- 이번에는 X와 Y 객체를 생성하고
shape를 통해 차원이 어떻게 다른지 확인한다.
x = np.ones((3,4))
print(x)
print(x.shape)
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
(3, 4)
y = np.arange(4)
print(y)
print(y.shape)
[0 1 2 3]
(4,)
# 뺄셈 연산 수행 (x-y)
print(x-y)
[[ 1. 0. -1. -2.]
[ 1. 0. -1. -2.]
[ 1. 0. -1. -2.]]
- 위 코드에서 중요한 것은 숫자
4이다. 즉, 1차원 길이가 다르면 연산은 에러가 발생한다. y의 숫자4대신5를 대입해서 적용해보자.
x = np.ones((3,4))
y = np.arange(5)
print(x-y)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-33-d91ef8252b95> in <module>()
1 x = np.ones((3,4))
2 y = np.arange(5)
----> 3 print(x-y)
ValueError: operands could not be broadcast together with shapes (3,4) (5,)
- 위 에러 문구(
operands could not be broadcast together with shapes (3,4) (5,))에서 확인 할 수 있는 것처럼 1차원 길이가 다르면 에러가 발생한다.
(3) Rule 3. Compatitble in all of the dimensions
- 이번에는 서로 다른 모양의 객체를 확인한다.
- 그리고 덧셈을 수행해보자.
x = np.ones((6,5))
print(x)
print(x.shape)
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
(6, 5)
y = np.random.random((3, 1, 5))
print(y)
print(y.shape)
[[[0.68586586 0.9179277 0.88033036 0.6306833 0.17327179]]
[[0.21184583 0.28629664 0.00532677 0.49662726 0.73354008]]
[[0.82677113 0.49873148 0.56901096 0.82320785 0.04587492]]]
(3, 1, 5)
print(x+y)
[[[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]
[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]
[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]
[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]
[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]
[1.68586586 1.9179277 1.88033036 1.6306833 1.17327179]]
[[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]
[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]
[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]
[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]
[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]
[1.21184583 1.28629664 1.00532677 1.49662726 1.73354008]]
[[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]
[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]
[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]
[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]
[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]
[1.82677113 1.49873148 1.56901096 1.82320785 1.04587492]]]
- 만약에 여기에서
y값을(3,2,5)또는(3,1,6)으로 바꾸면 어떻게 될까?
y = np.random.random((3, 2, 5))
print(y)
print(y.shape)
[[[0.95042186 0.52979398 0.30549682 0.93579665 0.03784094]
[0.27023327 0.19952522 0.68376492 0.11982131 0.45394735]]
[[0.69797278 0.85359121 0.01493669 0.06111047 0.25285451]
[0.57293653 0.28453573 0.18296577 0.12696192 0.28530794]]
[[0.75410798 0.88487199 0.78635143 0.05059668 0.48753369]
[0.65395856 0.74907103 0.47013049 0.14938089 0.36961655]]]
(3, 2, 5)
print(x+y)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-43-39cb3db33052> in <module>()
----> 1 print(x+y)
ValueError: operands could not be broadcast together with shapes (6,5) (3,2,5)
- 에러가 나는 것을 확인할 수 있다.
- 왜 에러가 날까?
x의 2차원 배열의 숫자가 앞에 6으로 되어 있기 때문이다. y값은 그대로 놔둔채, x의 값6대신2로 바꿔주고 덧셈을 하면 성공적으로 연산이 수행됨을 알 수 있다.
x = np.ones((2,5))
print(x)
print(x.shape)
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
(2, 5)
print(x+y)
[[[1.95042186 1.52979398 1.30549682 1.93579665 1.03784094]
[1.27023327 1.19952522 1.68376492 1.11982131 1.45394735]]
[[1.69797278 1.85359121 1.01493669 1.06111047 1.25285451]
[1.57293653 1.28453573 1.18296577 1.12696192 1.28530794]]
[[1.75410798 1.88487199 1.78635143 1.05059668 1.48753369]
[1.65395856 1.74907103 1.47013049 1.14938089 1.36961655]]]
V. 결론
- 머신러닝 & 딥러닝을 수행할 때,
NumPy을 활용한 객체 생성은 매우 빈번하다. - 대부분은 서로 다른 차원으로 인해 연산 오류가 자주 발생하는데, 이 때
Broadcasting의 개념을 알고 있으면 연산 오류를 줄일 수 있다.
Reference
Brownley, Clinton W. Foundations for Analytics with Python. O’Reilly Media, Inc., 2016.
Mukhiya, Suresh Kumar, and Usman Ahmed. “Hands-On Exploratory Data Analysis with Python.” Packt Publishing, Mar. 2020, www.packtpub.com/data/hands-on-exploratory-data-analysis-with-python.