지난번 포스팅에서는 다차원 행렬 ndarray에 축을 추가하는 방법으로 arr(:, np.newaxis, :), np.tile() 을 소개했었습니다.

 

이번 포스팅에서는 행렬의 행과 열을 바꾸기, 행렬의 축을 바꾸는 방법을 알아보겠습니다.  선형대수에서 보면 '전치행렬(transpose matrix)'이라는 특수한 형태의 행렬이 있는데요, 이번 포스팅이 바로 그겁니다. 행렬의 내적(inner product) 구할 때 aT*a 처럼 전치행렬과 원래 행렬을 곱할 때 전치행렬(aT)를 씁니다.

 

 

Python의 NumPy 로 부터 행렬 전치를 위해

 

 - a.T attribute

 - np.transpose(a) method

 - np.swapaxes(a, 0, 1) method

 

의 3가지 방법을 사용할 수 있습니다.

 

 

 

a.T attrbute, np.transpose() method, np.swapaxes() method 각각에 대해 2차원 행렬을 전치하는 단한 예를 들어보겠습니다.

 

 

  (1-1) Transposing 2 D array : a.T attribute

 

 

In [1]: import numpy as np


In [2]: a = np.arange(15).reshape(3, 5)


In [3]: a

Out[3]:

array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]])

 

# (1-1) transposing 2D array : T attribute

In [4]: a.T

Out[4]:

array([[ 0,  5, 10],
        [ 1,  6, 11],
        [ 2,  7, 12],
        [ 3,  8, 13],
        [ 4,  9, 14]])

 

 

 

 

  (1-2) Transposing 2D array : np.transpose() method

 

 

In [5]: a

Out[5]:

array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]])

 

# (1-2) transpose method : numpy.transpose(a, axes=None)

In [6]: np.transpose(a)

Out[6]:

array([[ 0,  5, 10],
        [ 1,  6, 11],
        [ 2,  7, 12],
        [ 3,  8, 13],
        [ 4,  9, 14]])

 

 

 

 

  (1-3) Transposing 2D array : np.swapaxes() method

 

 

In [7]: a

Out[7]:

array([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]])

 

# (1-3) swapaxes method : numpy.swapaxes(a, axis1, axis2)

In [8]: np.swapaxes(a, 0, 1)

Out[8]:

array([[ 0,  5, 10],
        [ 1,  6, 11],
        [ 2,  7, 12],
        [ 3,  8, 13],
        [ 4,  9, 14]])

 

 

 

 

이쯤에서 NumPy의 np.dot() 으로 행렬 내적 (inner product, aT*a) 계산해볼까요?

 

 

In [9]: np.dot(a.T, a)

Out[9]:

array([[125, 140, 155, 170, 185],
        [140, 158, 176, 194, 212],
        [155, 176, 197, 218, 239],
        [170, 194, 218, 242, 266],
        [185, 212, 239, 266, 293]])


In [10]: np.dot(np.transpose(a), a)

Out[10]:

array([[125, 140, 155, 170, 185],
        [140, 158, 176, 194, 212],
        [155, 176, 197, 218, 239],
        [170, 194, 218, 242, 266],
        [185, 212, 239, 266, 293]])


In [11]: np.dot(np.swapaxes(a, 0, 1), a)

Out[11]:

array([[125, 140, 155, 170, 185],
        [140, 158, 176, 194, 212],
        [155, 176, 197, 218, 239],
        [170, 194, 218, 242, 266],
        [185, 212, 239, 266, 293]])

 

 

 

 

2차원 행렬로 전치에 대한 맛을 봤으니, 이제 3차원 행렬의 축을 바꿔보는 것으로 난이도를 높여보겠습니다.  np.transpose() 와 np.swapaxes() method는 전치시키려고 하는 축을 입력해줘야 하는데요, 조금 조심해서 사용해야 합니다.

 

  (2-1) Transposing 3D array : a.T attribute

 

 

In [12]: b = np.arange(24).reshape(2, 3, 4)


In [13]: b

Out[13]:

array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],

        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]])


In [14]: b.T

Out[14]:

array([[[ 0, 12],
         [ 4, 16],
         [ 8, 20]],

        [[ 1, 13],
         [ 5, 17],
         [ 9, 21]],

        [[ 2, 14],
         [ 6, 18],
         [10, 22]],

        [[ 3, 15],
         [ 7, 19],
         [11, 23]]])

 

