[Python.NumPy] Array 간의 연산과 Broadcasting
2020. 12. 10. 05:00ㆍPython과 머신러닝/NumPy 데이터 분석
0. 요약
- Array 간의 연산을 수행할 때, 두 Array의 크기가 같은 경우에는 어떻게 연산이 될까?
- 그렇다면 크기가 다를 경우에는 어떻게 될까?
- Array에 Scalar값이나 vector를 더하려고 해도 정상적으로 수행될까? 그렇다면 어떤 결과가 나올까?
- 이를 이해하기 위해서는 Broadcasting이라는 개념을 이해해야 하는데, 자세히 하나씩 정리해보자.
1. Array와 Array 간의 연산
In [1]:import numpy as np
In [2]:test_a = np.array([[1,2,3],
[4,5,6]],
float)
test_a
Out[2]:array([[1., 2., 3.],
[4., 5., 6.]])
In [3]:test_a + test_a
Out[3]:array([[ 2., 4., 6.],
[ 8., 10., 12.]])
In [4]:test_a - test_a
Out[4]:array([[0., 0., 0.],
[0., 0., 0.]])
- 같은 크기의 array 간 연산을 하면 행렬의 연산과 동일하게 각 요소들 간의 연산이 수행된다.
2. Transpose와 Dot Product
In [5]:test_a = np.arange(1,7).reshape(2,3)
test_a
Out[5]:array([[1, 2, 3],
[4, 5, 6]])
In [6]:test_b = np.arange(7,13).reshape(3,2)
test_b
Out[6]:array([[ 7, 8],
[ 9, 10],
[11, 12]])
In [7]:test_a.dot(test_b)
Out[7]:array([[ 58, 64],
[139, 154]])
In [8]:test_a.transpose()
Out[8]:array([[1, 4],
[2, 5],
[3, 6]])
In [9]:test_a.T
Out[9]:array([[1, 4],
[2, 5],
[3, 6]])
In [10]:test_a.T.dot(test_a)
Out[10]:array([[17, 22, 27],
[22, 29, 36],
[27, 36, 45]])
- .transpose 혹은 .T 연산자를 사용해서 행렬을 transpose 할 수 있다.
- .dot 함수를 사용해서 두 개의 ndarray를 곱할 수도 있다.
- test_a.T.dot(test_a)는 test_a를 Transpose 한 결과값에 test_a함수를 곱한 것이다.
3. Array와 Scalar 간의 연산
In [11]:test_c = np.array([[1,2,3], [4,5,6]], float)
test_c
Out[11]:array([[1., 2., 3.],
[4., 5., 6.]])
In [12]:scalar = 3
In [13]:test_c + scalar
Out[13]:array([[4., 5., 6.],
[7., 8., 9.]])
- array와 scalar를 더하면 각 요소에 scalar를 더한 것과 동일한 연산을 수행한다.
- 이러한 동작을 broadcasting이라고 한다.
- 3이라는 scalar 값이 [[3., 3., 3.], [3., 3., 3.]] 배열로 확장되어 연산된다.
- broadcasting의 정의는 '같은 shape으로 복사/확장'이다.
4. Array와 vector 간의 연산
In [14]:test_d = np.arange(1,13).reshape(4,3)
test_d
Out[14]:array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
In [15]:vector = np.arange(10, 40, 10)
vector
Out[15]:array([10, 20, 30])
In [16]:test_d + vector
Out[16]:array([[11, 22, 33],
[14, 25, 36],
[17, 28, 39],
[20, 31, 42]])
- vector와의 연산에서도 동일하게 broadcasting이 일어난다.
- 수식으로 보면 4x3 matrix + 1x3 vector를 더하는 것 같지만,
- 실제 연산 시에는 1x3 vector가 4x3 matrix로 broadcasting 되어 ([[10,20,30], [10,20,30], [10,20,30], [10,20,30]])
test_d matrix와 합쳐지기 때문에 Out[16]과 같은 결과가 나온다.
5. Vector와 vector 간의 연산
In [17]:vector_transpose = vector.reshape(-1,3).T vector_transpose
Out[17]:array([[10],
[20],
[30]])
In [18]:vector + vector_transpose
Out[18]:array([[20, 30, 40],
[30, 40, 50],
[40, 50, 60]])
- 그렇다면 크기가 다른 vector 간의 연산은 어떻게 될까?
- 양쪽 다 broadcasting이 일어난 뒤에 연산이 수행된다.
- [10,20,30] (1x3 vector)와 [[10],[20],[30]] (3x1 vector) 두 개의 vector를 더하는 연산의 예시를 보자
- 첫 vector는 [[10,20,30], [10,20,30], [10,20,30]] 로 broadcasting이 되고
- 둘째 vector는 [[10,10,10], [20,20,20], [30,30,30]]로 broadcasting이 된다.
- Broadcasting이 된 이후의 연산은 각 요소별로 이루어지기 때문에, Out[18]과 같은 결과가 나오게 된다.
6. 마무리
- 같은 크기의 Array 간의 연산은 각 요소별로 이루어진다.
- 크기가 다른 Scalar나 Vector를 Array와 연산하기 위해서는 Scalar/Vector를 Array와 같은 크기로 확장시켜주는 동작이 선행되는데, 이를 Broadcasting이라고 한다.
- 즉 Array + Scalar 혹은 Array + Vector를 수행하면 Scalar/Vector를 Array로 확장을 시킨 뒤에 각 요소별로 연산을 수행하게 된다.