[Python.NumPy] Array 간의 연산과 Broadcasting

2020. 12. 10. 05:00Python과 머신러닝/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로 확장을 시킨 뒤에 각 요소별로 연산을 수행하게 된다.
반응형