In [15]: b.T.shape

Out[15]: (4, 3, 2)

 

 

 

 

  (2-2) Transposing 3D array : np.transpose() method

 

np.transpose() method는 축을 바꾸고 싶은 위치, 순서를 분석가가 마음대로 지정할 수 있다는 측면에서 T attribute 보다 자유도가 높습니다. (처음엔 좀 헷갈리고 이해가 잘 안가는 면도 있지만요)

 

 

# shape (2, 3, 4)

In [16]: b

Out[16]:

array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],

        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]])

 

 

# shape(2, 3, 4) => shape (4, 3, 2)

 

In [17]: np.transpose(b)

Out[17]:

array([[[ 0, 12],
         [ 4, 16],
         [ 8, 20]],

        [[ 1, 13],
         [ 5, 17],
         [ 9, 21]],

        [[ 2, 14],
         [ 6, 18],
         [10, 22]],

        [[ 3, 15],
         [ 7, 19],
         [11, 23]]])

 

 

# shape(2, 3, 4) => shape (4, 3, 2)

 

In [18]: np.transpose(b, (2, 1, 0))

Out[18]:

array([[[ 0, 12],
         [ 4, 16],
         [ 8, 20]],

        [[ 1, 13],
         [ 5, 17],
         [ 9, 21]],

        [[ 2, 14],
         [ 6, 18],
         [10, 22]],

        [[ 3, 15],
         [ 7, 19],
         [11, 23]]])


In [19]: b.shape

Out[19]: (2, 3, 4)


In [20]: np.transpose(b).shape

Out[20]: (4, 3, 2)

 

 

 

 

  (2-3) Transposing 3D array : np.swapaxes() method

 

 

In [21]: b

Out[21]:

array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],

        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]])


In [22]: b.shape

Out[22]: (2, 3, 4)

 


# shape(2, 3, 4) => shape(4, 3, 2)

 

In [23]: np.swapaxes(b, 0, 2)

Out[23]:

array([[[ 0, 12],
         [ 4, 16],
         [ 8, 20]],

        [[ 1, 13],
         [ 5, 17],
         [ 9, 21]],

        [[ 2, 14],
         [ 6, 18],
         [10, 22]],

        [[ 3, 15],
         [ 7, 19],
         [11, 23]]])

 

In [24]: np.swapaxes(b, 0, 2).shape

Out[24]: (4, 3, 2)

 

 

 

 

np.transpose() 와 np.swapaxes() method를 사용해서 전치시키려는 축의 순서를 위의 예시와는 조금 다르게 바꿔서 해보겠습니다. 축(axes)의 순서를 바꿔서 입력해주면 됩니다. (말로 설명하기 좀 어려운데요, 아래 예와 위의 예를 유심히 살펴보시기 바랍니다)

 

 

In [25]: b

Out[25]:

array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],

        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]])


In [26]: b.shape

Out[26]: (2, 3, 4)

 

 

# shape(2, 3, 4) => shape(3, 2, 4)

In [27]: np.transpose(b, (1, 0, 2)).shape

Out[27]: (3, 2, 4)


In [28]: np.transpose(b, (1, 0, 2))

Out[28]:

ararray([[[ 0,  1,  2,  3],
           [12, 13, 14, 15]],

          [[ 4,  5,  6,  7],
           [16, 17, 18, 19]],

          [[ 8,  9, 10, 11],
           [20, 21, 22, 23]]])

 

 

 

 

위의 [28]번 np.transpose(b, (1, 0, 2)) 와 똑같은 결과를 얻을 수 있는 방법으로 np.swapaxes(b, 1, 0)을 사용하면 됩니다.

 

 

In [29]: b

Out[29]:

array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],

        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]])


In [30]: b.shape

Out[30]: (2, 3, 4)


In [31]: np.swapaxes(b, 1, 0).shape

Out[31]: (3, 2, 4)


In [32]: np.swapaxes(b, 1, 0)

Out[32]:

ararray([[[ 0,  1,  2,  3],
           [12, 13, 14, 15]],

          [[ 4,  5,  6,  7],
           [16, 17, 18, 19]],

          [[ 8,  9, 10, 11],
           [20, 21, 22, 23]]])

 

 

 

많은 도움 되었기를 바랍니다.

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

지난번 포스팅에서 Broadcasting을 다루어보았는데요, 이번 포스팅에서는 Broadcasting 과 관련이 있는 NumPy Array에 새로운 축 추가하는 2가지 방법을 소개해보겠습니다.

 

하나는 np.newaxis attribute 이고, 또 하나는 np.tile() method 인데요, 사용법이나 결과가 조금 다르니 데이터 처리 용도나 목적에 맞게 골라서 사용하시면 되겠습니다.

 

(1) indexing으로 길이가 1인 새로운 축을 추가하기

   : arr(:, np.newaxis, :)

 

(2) 배열을 반복하면서 새로운 축을 추가하기

   : np.tile(arr, reps)

 

 

 

 

 

  (1) indexing으로 길이가 1인 새로운 축을 추가하기 : arr(:, np.newaxis, :)

 

먼저 NumPy 모듈을 불러어고, 예제 array 를 만들어보겠습니다.

 

 

In [1]: import numpy as np


In [2]: a = np.array([1., 2., 3., 4.])


In [3]: a

Out[3]: array([ 1., 2., 3., 4.])


In [4]: a.shape

Out[4]: (4,)

 

 

 

np.newaxis attribute를 사용해서 길이가 1인 새로운 축을 하나 추가해보겠습니다.

 

 

# (1) np.newaxis : adding and inserting new axis  with length 1 by indexing

 

In [5]: a_4_1 = a[:, np.newaxis]


In [6]: a_4_1

Out[6]:

array([[ 1.],
       [ 2.],
       [ 3.],
       [ 4.]])


In [7]: a_4_1.shape

Out[7]: (4, 1)

 

 

 

 

이번에는 shape(3, 4) 인 2차원의 배열에 길이가 1인 새로운 축을 추가해서 3차원 배열을 만들어보겠습니다.  ':'를 사용해서 기존 배열의 값을 indexing 하구요, np.newaxis attribute로 새로운 축을 추가하게 됩니다.

 

 


In [8]: b = np.arange(12).reshape(3, 4)


In [9]: b

Out[9]:

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])


In [10]: b.shape

Out[10]: (3, 4)

 


# shape(3, 4, 1)

In [11]: b_3_4_1 = b[ :, :, np.newaxis]


In [12]: b_3_4_1

Out[12]:

array([[[ 0],
         [ 1],
         [ 2],
         [ 3]],

        [[ 4],
         [ 5],
         [ 6],
         [ 7]],

        [[ 8],
         [ 9],
         [10],
         [11]]])


In [13]: b_3_4_1.shape

Out[13]: (3, 4, 1)

 


# shape(3, 1, 4)

In [14]: b_3_1_4 = b[ :, np.newaxis, : ]


In [15]: b_3_1_4

Out[15]:

array([[[ 0,  1,  2,  3]],

        [[ 4,  5,  6,  7]],

        [[ 8,  9, 10, 11]]])


In [16]: b_3_1_4.shape

Out[16]: (3, 1, 4) 

 

 

 

 

 

(2) 배열을 반복하면서 새로운 축을 추가하기 : np.tile(arr, reps)

 

np.tile(arr, reps) method 는 'arr' 에는 배열을, 'reps'에는 반복하고자 하는 회수를 넣어줍니다.

'reps'에는 숫자를 넣을 수도 있고, 배열을 넣을 수도 있습니다.

 

먼저 원소 4개짜리 배열을 가지고

 - 같은 차원으로 '2번' 반복하기 : reps = 2

 - '2차원'으로 '2번' 반복하기 : reps = (2, 2)

를 차례대로 해보겠습니다.

 

 

In [17]: A = np.array([0., 1., 2., 3.])


In [18]: A

Out[18]: array([ 0., 1., 2., 3.])


In [19]: A.shape

Out[19]: (4,)

 


# reps = 2

In [20]: A_8 = np.tile(A, 2)


In [21]: A_8

Out[21]: array([ 0., 1., 2., 3., 0., 1., 2., 3.])


In [22]: A_8.shape

Out[22]: (8,)

 


# reps = (2, 2)

In [23]: A_2_8 = np.tile(A, (2, 2))


In [24]: A_2_8

Out[24]:

array([[ 0.,  1.,  2.,  3.,  0.,  1.,  2.,  3.],
        [ 0.,  1.,  2.,  3.,  0.,  1.,  2.,  3.]])


In [25]: A_2_8.shape

Out[25]: (2, 8)

 

 

 

 

다음으로 2차원 배열에 np.tile() method를 사용해서

 - 배열을 반복하기

 - 배열을 반복하면서 차원을 하나 더 추가하기

를 해보겠습니다.

 

 

In [26]: B = np.arange(8).reshape(2, 4)


In [27]: B

Out[27]:

array([[0, 1, 2, 3],
        [4, 5, 6, 7]])


In [28]: B.shape

Out[28]: (2, 4)


In [29]: B_2_8 = np.tile(B, 2)


In [30]: B_2_8

Out[30]:

array([[0, 1, 2, 3, 0, 1, 2, 3],
        [4, 5, 6, 7, 4, 5, 6, 7]])


In [31]: B_2_8.shape

Out[31]: (2, 8)


In [32]: B_4_4 = np.tile(B, (2, 1))


In [33]: B_4_4

Out[33]:

array([[0, 1, 2, 3],
        [4, 5, 6, 7],
        [0, 1, 2, 3],
        [4, 5, 6, 7]
])


In [34]: B_4_4.shape

Out[34]: (4, 4)


In [35]: B_3_4_8 = np.tile(B, (3, 2, 2))


In [36]: B_3_4_8

Out[36]:

array([[[0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7],
         [0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7]],

        [[0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7],
         [0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7]],

        [[0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7],
         [0, 1, 2, 3, 0, 1, 2, 3],
         [4, 5, 6, 7, 4, 5, 6, 7]]]
)


In [37]: B_3_4_8.shape

Out[37]: (3, 4, 8)

 

 

 

많은 도움 되었기를 바랍니다.

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

지난번 포스팅에서는 같은 차원 크기의 배열 간 산술연산인 Vectorization 에 대해서 소개하였습니다.

 

이번 포스팅에서는 차원의 크기가 서로 다른 배열 간 산술연산 시의 Broadcasting 에 대해서 알아보겠습니다. (Braodcasting도 Vectorization 의 일부분 입니다. 사실, 지난번 vectorization에서 Scalar와의 연산 시 element-wise 연산 시 이미 Broadcasting을 맛보았었습니다. ㅎㅎ

 

Broadcasting이 서로 다른 모양, 크기이 배열 간 연산이다 보니 좀 헷갈릴 수도 있는데요, 알아두면 매우 편리하고 또 빠른 연산으로 유용합니다. 이해하기 쉽도록 Broadcasting 되는 모습을 이미지(점선 & 화살표)로 표현을 병행했습니다.

 

배열의 차원(Dimension)과 축(Axis) 별로 4가지 유형의 Broadcasting 을 차례대로 소개해보겠습니다.

 

 1) Broadcasting over axis 1 with a Scalar

 2) Broadcasting over axis 0 with a 1-D array

 3) Broadcasting over axis 1 with a 2-D array

 4) Broadcasting over axis 0 with a 3-D array

 

 

순서대로 예를 들어 살펴보겠습니다.

 

 1) Broadcasting over axis 1 with a Scalar 

 

먼저, 간단한 Scalar 부터 시작해보시지요.

 

 

 

# (1-1) Arithmetic operations between array and scalars
# : the scalar are broadcasted along the same dimensions of ndarray

 

In [1]: import numpy as np


In [2]: a_ar = np.array([1., 2., 3., 4.])


In [3]: a_ar.shape

Out[3]: (4,)


In [4]: a_ar + 1

Out[4]: array([ 2., 3., 4., 5.])

 

 

 

 

배열 뿐만 아니라 Pandas의 DataFrame 도 Scalar 산술 연산 시에 Broadcasting 이 적용됩니다.  간단한 예를 들어볼겠요.

 

 

# (1-2) Arithmetic operations between DataFrame and scalars
# : the scalar are broadcasted along the same dimensions of DataFrame

 

In [5]: import pandas as pd


In [6]: a_df = pd.DataFrame({'x1': [1, 2, 3, 4], 'x2': [5, 6, 7, 8]})


In [7]: a_df

Out[7]:

  x1 x2

0 1 5

1 2 6

2 3 7

3 4 8


In [8]: a_df + 1

Out[8]:

  x1 x2

0 2 6

1 3 7

2 4 8

3 5 9

 

 

 

 

자, 이제 차원을 하나 늘려볼까요?

 

 2) Broadcasting over axis 0 with a 1-D array

 

세로 방향(over axis 0)으로 row를 복사해가면서 Braodcasting을 하는 예입니다.

 

 

 

## (2) Broadcasting using a 1-D array
# Arithmetic operations between 2-D array and 1-D array
# that is the same length as the row-length

 

In [9]: b = np.arange(12).reshape((4, 3))


In [10]: b.shape

Out[10]: (4, 3)


In [11]: b

Out[11]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])


In [12]: c = np.array([0, 1, 2])


In [13]: c.shape

Out[13]: (3,)


In [14]: c

Out[14]: array([0, 1, 2])

 

# adding c (1-D array) row-wise to b (2-D array)

In [15]: b + c

Out[15]:

array([[ 0, 2, 4],

        [ 3, 5, 7],

        [ 6, 8, 10],

        [ 9, 11, 13]])

 

 

 

 

배열의 차원 크기, 모양이 다르다고 해서 Broadcasting 이 아무때나 되는 것은 아닙니다. Broadcasting을 시키려면 기준 축에 있는 원소의 크기(개수)가 서로 같아야지 짝을 맞추어서 확산(broadcasting, propagating)을 할 수 있습니다. 말로 설명하기가 좀 어렵습니다. ^^; 아래에 Broadcasting이 안되고 ValueError가 난 사례를 예로 들어보겠습니다.

 

  ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

 

## Shape mismatches
# ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

In [11]: b

Out[11]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])

 

In [16]: d = np.array([0, 1, 2, 3])


In [17]: b + d

Traceback (most recent call last):


File "<ipython-input-17-8c4237e65878>", line 1, in <module>

b + d


ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

 

 

 

  3) Broadcasting over axis 1 with a 2-D array

 

가로 방향(over axis 1)으로 column을 복사해가면서 broadcasting하는 예입니다.

 

 

 

## (3) Broadcasting over axis 1 of a 2-D array

 

In [18]: b = np.arange(12).reshape((4, 3))


In [19]: b.shape

Out[19]: (4, 3)


In [20]: b

Out[20]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])


In [21]: e = np.array([0, 1, 2, 3]).reshape(4, 1)


In [22]: e.shape

Out[22]: (4, 1)


In [23]: e

Out[23]:

array([[0],

        [1],

        [2],

        [3]])

 

# adding e (2-D array) column-wise to b (2-D array)

In [24]: b + e

Out[24]:

array([[ 0, 1, 2],

        [ 4, 5, 6],

        [ 8, 9, 10],

        [12, 13, 14]])

 

 

 

 

자, 이제 3차원으로 넘어가보겠습니다.  머리가 슬슬 아파오지요? ^^;

4차원부터는 그림으로 예시를 들기가 애매해서 3차원까지만 할께요.

 

  4) Broadcasting over axis 0 with a 3-D array

 

3-D 배열에서 앞뒤 방향(over axis 0) 으로 2-D 배열을 복사해가면서 Broadcasting 하는 예제입니다.

 

 

 

## (4) Broadcasting over axis 0 of a 3-D array
# 3-D array

 

In [25]: f = np.arange(24).reshape((2,4,3))


In [26]: f

Out[26]:

array([[[ 0, 1, 2],

         [ 3, 4, 5],

         [ 6, 7, 8],

         [ 9, 10, 11]],


        [[12, 13, 14],

         [15, 16, 17],

         [18, 19, 20],

         [21, 22, 23]]])

 

 

# 2-D array

In [27]: g = np.ones((4,3))


In [28]: g

Out[28]:

array([[ 1., 1., 1.],

        [ 1., 1., 1.],

        [ 1., 1., 1.],

        [ 1., 1., 1.]])

 

 

# Broadcasting over axis 0 of a 3-D array : 3-D array + 2-D array

In [29]: f + g

Out[29]:

array([[[ 1., 2., 3.],

         [ 4., 5., 6.],

         [ 7., 8., 9.],

         [ 10., 11., 12.]],


        [[ 13., 14., 15.],

         [ 16., 17., 18.],

         [ 19., 20., 21.],

         [ 22., 23., 24.]]])

 

 

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡'를 꾹 눌러주세요. ^^

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

Python을 활용한 기계학습이나 딥러닝 공부하다보면 NumPy 연산이 기본으로 깔려있습니다.  NumPy를 알고 있으면 공부하기가 편할 것이고, NumPy를 모르면 암호처럼 보일 거예요.  

 

이번 포스팅에서는 Python NumPy의 배열과 배열, 배열과 스칼라 연산 (Numerical Operations between Arrarys and Scalars) 에 대해서 알아보겠습니다. 별로 어렵지는 않습니다.  

 

크기가 같은 두 개의 숫자형 배열에 대해서 산술 연산(arithmetic operations)을 할 때 'for loops'를 사용하지 않고도 NumPy ndarray를 사용하면 Vectorization 으로 매우 빠르게 batch 연산을 수행할 수 있습니다.

 

만약 연산을 하는 두 배열의 차원(dimension, shape)이 다르다면 NumPy는 Broadcasting을 해서 연산을 해주는데요, 이건 다음번 포스팅에서 별도로 소개하겠습니다.

 

 

[ Operations between NumPy Arrarys and Scalars ]

 

 

 

 

먼저 NumPy 모듈을 불러오고 예제 array 를 만들어보겠습니다.

 

 

#%% Numerical Operations between Arrays and Scalars
# vectorization

## importing modules

 

In [1]: import numpy as np


## making an nparray

 

In [2]: x = np.array([1., 1., 2., 2.])


In [3]: y = np.array([1., 2., 3., 4.])


In [4]: x

Out[4]: array([ 1., 1., 2., 2.])


In [5]: y

Out[5]: array([ 1., 2., 3., 4.])

 

 

 

 

 

 (1) 배열과 스칼라의 산술 연산 (Arithmetic operations with an array and scalar)

  • 산술연산 종류 : 덧셈 (addition, +), 뺄셈 (subtraction, -), 곱셈 (multiplication, *), 나눗셈 (division, /), 몫 (floor division, //), 나머지 (modulus, %), 배수 (exponent, **)
  • 연산할 때 스칼라가 배열의 각 원소별로 모두 돌아가면서 연산의 대상으로 적용됨 (한글로 풀어쓰려니 표현이 참... -_-;) (propagating the value to each element).

 

 

## (1) Arithmetic operations with scalars, propagating the value to each element
# (1-1) addition

In [6]: y + 1

Out[6]: array([ 2., 3., 4., 5.])

 

# (1-2) subtraction

In [7]: y - 1

Out[7]: array([ 0., 1., 2., 3.])

 

# (1-3) multiplication

In [8]: y*2

Out[8]: array([ 2., 4., 6., 8.])

 

# (1-4) division

In [9]: y/2

Out[9]: array([ 0.5, 1. , 1.5, 2. ])

 

# (1-5) floor division

In [10]: y//2

Out[10]: array([ 0., 1., 1., 2.])

 

# (1-6) modulus : returns remainder after division

In [11]: y%2

Out[11]: array([ 1., 0., 1., 0.])

 

# (1-7) exponent

In [12]: y**2

Out[12]: array([ 1., 4., 9., 16.])


In [13]: 2**y

Out[13]: array([ 2., 4., 8., 16.])

 

 

 

 

  NumPy 와 Pure Python 속도 비교

 

위에서 NumPy (vectorization) 가 Pure Python (for loops) 보다 많이 빠르다고 했는데요, 한번 벤치마킹 테스트를 해보았습니다.  똑같은 연산 (배열에 스칼라 1 더하기)을 해봤는데요, NumPy가 Pure Python보다 62.4배 빠르네요. 이거 아주 중요해요.  보통 Python 공부하면서 아주 짧고 간단한 예제를 가지고 실습하다보면 NumPy와 Pure Python의 'for loops'의 속도 차이를 못느낄 수 있습니다. 그런데 만약 백만, 천만 row를 가진 big data에 for loop 잘못 썼다가는 몇 시간이 걸려도 연산이 끝나지 않던게, NumPy 잘 사용하면 수 분 안에 끝낼 수 있다는 뜻이거든요.

 

 

## comparison process time between NumPy and Pure Python
# NumPy

In [14]: a = np.arange(1000000)


In [15]: a

Out[15]: array([ 0, 1, 2, ..., 999997, 999998, 999999])


In [16]: %timeit a + 1

1000 loops, best of 3: 1.45 ms per loop

 


# Pure Python

In [17]: b = range(1000000)


In [18]: b

Out[18]: range(0, 1000000)


In [19]: %timeit [i+1 for i in b]

10 loops, best of 3: 90.5 ms per loop

 


# how fast does NumPy than Pure Python?

In [20]: 90.5/1.45

Out[20]: 62.41379310344828

 

 

 

 

 (2) 같은 크기 배열 간 산술 연산

     (Arithmetic elementwise operstions between equal-size arrays)

 

NumPy에서의 x*y 곱은 선형대수에서 쓰는 행렬곱이 아니며, 그냥 같은 위치에 있는 원소들 간의 곱(element-wise multiplication) 이라는 점 유의하세요.

 

 

## (2) Arithmetic elementwise operations between equal-size arrays

In [21]: x

Out[21]: array([ 1., 1., 2., 2.])


In [22]: y

Out[22]: array([ 1., 2., 3., 4.])

 


# (2-1) addition

In [23]: x + y

Out[23]: array([ 2., 3., 5., 6.])


# (2-2) substraction

In [24]: x - y

Out[24]: array([ 0., -1., -1., -2.])


# (2-3) Array multiplication is not matrix multiplication

In [25]: x*y

Out[25]: array([ 1., 2., 6., 8.])


# (2-4) division

In [26]: y/x

Out[26]: array([ 1. , 2. , 1.5, 2. ])

 

# (2-5) floor division : 몫

In [27]: y//x

Out[27]: array([ 1., 2., 1., 2.])


# (2-6) modulus : returns remainder after division, 나머지

In [28]: y%x

Out[28]: array([ 0., 0., 1., 0.])


# (2-7) power

In [29]: y**x

Out[29]: array([ 1., 2., 9., 16.])

 

 

 

 

 (3) 배열 간 비교 연산 (Comparison operations between equal-size arrays)

  • 원소 단위 비교 연산(element-wise comparison) : np.equal(x, y), np.not_equal(x, y), np.greater(x, y), np.greater_equal(x, y), np.less(x, y), np.less_equal(x, y)
  • 원소 단위로 비교 연산을 만족하면 True 반환, 비교 연산을 만족하지 않으면 False 반환함
  • 배열 단위 비교 연산(array-wise comparson) : np.array_equal(x, y)

 

 

## (3) Comparison operations : returns boolean array 

In [30]: x

Out[30]: array([ 1., 1., 2., 2.])

 

In [31]: y

Out[31]: array([ 1., 2., 3., 4.])

 


# element-wise comparisons
# (3-1) np.equal(x, y) : x==y

In [32]: np.equal(x, y)

Out[32]: array([ True, False, False, False], dtype=bool)

 


# (3-2) np.not_equal(x, y) : x != y, x <> y

In [33]: np.not_equal(x, y)

Out[33]: array([False, True, True, True], dtype=bool)

 


# (3-3) np.greater(x, y) : x > y

In [34]: np.greater(x, y)

Out[34]: array([False, False, False, False], dtype=bool)

 

 

# (3-4) np.greater_equal(x, y) : x >= y

In [35]: np.greater_equal(x, y)

Out[35]: array([ True, False, False, False], dtype=bool)

 


# (3-5) np.less(x, y) : x < y

In [36]: np.less(x, y)

Out[36]: array([False, True, True, True], dtype=bool)

 


# (3-6) np.less_equal(x, y) : x <= y

In [37]: np.less_equal(x, y)

Out[37]: array([ True, True, True, True], dtype=bool)

 


# (3-7) array-wise comparisons

In [38]: np.array_equal(x, y)

Out[38]: False


In [39]: z = y.copy()


In [40]: z

Out[40]: array([ 1., 2., 3., 4.])


In [41]: np.array_equal(y, z)

Out[41]: True

 

 

 

 

  (4) 배열 간 할당 연산 (Assignment operations between equal-size arrays)

  • 할당 연산 : Add AND (m += n), Subtract AND (m -= n), Multiply AND (m *= n), Divide AND (m /= n), Floor Division (m //= n), Modulus AND (m %= n), Exponent AND (m **= n)

 

##----------------
## (4) Assignment operattions

 

In [42]: m = np.array([1., 1., 2., 2.])


In [43]: n = np.array([1., 2., 3., 4.])

 


# (4-1) Add AND : +=

In [44]: m += n # equivalent to m = m + n

 

In [45]: m

Out[45]: array([ 2.,  3.,  5.,  6.])

 

 

# m += n  is equivalent to  m = m + n

In [46]: m = np.array([1., 1., 2., 2.])

 

In [47]: m = m + n


In [48]: m

Out[48]: array([ 2., 3., 5., 6.])

 

 

 

# (4-2) Subtract AND : -=

In [49]: m = np.array([1., 1., 2., 2.])


In [50]: m -= n # equivalent to m = m - n


In [51]: m

Out[51]: array([ 0., -1., -1., -2.])

 

 

 

# (4-3) Multiply AND : *=

In [52]: m = np.array([1., 1., 2., 2.])


In [53]: m *= n # equivalent to m = m*n


In [54]: m

Out[54]: array([ 1., 2., 6., 8.])

 

 

 

# (4-4) Divide AND : /=

In [55]: m = np.array([1., 1., 2., 2.])


In [56]: m /= n # equivalent to m = m/n


In [57]: m

Out[57]: array([ 1. , 0.5 , 0.66666667, 0.5 ])

 

 

 

# (4-5) Floor Division : //=

In [58]: m = np.array([1., 1., 2., 2.])


In [59]: m //= n # equivalent to m = m//n


In [60]: m

Out[60]: array([ 1., 0., 0., 0.])

 

 

 

# (4-6) Modulus AND : %=

In [61]: m = np.array([1., 1., 2., 2.])


In [62]: m %= n # equivalent to m = m % n


In [63]: m

Out[63]: array([ 0., 1., 2., 2.])

 

 

 

# (4-7) Exponent AND : **=

In [64]: m = np.array([1., 1., 2., 2.])


In [65]: m **= n # equivalent to m = m**n


In [66]: m

Out[66]: array([ 1., 1., 8., 16.])

 

 

 

 

  (5) 배열 간 논리 연산 (Logical operations between equal-size arrays)

  • 논리 연산
    - np.logical_and(a, b) : 두 배열의 원소가 모두 '0'이 아니면 True 반환 
    - np.logical_or(a, b) : 두 배열의 원소 중 한개라도 '0'이 아니면 True 반환
    - np.logical_xor(a, b) : 두 배열의 원소가 모두 '1'이 아니면 True 반환
                                 (↔ np.logical_and(a, b)와 정반대)

 

 

##----------------
## (5) Logical operators

In [67]: a = np.array([1, 1, 0, 0], dtype=bool)


In [68]: b = np.array([1, 0, 1, 0], dtype=bool)

 


# (5-1) np.logcal_and : (a and b) is true
# if all of the two operands are non-zero then condition becomes true

# equivalent to infix operators : &

In [69]: np.logical_and(a, b)

Out[69]: array([ True, False, False, False], dtype=bool)

 


# (5-2) np.logical_or : (a or b) is true
# if any of the operands are non-zero then contition becoems true

# equivalent to infix operators : |

In [70]: np.logical_or(a, b)

Out[70]: array([ True, True, True, False], dtype=bool)

 


# (5-3) np.logical_xor : Not (a and b) is false
# used to reverse the logical state of its operand

# equivalent to infix operators : ^

In [71]: np.logical_xor(a, b)

Out[71]: array([False, True, True, False], dtype=bool)

 

 

 

  (6) 소속 여부 판단 연산 (Membership operators)

  • 소속 여부 판단 연산 : in, not in
  • 배열 (혹은 리스트)에 특정 객체들어있으면 True를 반환, 안들어 있으면 False를 반환

 

# (6) Membership operators

In [72]: p = "P"


In [73]: q = np.array(["P", "Q"])


In [74]: r = np.array(["R", "S"])

 


# (6-1) in

In [75]: p in q

Out[75]: True


In [76]: p in r

Out[76]: False

 


# (6-2) not in

In [77]: p not in q

Out[77]: False


In [78]: p not in r

Out[78]: True

 

 

 

 

 배열의 차원, 크기가 다를 때

 => ValueError: operands could not be broadcast together with shapes (4,) (5,) 

 

 

##--------------
## Shape mismatches

In [79]: x4 = np.array([1., 1., 2., 2.])

 

In [80]: x5 = np.arange(5)

 


# ValueError: operands could not be broadcast together with shapes (4,) (5,)

In [81]: x4 + x5

Traceback (most recent call last):


File "<ipython-input-82-5e88af36d6f1>", line 1, in <module>

x4 + x5


ValueError: operands could not be broadcast together with shapes (4,) (5,)

 

 

배열의 차원, 크기가 다를 때 ValueError가 났습니다.  그리고 'broadcast'를 할 수 없다(could not be broadcast together...)는 메시지가 나왔습니다.

 

다음번 포스팅에서는 Broadcasting 에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감~♡'를 눌러주세요. ^^

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend


티스토리 툴바