이번 포스팅에서는 Python Numpy 배열 (array)에 차원을 추가하는 3가지 방법을 소개하겠습니다. 딥러닝 공부하다 보면 computer vision의 CNN에서 이미지 파일을 불러와서 다차원 배열로 변환할 때 사용하곤 합니다. 

1. numpy.reshape() 을 이용한 차원 추가

2. numpy.expand_dims() 을 이용한 차원 추가

3. numpy.newaxis 을 이용한 차원 추가


예제로 사용할 간단한 (4, 3, 2) 3차원의 다차원 배열을 만들어보겠습니다. 


import numpy as np

a = np.arange(24).reshape(4, 3, 2)

a

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]]])

a.shape

(4, 3, 2)




(4, 3, 2) 차원의 배열 a에 차원을 추가하여 (1, 4, 3, 2)의 4차원 배열로 만들어보겠습니다. 


  1. numpy.reshape() 를 이용한 차원 추가


 

np.reshape(a, (1, 4, 3, 2))

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]]]])


 np.reshape(a, ((1,) + a.shape))

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]]]])

 a.reshape((1,) + a.shape)

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. numpy.expand_dims() 를 이용한 차원 추가



np.expand_dims(a, axis=0)

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]]]])

 



  3. numpy.newaxis 를 이용한 차원 추가



a[:, np.newaxis]

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]]]])

 


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

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

Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 배열(array)에서 0보다 작은 수는 0으로 변환하고 나머지는 그대로 두는 여러가지 방법을 소개하겠습니다. 


1. List Comprehension with for loop

2. Indexing

3. np.where(condition[, x, y])

4. np.clip(a, a_min, a_max, out=None)





  1. List Comprehension: [0 if i < 0 else i for i in a]


아래처럼 for loop 을 써서 list comprehension 방법을 사용하면 특정 라이브러리의 함수를 사용하지 않아도 0보다 작은 수는 0으로 변환할 수 있습니다. 하지만, for loop 을 돌기 때문에 배열(array)가 커지면 성능이 문제될 수 있습니다.  원래의 배열 a는 그대로 있습니다. 



>>> import numpy as np

>>> a = np.arange(-5, 5)

>>> a

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

>>> [0 if i < 0 else i for i in a]

[0, 0, 0, 0, 0, 0, 1, 2, 3, 4]

>>> a

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





  2. Indexing: a[a < 0] = 0


아래처럼 indexing을 사용해서 a[a < 0] = 0 처럼 0보다 작은 값이 위치한 곳에 0을 직접 할당할 수 있습니다. 이렇게 하면 원래의 배열 a가 변경됩니다. 



>>> a = np.arange(-5, 5)

>>> a

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

>>> a[a < 0] = 0

>>> a

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

 




  3. np.where() : np.where(a < 0, 0, a)


np.where(조건, True일 때 값, False일 때 값) 를 사용하면 편리하게 0보다 작은 조건의 위치에 0을 할당할 수 있습니다. 벡터 연산을 하므로 for loop이 돌지 않아서 속도가 매우 빠릅니다. 원래의 배열 a는 변경되지 않고 그대로 있습니다. 



>>> a = np.arange(-5, 5)

>>> a

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

>>> np.where(a < 0, 0, a)

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

>>> a

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

 



만약 0보다 작은 수는 0으로 변환, 2보다 큰 수는 2로 변환하고 싶다면 아래처럼 np.where() 안에 np.where()를 한번 더 넣어서 써주면 되는데요, 코드가 좀 복잡해보입니다. 



>>> a = np.arange(-5, 5)

>>> a

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

>>>

>>> np.where(a < 0, 0, np.where(a > 2, 2, a))

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

 




  4. np.clip() : np.clip(a, 0, 4, out=a)


np.clip(배열, 최소값 기준, 최대값 기준) 을 사용하면 최소값과 최대값 조건으로 값을 기준으로 해서, 이 범위 기준을 벗어나는 값에 대해서는 일괄적으로 최소값, 최대값으로 대치해줄 때 매우 편리합니다. 최소값 부분을 0으로 해주었으므로 0보다 작은 값은 모두 0으로 대치되었습니다. 이때 원래의 배열 a는 그대로 있습니다. 



>>> a = np.arange(-5, 5)

>>> a

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

>>> np.clip(a, 0, 4)

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

>>> a

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

 



np.clip(배열, 최소값 기준, 최대값 기준, out 배열)을 사용해서 out = a 를 추가로 설정해주면 반환되는 값을 배열 a에 저장할 수 있습니다. 배열 a의 0보다 작았던 부분이 모두 0으로 대치되어 a가 변경되었음을 확인할 수 있습니다. 



>>> np.clip(a, 0, 4, out=a)

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

>>> a

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

 



최소값 기준만 적용해서 간단하게 '0'보다 작은 수는 모두 0으로 바꾸는 것은 a.clip(0) 처럼 메소드를 사용해도 됩니다. 



>>> a = np.arange(-5, 5)

>>> a

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

>>> a.clip(0)

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

 



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


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



Posted by R Friend R_Friend

댓글을 달아 주세요

학교 다닐 때 행렬로 연립방정식 풀었던 기억이 날 듯 합니다. 선형대수(Linear Algebra)는 통계, 기계학습, 공학, 영상/이미지 처리 등 여러 분야에서 활용이 됩니다. 선형대수를 전부 다루려면 너무나 방대하므로, 이번 포스팅에서는 Python의 NumPy에 있는 선형대수(Linear Algebra) 함수들 중에서 자주 사용하는 함수에 대해서만 선별적으로 소개하겠습니다. 그리고 선형대수의 이론적인 부분은 별도로 참고할 수 있는 링크를 달도록 하겠습니다. 


  • 단위행렬 (Unit matrix): np.eye(n)
  • 대각행렬 (Diagonal matrix): np.diag(x)
  • 내적 (Dot product, Inner product): np.dot(a, b)
  • 대각합 (Trace): np.trace(x)
  • 행렬식 (Matrix Determinant): np.linalg.det(x)
  • 역행렬 (Inverse of a matrix): np.linalg.inv(x)
  • 고유값 (Eigenvalue), 고유벡터 (Eigenvector): w, v = np.linalg.eig(x)
  • 특이값 분해 (Singular Value Decomposition): u, s, vh = np.linalg.svd(A)
  • 연립방정식 해 풀기 (Solve a linear matrix equation): np.linalg.solve(a, b)
  • 최소자승 해 풀기 (Compute the Least-squares solution): m, c = np.linalg.lstsq(A, y, rcond=None)[0]




 1. 단위행렬 혹은 항등행렬 (Unit matrix, Identity matrix): np.eye(n)


단위행렬은 대각원소가 1이고, 나머지는 모두 0인 n차 정방행렬을 말하며, numpy의 eye() 함수를 사용해서 만들 수 있습니다. 


* 참고 링크 : https://rfriend.tistory.com/141



import numpy as np


unit_mat_4 = np.eye(4)


print(unit_mat_4)

[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

 




  1. 대각행렬 (Diagonal matrix): np.diag(x)


대각행렬은 대각성분 이외의 모든 성분이 모두 '0'인 n차 정방행렬을 말합니다. 아래 예시의 행렬에서 빨간색으로 표시한 원소를 '0'으로 바꾼 행렬이 대각행렬입니다. 


* 참고 링크 : http://rfriend.tistory.com/141


 

In [1]: import numpy as np


In [2]: x = np.arange(9).reshape(3, 3)


In [3]: print(x)

[[0 1 2]

 [3 4 5]

 [6 7 8]]


In [4]: np.diag(x)

Out[4]: array([0, 4, 8])


In [5]: np.diag(np.diag(x))

Out[5]:

array([[0, 0, 0],

        [0, 4, 0],

        [0, 0, 8]])





  2. 내적 (Dot product, Inner product): np.dot(a, b), a.dot(b)


matrix dot product, inner product, scalar product, projection product

Python에서 '*' 를 사용한 두 행렬 간 곱은 원소 간 곱(element-wise product)을 반환하며, 선형대수에서 말하는 행렬 간 내적 곱을 위해서는 np.dot() 함수를 이용해야 합니다. 


원소 간 곱 (element-wise product)

: a*b

내적 (dot product, inner product)

: np.dot(a, b)

 

In [6]: a = np.arange(4).reshape(2, 2)


In [7]: print(a)

[[0 1]

 [2 3]]


In [8]: a*a

Out[8]:

array([[0, 1],

        [4, 9]])


In [6]: a = np.arange(4).reshape(2, 2)


In [7]: print(a)

[[0 1]

 [2 3]]


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

Out[9]:

array([[ 2, 3],

        [ 6, 11]])



np.dot(a, b) NumPy 함수와 a.dot(b)의 배열 메소드의 결과는 동일합니다. 



In [10]: a.dot(a)

Out[10]:

array([[ 2, 3],

        [ 6, 11]])

 




  3. 대각합 (Trace): np.trace(x)


정방행렬의 대각에 위치한 원소를 전부 더해줍니다. 

아래의 2차 정방행렬 예의 대각합은 0+5+10+15 = 30 이 됩니다. (파란색으로 표시함)



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


In [13]: print(b)

[[ 0 1 2 3]

 [ 4 5 6 7]

 [ 8 9 10 11]

 [12 13 14 15]]


In [14]: np.trace(b)

Out[14]: 30

 



3차원 행렬에 대해서도 대각합을 구할 수 있습니다. 2차원은 대각선 부분의 원소 값을 전부 더하면 되지만 3차원 행렬에서는 대각(diagonal)이 어떻게 되나 좀 헷갈릴 수 있겠습니다. 아래의 3차원 행렬의 대각합을 구하는 예를 살펴보면, [0+12+24, 1+13+25, 2+14+26] = [36, 39, 42] 가 됩니다. 



In [15]: c = np.arange(27).reshape(3, 3, 3)


In [16]: print(c)

[[[ 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]]]


In [17]: np.trace(c)

Out[17]: array([36, 39, 42])

 




  4. 행렬식 (Matrix Determinant): np.linalg.det(x)


역행렬이 존재하는지 여부를 확인하는 방법으로 행렬식(determinant, 줄여서 det)이라는 지표를 사용합니다. 이 행렬식이 '0'이 아니면 역행렬이 존재하고, 이 행렬식이 '0'이면 역행렬이 존재하지 않습니다. 


* 참고 링크 : http://rfriend.tistory.com/142


아래의 예에서 array([[1, 2], [3, 4]]) 의 행렬식이 '-2.0'으로서, '0'이 아니므로 역행렬이 존재한다고 판단할 수 있습니다. 



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


In [19]: np.linalg.det(a)

Out[19]: -2.0

 




  5. 역행렬 (Inverse of a matrix): np.linalg.inv(x)


역행렬은 n차정방행렬 Amn과의 곱이 항등행렬 또는 단위행렬 In이 되는 n차정방행렬을 말합니다. A*B 와 B*A 모두 순서에 상관없이 곱했을 때 단위행렬이 나오는 n차정방행렬이 있다면 역행렬이 존재하는 것입니다.

역행렬은 가우스 소거법(Gauss-Jordan elimination method), 혹은 여인수(cofactor method)로 풀 수 있습니다. 




In [20]: a = np.array(range(4)).reshape(2, 2)


In [21]: print(a)

[[0 1]

 [2 3]]


In [22]: a_inv = np.linalg.inv(a)


In [23]: a_inv

Out[23]:

array([[-1.5, 0.5],

        [ 1. , 0. ]])




위의 예제에서 np.linalg.inv() 함수를 사용하여 푼 역행렬이 제대로 푼 것인지 확인을 해보겠습니다. 역행렬의 정의에 따라서 원래의 행렬에 역행렬을 곱하면, 즉, a.dot(a_inv) 또는 np.dot(a, a_inv) 를 하면 단위행렬(unit matrix)가 되는지 확인해보겠습니다. 



In [24]: a.dot(a_inv)

Out[24]:

array([[1., 0.],

         [0., 1.]])

 




  6. 고유값 (Eigenvalue), 고유벡터 (Eigenvector): w, v = np.linalg.eig(x)


정방행렬 A에 대하여 Ax = λx  (상수 λ) 가 성립하는 0이 아닌 벡터 x가 존재할 때 상수 λ 를 행렬 A의 고유값 (eigenvalue), x 를 이에 대응하는 고유벡터 (eigenvector) 라고 합니다. 


np.linalg.eig() 함수는 고유값(eigenvalue) w, 고유벡터(eigenvector) v 의 두 개의 객체를 반환합니다. 


In [25]: e = np.array([[4, 2],[3, 5]])


In [26]: print(e)

[[4 2]

[3 5]]


In [27]: w, v = np.linalg.eig(e)


#  w: the eigenvalues lambda

In [28]: print(w)

[2. 7.]


# v: the corresponding eigenvectors, one eigenvector per column

In [29]: print(v)

[[-0.70710678 -0.5547002 ]

[ 0.70710678 -0.83205029]]

 



고유벡터는 배열 인덱싱하는 방법을 사용해서 각 고유값에 대응하는 고유벡터를 선택할 수 있습니다. 



# eigenvector of eigenvalue lambda 2

In [30]: print(v[:, 0]

[-0.70710678 0.70710678]


# eigenvector of eigenvalue labmda 7

In [31]: print(v[:, 1]

[-0.5547002 -0.83205029]

 




  7. 특이값 분해 (Singular Value Decomposition): u, s, vh = np.linalg.svd(A)


특이값 분해는 고유값 분해(eigen decomposition)처럼 행렬을 대각화하는 한 방법으로서, 정방행렬뿐만 아니라 모든 m x n 행렬에 대해 적용 가능합니다. 특이값 분해는 차원축소, 데이터 압축 등에 사용할 수 있습니다. 이론적인 부분은 설명하자면 너무 길기 때문에 이 포스팅에서는 설명하지 않겠으며, 아래의 링크를 참고하시기 바랍니다. 


* 참고 링크 : http://rfriend.tistory.com/185


아래의 np.linalg.svd(A) 예제는 위의 참고 링크에서 사용했던 예제와 동일한 것을 사용하였습니다. 


In [32]: A = np.array([[3,6], [2,3], [0,0], [0,0]])


In [33]: print(A)

[[3 6]

 [2 3]

 [0 0]

 [0 0]]


In [34]: u, s, vh = np.linalg.svd(A)


In [35]: print(u)

[[-0.8816746 -0.47185793 0. 0. ]

 [-0.47185793 0.8816746 0. 0. ]

 [ 0. 0. 1. 0. ]

 [ 0. 0. 0. 1. ]]


In [36]: print(s)

[7.60555128 0.39444872]


In [37]: print(vh)

[[-0.47185793 -0.8816746 ]

 [ 0.8816746 -0.47185793]]

 




  8. 연립방정식 해 풀기 (Solve a linear matrix equation): np.linalg.solve(a, b)


아래의 두 개 연립방정식의 해(x0, x1)를 np.linalg.solve(a, b) 함수를 사용하여 풀어보겠습니다. 



위의 연립방정식을 어떻게 행렬로 입력하고, np.linalg.solve(a, b)에 입력하는지 유심히 살펴보시기 바랍니다. 



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


In [39]: b = np.array([23, 16])


In [40]: x = np.linalg.solve(a, b)


In [41]: print(x)

[2. 5.]

 



NumPy 가 제대로 x0, x1의 해를 풀었는지 확인해보겠습니다. x0=2, x1=5 가 해 맞네요!



In [42]: np.allclose(np.dot(a, x), b)

Out[42]: True

 




  9. 최소자승 해 풀기 (Compute the Least-squares solution)

     : m, c = np.linalg.lstsq(A, y, rcond=None)[0]


회귀모형 적합할 때 최소자승법(Least-squares method)으로 잔차 제곱합을 최소화하는 회귀계수를 추정합니다. 


* 참고 링크 : https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.lstsq.html



아래의 예에서는 회귀계수 m, y절편 c를 최소자승법을 사용해서 구해보겠습니다. 



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


In [44]: y = np.array([-1, 0.2, 0.9, 2.1])


In [45]: A = np.vstack([x, np.ones(len(x))]).T


In [46]: A

Out[46]:

array([[0., 1.],

        [1., 1.],

        [2., 1.],

        [3., 1.]])


In [47]: m, c = np.linalg.lstsq(A, y, rcond=None)[0]


In [48]: print(m, c)

0.9999999999999999 -0.9499999999999997

 



아래의 그래프에서 점은 원래의 데이터이며, 빨간색 선은 최소자승법으로 추정한 회귀식의 적합선이 되겠습니다. 



In [49]: import matplotlib.pyplot as plt

    ...: plt.plot(x, y, 'o', label='Original data', markersize=10)

    ...: plt.plot(x, m*x + c, 'r', label='Fitted line')

    ...: plt.legend()

    ...: plt.show()




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


Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 Python NumPy 배열을 여러개의 하위 배열로 분할하는 방법을 소개하겠습니다. 


  • 한 개의 배열을 수평 축(열 방향, column-wise)으로 여러 개의 하위 배열로 분할하기
    - np.hsplit(x, 3), np.hsplit(x, (2, 4))
    - np.split(x, 3, axis=1), np.split(x, (2, 4), axis=1)
  • 한 개의 배열을 수직 축( 방향, row-wise)으로 여러 개의 하위 배열로 분할하기
    - np.vsplit(x, 3), np.vsplit(x, (1, 2))
    - np.split(x, 3, axis=0), np.split(x, (1, 2), axis=0)


[ Python NumPy 배열 분할하기 ]




간단한 예를 들어서 설명하겠습니다. 


 (1) 한 개의 배열을 수평 축(열 방향, column-wise)으로 여러 개의 하위 배열로 분할하기



In [1]: import numpy as np


In [2]: x = np.arange(18).reshape(3, 6)


In [3]: x

Out[3]:

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

        [ 6, 7, 8, 9, 10, 11],

        [12, 13, 14, 15, 16, 17]])



아래의 4가지 함수 모두 동일한 결과를 반환합니다. 

  • np.hsplit(x, 3) : x 배열을 수평 축(열 방향, column-wise)으로 3개의 배열로 분할
  • np.hsplit(x, (2, 4)) : x 배열을 수평 축(열 방향, colomn-wise)의 x[:,0:2], x[:,2:4], x[:,4:6] 위치의 원소를 가지는 3개의 배열로 분할

 np.hsplit(x, 3)

np.hsplit(x, (2, 4)) 


 In [4]: np.hsplit(x, 3)

Out[4]:

[array([[ 0, 1],

         [ 6, 7],

         [12, 13]]), 

 array([[ 2, 3],

         [ 8, 9],

         [14, 15]]), 

 array([[ 4, 5],

         [10, 11],

         [16, 17]])]


 In [5]: np.hsplit(x, (2, 4))

Out[5]:

[array([[ 0, 1],

         [ 6, 7],

         [12, 13]]), 

 array([[ 2, 3],

         [ 8, 9],

         [14, 15]]), 

 array([[ 4, 5],

         [10, 11],

         [16, 17]])]


  • np.split(x, 3, axis=1) = np.hsplit(x, 3) 와 동일
  • np.split(x, (2, 4), axis=1) = np.hsplit(x, (2, 4)) 와 동일

np.split(x, 3, axis=1)

np.split(x, (2, 4), axis=1)

 

In [6]: np.split(x, 3, axis=1)

Out[6]:

[array([[ 0, 1],

         [ 6, 7],

         [12, 13]]), 

 array([[ 2, 3],

         [ 8, 9],

         [14, 15]]), 

 array([[ 4, 5],

         [10, 11],

         [16, 17]])]


 

In [7]: np.split(x, (2, 4), axis=1)

Out[7]:

[array([[ 0, 1],

         [ 6, 7],

         [12, 13]]), 

 array([[ 2, 3],

         [ 8, 9],

         [14, 15]]), 

 array([[ 4, 5],

         [10, 11],

         [16, 17]])]




아래 처럼 하나의 배열을 3개로 분할했을 때, 각 하위 배열을 x1, x2, x3 에 할당할 수 있습니다. 


In [8]: x1, x2, x3 = np.hsplit(x, 3)


In [9]: x1

Out[9]:

array([[ 0, 1],

        [ 6, 7],

        [12, 13]])


In [10]: x2

Out[10]:

array([[ 2, 3],

        [ 8, 9],

        [14, 15]])


In [11]: x3

Out[11]:

array([[ 4, 5],

        [10, 11],

        [16, 17]])

 




(2) 한 개의 배열을 수직 축( 방향, row-wise)으로 여러 개의 하위 배열로 분할하기


 

In [2]: x = np.arange(18).reshape(3, 6)


In [3]: x

Out[3]:

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

        [ 6, 7, 8, 9, 10, 11],

        [12, 13, 14, 15, 16, 17]])



  • np.vsplit(x, 3) : x배열을 수직 축 (행 방향, row-wise) 으로 3개의 하위 배열로 분할하기
  • np.vsplit(x, (1, 2)) : x배열을 수직 축 (행 방향, row-wise) 기준으로 x[0:1, :], x[1:2, :], x[2:3, :] 위치의 원소를 가지는 3개의 하위 배열로 분할하기

np.vsplit(x, 3

np.vsplit(x, (1, 2))

 

In [12]: np.vsplit(x, 3)

Out[12]:

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

 array([[ 6, 7, 8, 9, 10, 11]]),

 array([[12, 13, 14, 15, 16, 17]])]



 In [13]: np.vsplit(x, (1, 2))

Out[13]:

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

 array([[ 6, 7, 8, 9, 10, 11]]),

 array([[12, 13, 14, 15, 16, 17]])]



  • np.split(x, 3, axis=0) = np.vsplit(x, 3) 과 동일
  • np.split(x, (1, 2), axis=0) = np.vsplit(x, (1, 2)) 와 동일

np.split(x, 3, axis=0)

np.split(x, (1, 2), axis=0) 

 

In [14]: np.split(x, 3, axis=0)

Out[14]:

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

 array([[ 6, 7, 8, 9, 10, 11]]),

 array([[12, 13, 14, 15, 16, 17]])]


 

In [15]: np.split(x, (1, 2), axis=0)

Out[15]:

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

 array([[ 6, 7, 8, 9, 10, 11]]),

 array([[12, 13, 14, 15, 16, 17]])]




저는 np.hsplit()과 np.vsplit() 이 행과 열 중에서 어디를 기준으로 분할이 되는 건지 자꾸 헷갈리네요. 직관적인 코드 가독성면에서는 np.split(x, n, axis=0), np.split(x, n, axis=1) 처럼 axis = 0 or 1 로 표기해주는 방식이 저한테는 더 이해하기가 쉽네요. 


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


Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 Python NumPy 배열(array) 데이터를 외부 파일로 저장(save)하는 방법, 외부 파일을 배열로 불러오는(load) 방법에 대해서 알아보겠습니다.


  • np.save() : 1개의 배열을 NumPy format의 바이너리 파일로 저장하기 (Save a single array to a binary file in NumPy format)
  • np.load() : np.save()로 저장된 *.npy 파일을 배열로 불러오기 (Open a *.npy file and load it as an array)
  • np.savez() : 여러개의 배열을 1개의 압축되지 않은 *.npz 포맷 파일로 저장하기 (Save several arrays into a single file in uncompressed .npz format)
  • np.load() : np.savez()로 저장된 *.npz 파일을 배열로 불러오기 (Open a *.npz file and load it as an array)
  • np.save_compressed() : 여러개의 배열을 1개의 압축된 *.npz 포맷 파일로 저장하기 (Save several arrays into a single file in compressed .npz format)
  • np.load() : np.save_compressed()로 저장된 압축된 *.npz 파일을 배열러 불러오기 (Open a compressed *.npz file and load it as an array)
  • np.savetext(: 여러개의 배열을 텍스트 파일로 저장하기 (Save several array to a file as plain text)
  • np.loadtext(: 텍스트 파일을 배열로 불러오기 (Open a text file and load it as an array)


[ Python NumPy 배열을 파일로 저장하기(save), 불러오기(load) ]




하나씩 간단한 예를 들어서 설명하겠습니다. 


 > np.save() : 1개의 배열을 NumPy format의 바이너리 파일로 저장하기

 > np.load() : np.save()로 저장된 *.npy 파일을 배열로 불러오기 



In [1]: import numpy as np


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


# 배열을 저장하기

In [3]: np.save('D:/admin/Documents/x_save', x) # x_save.npy


[ .npy 형식으로 저장된 파일 ]


# 배열로 불러오기

In [4]: x_save_load = np.load('D:/admin/Documents/x_save.npy')


In [5]: x_save_load

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

 




 > np.savez() : 여러개의 배열을 1개의 압축되지 않은 *.npz 포맷 파일로 저장하기

 > np.load() : np.savez()로 저장된 *.npz 파일을 배열로 불러오기



In [6]: x = np.array([0, 1, 2, 3, 4])


In [7]: y = np.array([5, 6, 7, 8, 9])


In [8]: np.savez('D:/admin/Documents/xy_savez'

   ...: , x=x, y=y) # 각 배열에 이름 부여

 

 [ .npz 형식으로 저장된 파일 ]



np.load() 함수로 .npz 파일을 열어서 배열로 불러올 수 있습니다. 이때 불러온 파일의 type은 'numpy.lib.npyio.NpzFile' 이며, 개별 배열을 indexing 하려면 [ ]  를 사용합니다. 


# 배열로 불러오기

In [9]: xy_savez_load = np.load('D:/admin/Documents/xy_savez.npz')


In [10]: type(xy_savez_load)

Out[10]: numpy.lib.npyio.NpzFile


In [11]: xy_savez_load['x']

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


In [12]: xy_savez_load['y']

Out[12]: array([5, 6, 7, 8, 9])

 


np.load() 함수로 연 파일을 더이상 사용할 일이 없으면 메모리 효율 관리를 위해 file.close() 로 닫아주어야 합니다. .close() 로 파일을 닫은 상태에서 indexing 을 하려면 'NoneType' object has no attribute 'open' 에러가 납니다. 


In [13]: xy_savez_load.close()


In [14]: xy_savez_load['x'] # AttributeError: 'NoneType' object has no attribute 'open'

Traceback (most recent call last):


File "<ipython-input-14-14d248a305d2>", line 1, in <module>

xy_savez_load['x'] # AttributeError: 'NoneType' object has no attribute 'open'


File "C:\Users\admin\Anaconda3\envs\py_v36\lib\site-packages\numpy\lib\npyio.py", line 226, in __getitem__

bytes = self.zip.open(key)


AttributeError: 'NoneType' object has no attribute 'open'

 




 > np.save_compressed() : 여러개의 배열을 1개의 압축된 *.npz 포맷 파일로 저장하기

 > np.load() : np.save_compressed()로 저장된 압축된 *.npz 파일을 배열러 불러오기



In [15]: x = np.arange([0, 1, 2, 3, 4])


In [16]: y = np.array([5, 6, 7, 8, 9])


In [17]: np.savez_compressed('D:/admin/Documents/xy_savez_compress'

    ...: , x=x, y=y)

 

 [ .npz 형식으로 압축되어 저장된 파일 ]



np.load() 함수로 불러오기를 하면 'numpy.lib.npyio.NpzFile' type 이며, [ ] 를 사용해서 배열을 indexing 할 수 있습니다. 사용을 끝냈으면 .close() 함수로 닫아줍니다. 


In [18]: xy_savez_compress_load = np.load('D:/admin/Documents/xy_savez_compress.npz')


In [19]: type(xy_savez_compress_load)

Out[19]: numpy.lib.npyio.NpzFile


In [20]: xy_savez_compress_load['x']

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


In [21]: xy_savez_compress_load['y']

Out[21]: array([5, 6, 7, 8, 9])


In [22]: xy_savez_compress_load.close()

 




 > np.savetext() : 여러개의 배열을 텍스트 파일로 저장하기

 > np.loadtext() : 텍스트 파일을 배열로 불러오기


header, footer 로 '#'으로 시작되는 부가설명을 추가할 수 있습니다. 

fmt 로 포맷을 지정할 수 있습니다. 아래 예에서는 소수점 2자리까지만 고정된 자리수로 표현하도록 해보았습니다. 


In [23]: x = np.array([0, 1, 2, 3, 4])


In [24]: y = np.array([5, 6, 7, 8, 9])


In [25]: np.savetxt('D:/admin/Documents/xy_savetxt.txt'

   ...: , (x, y) # x,y equal sized 1D arrays

   ...: , header='--xy save start--'

   ...: , footer='--xy save end--'

   ...: , fmt='%1.2f') # the second digit after the decimal point

 

 [ Text file 로 저장된 배열 ]



np.loadtxt() 함수로 텍스트 파일을 배열로 불러올 수 있으며, ndarray type 으로 바로 불러오게 됩니다. 


In [26]: xy_savetxt_load = np.loadtxt('D:/admin/Documents/xy_savetxt.txt')


In [27]: xy_savetxt_load

Out[27]:

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

        [ 5., 6., 7., 8., 9.]])

 

In [28]: type(xy_savetxt_load)

Out[28]: numpy.ndarray




2D array 도 텍스트 파일로 저장할 수 있습니다. 

 

In [29]: x2 = np.arange(12).reshape(3, 4)


In [30]: x2

Out[30]:

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

        [ 4, 5, 6, 7],

        [ 8, 9, 10, 11]])


In [31]: np.savetxt('D:/admin/Documents/x2_savetxt.txt'

    ...: , x2

    ...: , fmt='%1.2f')


 [ Text 파일로 저장된 2D 배열 ]



np.loadtxt() 함수로 텍스트 파일을 배열로 불러올 수 있습니다. 원래의 x2 배열과 정확하게 동일하게 잘 불러왔습니다. 


In [32]: x2_savetxt_load = np.loadtxt('D:/admin/Documents/x2_savetxt.txt')


In [33]: x2_savetxt_load

Out[33]:

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

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

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

 


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


Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 Python numpy 배열을 정렬(array sorting)하는 방법에 대해서 소개하겠습니다.

 

- (1) 1차원 배열 정렬 : np.sort(x)

- (2) 1차원 배열 거꾸로 정렬 : np.sort(x)[::-1] , x[np.argsort(-x)]

- (3) 2차원 배열 열 축 기준으로 정렬 : np.sort(x, axis=1)

- (4) 2차원 배열 행 축 기준으로 정렬 : np.sort(x, axis=0)

- (5) 2차원 배열 행 축 기준으로 거꾸로 정렬 : np.sort(x, axis=0)[::-1]

 


[ Python Numpy 배열 정렬: np.sort() ]

 



  (1) 1차원 배열 정렬 : np.sort(x)

 

 

In [1]: import numpy as np


In [2]: x = np.array([4, 2, 6, 5, 1, 3, 0])


In [3]: np.sort(x)

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

 

 

 

참고로, np.sort(x) 메소드는 원래의 배열은 그대로 둔채로 정렬이 된 결과를 복사본으로 반환합니다.

반면에 x.sort() 메소드는 원래의 배열 자체를 정렬합니다.

 

np.sort(x) 

=> 원래 배열은 그래로, 정렬 결과 복사본 반환

x.sort()

=> 배열 자체를 정렬

 

In [2]: x = np.array([4, 2, 6, 5, 1, 3, 0])


In [3]: np.sort(x)

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


In [4]: x

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

 

 In [5]: x = np.array([4, 2, 6, 5, 1, 3, 0])

   ...:


In [6]: x.sort()


In [7]: x

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

 

 

 

 (2) 1차원 배열 거꾸로 정렬 : np.sort(x)[::-1] , x[np.argsort(-x)]

 

배열을 거꾸로 정렬하는 방법에는 2가지가 있습니다.

 

(2-1) np.sort(x)[::-1] : 정렬을 한 후 mirror view 생성

 

 

In [8]: x = np.array([4, 2, 6, 5, 1, 3, 0])


In [9]: x_reverse_1 = np.sort(x)[::-1] # mirror view


In [10]: x_reverse_1

Out[10]: array([6, 5, 4, 3, 2, 1, 0])

 

 

 

(2-2) x[np.argsort(-x)] : np.argsort() 로 index를 받아서 indexing 해오기

 

 

In [11]: x = np.array([4, 2, 6, 5, 1, 3, 0])


In [12]: x_reverse_2 = x[np.argsort(-x)] # copy of reversed sorting


In [13]: x_reverse_2

Out[13]: array([6, 5, 4, 3, 2, 1, 0])

 

 



(3) 2차원 배열 열 축 기준으로 정렬 (from left to right) : np.sort(x, axis=1)


'axis = 1' 옵션을 주면 열 축을 기준으로, 좌에서 우로 (from left to right) 정렬을 합니다. 

이게 좀 헷갈릴 수 있는데요, 아래 예제로 확인해 보시기 바랍니다. 



In [14]: x2 = np.array([[2, 1, 6],

    ...:                       [0, 7, 4],

    ...:                       [5, 3, 2]])


In [15]: x2_sort_axis_1 = np.sort(x2, axis=1) # default


In [16]: x2_sort_axis_1

Out[16]:

array([[1, 2, 6],

        [0, 4, 7],

        [2, 3, 5]])

 




 (4) 2차원 배열 행 축 기준으로 정렬 (from top to bottom) : np.sort(x, axis=0)



In [17]: x2 = np.array([[2, 1, 6],

    ...:                       [0, 7, 4],

    ...:                       [5, 3, 2]])


In [18]: x2_sort_axis_0 = np.sort(x2, axis=0)


In [19]: x2_sort_axis_0

Out[19]:

array([[0, 1, 2],

        [2, 3, 4],

        [5, 7, 6]])

 




 (5) 2차원 배열 열 축 기준으로 거꾸로 정렬 (from bottom to top, reversely) 

     : np.sort(x, axis=1)[::-1]



In [20]: x2 = np.array([[2, 1, 6],

    ...:                       [0, 7, 4],

    ...:                       [5, 3, 2]])


In [21]: x2_sort_axis_0_reverse = np.sort(x2, axis=0)[::-1]


In [22]: x2_sort_axis_0_reverse

Out[22]:

array([[5, 7, 6],

        [2, 3, 4],

        [0, 1, 2]])

 


 

참고로 Python

 - (1) DataFrame 정렬 : DataFrame.sort_values()

 - (2) Tuple 정렬 : sorted(tuple, key)

 - (3) List 정렬 : list.sort(), sorted(list)

http://rfriend.tistory.com/281  을 참고하시기 바랍니다.


사전 자료형(Dictionary)의 키, 값 기준 정렬은 https://rfriend.tistory.com/473 를 참고하세요. 


데이터 형태마다 정렬 함수, 메소드가 조금씩 달라서 매번 헷갈리곤 합니다. ㅜ_ㅜ

 

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

 

Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 Python의 numpy 라이브러리에 있는 함수들을 이용해서 두 개의 배열(array)을 옆으로 붙이기, 배열을 위 아래로 붙이기(concatenate) 하는 방법에 대해서 소개하겠습니다.  알아두면 편리하게 배열을 조작할 수 있는 유용한 함수들입니다. 


(1) 두 배열을 왼쪽에서 오른쪽으로 붙이기 

   : np.r_[a, b]

   : np.hstack([a, b])
   : np.concatenate((a, b), axis = 0)


(2) 두 배열을 위에서 아래로 붙이기

   : np.r_[[a], [b]]

   : np.vstack([a, b])

   : np.concatenate((c, d), axis = 1) # for 2D ~ array


(3) 두 개의 1차원 배열을 칼럼으로 세로로 붙여서 2차원 배열 만들기

    (Stack 1-D arrays as columns into a 2-D array)

   : np.c_[a, b]

   : np.column_stack([a, b])

   : np.concatenate((c.T, d.T), axis = 1) # for 2D~ array


 [ 배열을 옆으로, 위 아래로 붙이기 : np.r_, np.c_, np.hstack(), np.vstack(), np.column_stack(), np.concatenate(axis=0), np.concatenate(axis=1) ]




처음에 np.r_[a, b], np.c_[a, b] 코드를 봤을 때 '이게 뭐지?', '잘못 타이핑한거 아닌가?', '쓰다 말았나?' 하고 갸우뚱 했던 기억이 납니다. ^^; 


아래에 간단한 예를 들어서 설명하겠습니다. 

np.r_[], np.c_[] 는 코드가 완전 간단한 장점이 있구요, np.hstack(), np.vstack(), np.column_stack() 는 코드 이해가 쉬운 장점이 있는데요, 코드 작성하시는 분의 선호도에 따라 골라 쓰시면 되겠습니다. 


먼저 numpy 라이브러리 importing 한 후에 a, b 두 개의 예제 배열(array)을 만들겠습니다. 



In [1]: import numpy as np


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


In [3]: b = np.array([4, 5, 6])


 



(1) 두 배열을 왼쪽에서 오른쪽으로 붙이기 

   : np.r_[a, b]     <- ( ) 를 사용하지 않고 [ ] 를 사용하는 것에 주의하세요

   : np.hstack([a, b])
   : np.concatenate((a, b), axis=0)


 

 In [4]: np.r_[a, b]

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


 In [7]: np.hstack([a, b])

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


 In [23]: np.concatenate((a, b), axis = 0)

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




(2) 두 배열을 위에서 아래로 붙이기

   : np.r_[[a], [b]]   <- a, b 배열을 [ ]을 사용해서 1-D 배열로 만든거 주의하세요

   : np.vstack([a, b])
   : np.concatenate((c, d), axis = 1<- 1D 배열은 "
AxisError: axis 1 is out of bounds for array of dimension 1"라는 AxisError가 나네요. 2D 이상 배열은 에러 없이 잘 되구요. 



In [5]: np.r_[[a], [b]]

Out[5]:

array([[1, 2, 3],

        [4, 5, 6]])

 


In [8]: np.vstack([a, b])

Out[8]:

array([[1, 2, 3],

        [4, 5, 6]])

 


 In [27]: c = np.array([[0, 1, 2], [3, 4, 5,]])

    ...: d = np.array([[6, 7, 8], [9, 10, 11]])


In [28]: np.concatenate((c, d), axis = 1) # for 2D~ array

Out[28]:

array([[ 0,  1,  2,  6,  7,  8],

        [ 3,  4,  5,  9, 10, 11]])




(3) 두 개의 1차원 배열을 칼럼으로 세로로 붙여서 2차원 배열 만들기

    (Stack 1-D arrays as columns into a 2-D array)

   : np.c_[a, b]

   : np.column_stack([a, b])

   : np.concatenate((c.T, d.T), axis = 1) # for 2D~ array



In [6]: np.c_[a, b]

Out[6]:

array([[1, 4],

        [2, 5],

        [3, 6]])

 


In [9]: np.column_stack([a, b])

Out[9]:

array([[1, 4],

        [2, 5],

        [3, 6]])




np.concatenate(axis=1) 은 1D array 로 하면 AxisError 가 납니다. 2D array 이상에 대해서 사용하세요. 


 In [27]: c = np.array([[0, 1, 2], [3, 4, 5,]])

    ...: d = np.array([[6, 7, 8], [9, 10, 11]])


In [29]: np.concatenate((c.T, d.T), axis = 1)

Out[29]:

array([[ 0,  3,  6,  9],

       [ 1,  4,  7, 10],

       [ 2,  5,  8, 11]])




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

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



Posted by R Friend R_Friend

댓글을 달아 주세요

이번 포스팅에서는 파이썬에서 다차원 배열(array)을 1차원 배열로 평평하게 펴주는 NumPy의 ravel() 함수, flatten() 함수에 대해서 알아보겠습니다. 


1차원 배열을 다차원 배열로 재구성/재배열 해주는 NumPy의 reshape() 함수와 반대의 기능을 하는 함수가 ravel(), flatten() 함수라고 보시면 되겠습니다. 


기계학습 알고리즘 학습하다보면 가끔씩 ravel() 함수가 나오는데요, 이참에 order 옵션 'C', 'F', 'K' 별 기능에 대해서도 정리해서 알아두면 좋을 듯 합니다. 


[ Python NumPy ravel() 함수 vs. reshape() 함수 ]




-- 2차원 배열 -- 


먼저 0 ~ 11 까지의 12개의 원소로 이루어진 3 x 4 배열을 만들어 보겠습니다.  



In [1]: import numpy as np

   ...: x = np.arange(12).reshape(3, 4)

   ...: x

   ...:

Out[1]:

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

        [ 4, 5, 6, 7],

        [ 8, 9, 10, 11]])




위에서 만든 2차원 배열에 대해서 order='C', order='F', order='k'별로 순서대로 위의 배열 3*4 배열 x가 어떤 순서대로 평평하게 펴지는지 예제로 살펴보겠습니다. 


(1) np.ravel(x, order='C') : C와 같은 순서로 인덱싱하여 평평하게 배열 (디폴트)



In [2]: np.ravel(x, order='C') # by default

   ...:

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

 




(2) np.ravel(x, order='F') : Fortran과 같은 순서로 인덱싱하여 평평하게 배열



In [3]: np.ravel(x, order='F')

   ...:

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

 




 (3) np.ravel(x, order='K') : 메모리에서 발생하는 순서대로 인덱싱하여 평평하게 배열



In [4]: np.ravel(x, order='K')

   ...:

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





-- 3차원 배열 -- 


3차원 이상의 배열에 대해서도 ravel() 함수를 사용해서 1차원 배열로 평평하게 펼 수가 있습니다. 이때 order 매개변수를 설정해줄 때 조금 주의가 필요합니다. 아래에 2*3*2 의 3차원 배열에 대해서 축이 어떻게 설정되어있느냐(배열 순서가 어떤가)에 따라서 order='C'와 order='K'를 선택해서 사용하면 되겠습니다. 


(4) np.raver(y, order='C') : 3차원 배열의 평평하게 펴기



In [5]: y = np.arange(12).reshape(2, 3, 2)

   ...: y

Out[5]:

array([[[ 0, 1],

         [ 2, 3],

         [ 4, 5]],


        [[ 6, 7],

         [ 8, 9],

         [10, 11]]])

 



In [6]: np.ravel(y, order='C')

   ...:

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

 




 (5) np.ravel(z, order='K') : 축이 바뀐 3차원 배열을 평평하게 펴기



In [7]: z = np.arange(12).reshape(2, 3, 2).swapaxes(1, 2)


In [8]: z

Out[8]:

array([[[ 0, 2, 4],

         [ 1, 3, 5]],


        [[ 6, 8, 10],

         [ 7, 9, 11]]])

 



In [9]: np.ravel(z, order='K')

   ...:

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

 



이상으로 다차원 배열을 1차원 배열로 평평하게 펴주는 numpy.ravel(a, order='C', 'F', 'K') 함수에 대해서 알아보았습니다. 


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

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



Posted by R Friend R_Friend

댓글을 달아 주세요

파이썬 NumPy 에서 배열의 차원(Dimension)을 재구조화, 변경하고자 할 때 reshape() 메소드를 사용합니다.  가령, 3개의 행과 4개의 열로 구성된 2차원의 배열로 재설정하고 싶으면 reshape(3, 4) 처럼 reshape()의 매개변수로 변경하고자 하는 배열의 행과 열의 차원을 정수로 입력해주면 됩니다. 


그런데 reshape(-1, 2) 혹은 reshape(3, -1) 처럼 reshape() 메소드 안에 '-1'이 들어가 있는 경우가 있습니다. 이때 reshape()의 '-1'이 의미하는 바는, 변경된 배열의 '-1' 위치의 차원은 "원래 배열의 길이와 남은 차원으로 부터 추정"이 된다는 뜻입니다. (One shape dimension can be -1. In this case, the value is inferred from the length of the array and remaining dimensions.)


말이 좀 어렵고, 금방 이해하기가 쉽지 않은데요, ^^; 아래에 간단한 예를 들어서 설명해보겠습니다. 


먼저 NumPy 라이브러리를 import 하고 3x4 차원의 예제 배열을 만들어보겠습니다. 

(우리가 일상적으로 사용하는 reshape() 의 사용 예제)



In [1]: import numpy as np


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


In [3]: x.shape

Out[3]: (3, 4)


In [4]: x

Out[4]:

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

        [ 4, 5, 6, 7],

        [ 8, 9, 10, 11]])

 



  (1) reshape(-1, 정수) 의 행(row) 위치에 '-1'이 들어있을 경우


이제 reshape() 의 행(row) 차원 위치에 '-1'을 넣으면 어떻게 재구조화가 되는지 살펴보겠습니다. 

총 12개의 원소가 들어있는 배열 x에 대해서 x.reshape(-1, 정수) 를 해주면 '열(column)' 차원의 '정수'에 따라서 12개의 원소가 빠짐없이 배치될 수 있도록 '-1'이 들어가 있는 '행(row)' 의 개수가 가변적으로 정해짐을 알 수 있습니다.  


x.reshape(-1, 1)

=> shape(12,1)

x.reshape(-1, 2

=> shape(6, 2)

 x.reshape(-1, 3)

=> shape(4, 3)

x.reshape(-1, 4

=> shape(34)

 

In [5]: x.reshape(-1, 1)

Out[5]:

array([[ 0],

        [ 1],

        [ 2],

        [ 3],

        [ 4],

        [ 5],

        [ 6],

        [ 7],

        [ 8],

        [ 9],

        [10],

        [11]])


 In [6]: x.reshape(-1, 2)

Out[6]:

array([[ 0, 1],

        [ 2, 3],

        [ 4, 5],

        [ 6, 7],

        [ 8, 9],

        [10, 11]])







 In [7]: x.reshape(-1, 3)

Out[7]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])









 In [8]: x.reshape(-1, 4)

Out[8]:

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

        [ 4, 5, 6, 7],

        [ 8, 9, 10, 11]])













  (2) reshape(정수, -1) 의 열(column) 위치에 '-1'이 들어있을 경우


다음으로 reshape()의 열(column) 위치에 '-1'을 넣으면 어떻게 재구조화되는지 살펴보겠습니다. 

x의 총 원소 12개가 모두 배열될 수 있도록 행(row)의 정수가 정해지면, 이에 따라서 '-1'이 들어있는 열(column)의 개수가 정해짐을 알 수 있습니다. 


즉, 행이나 열의 특정 차원을 기준으로 재배열하고 싶은 행이나 열의 개수가 있으면 나머지 차원의 개수는 '-1'로 해두면 알아서 자동으로 재배열을 해주니 편리한 기능이라고 하겠습니다. 


x.reshape(1, -1)

  => shape(1, 12)

 

In [9]: x.reshape(1, -1)

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


 x.reshape(2, -1)

  => shape(2, 6)

 

In [10]: x.reshape(2, -1)

Out[10]:

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

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


 x.reshape(3, -1)

  => shape(3, 4)

 

In [11]: x.reshape(3, -1)

Out[11]:

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

        [ 4, 5, 6, 7],

        [ 8, 9, 10, 11]])


 x.reshape(4, -1)

  => shape(4, 3)


In [12]: x.reshape(4, -1)

Out[12]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])





  (3) reshape(-1) 인 경우


x.reshape(-1)은 x.reshape(1, -1)과 같이 1차원 배열을 반환합니다. 


x.reshape(-1)

 

In [13]: x.reshape(-1)

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


 x.reshape(1, -1)

 

x.reshape(1, -1)

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





  (4) ValueError: cannot reshape array of size 12 into shape (5)


reshape(-1, 정수) 또는 reshape(정수, -1) 메소드가 제대로 작동하기 위해서는 한가지 조건이 있는데요, 원래의 배열에 있는 원소가 재구조화 혹은 재배열 되려는 배열의 차원에 빠짐없이 분배가 될 수 있어야 한다는 점입니다.  


가령, 위의 (1), (2), (3)번 예에서는 12개의 원소로 구성된 x배열을 (1, 12), (2, 6), (3, 4), (4, 3) 으로 재배열했었습니다. 하지만 아래의 ValueError 가 난 것처럼 12개의 원소로 구성된 원래의 배열 x에 대해 x.reshape(-1, 5) 혹은 x.reshape(7, -1) 로 재구조화하려고 하면 서로 호환이 안되기 때문에 ValueError가 난 것입니다. 



In [15]: x.reshape(-1, 5)

Traceback (most recent call last):


File "<ipython-input-15-3341ca33497d>", line 1, in <module>

x.reshape(-1, 5)


ValueError: cannot reshape array of size 12 into shape (5)

In [16]: x.reshape(7, -1)

Traceback (most recent call last):


File "<ipython-input-16-c8e97ae7c9bc>", line 1, in <module>

x.reshape(7, -1)


ValueError: cannot reshape array of size 12 into shape (7,newaxis)

 




  (5) ValueError: can only specify one unknown dimension


reshape(-1, -1)은 행, 열 어느 차원도 정해주지 않았으므로 ValueError 가 발생합니다. 



In [17]: x.reshape(-1, -1)

Traceback (most recent call last):


File "<ipython-input-17-8142d87a8f95>", line 1, in <module>

x.reshape(-1, -1)


ValueError: can only specify one unknown dimension

 



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


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



Posted by R Friend R_Friend

댓글을 달아 주세요

그동안 Python NumPy의 단일 배열 unary ufuncs 에 대해서 알아보았습니다.

(http://rfriend.tistory.com/300, http://rfriend.tistory.com/301)

 

이번 포스팅에서는 그동안 배웠던 unary ufuncs 들을 요리조리 조합하고 응용하는 한가지 예를 들어보겠습니다.

 

- 절대값을 구하는 함수 np.abs(x)

- 배열 원소의 부호를 판별하는 np.sign(x) 함수

- 배열의 1개 이상의 원소가 참(True) 인지 평가하는 np.any(x) 함수

 

를 이용해서 특이값, 이상치(outlier)를 탐색하고, indexing해서 다른 값으로 대체하는 방법을 소개하겠습니다.

 

 

먼저 numpy, pandas, matplotlib.pyplot 모듈을 불러오고, 평균이 0, 표준편차가 1인 정규분포로 부터 난수 10,000만개를 생성해보겠습니다.

 

 

In [1]: import numpy as np

   ...: import pandas as pd

   ...: import matplotlib.pyplot as plt

   ...:


In [2]: np.set_printoptions(precision=2)

   ...:

   ...: # setting random seed number

   ...: np.random.seed(10)

   ...:

   ...: # random number 10000 ~ N(0, 1)

   ...: mu, sigma = 0, 1

   ...: x = pd.DataFrame(mu + sigma*np.random.randn(10000))

 

 

 

 

다음으로 dexcribe() 메서드를 사용해서 x의 기술통계량을 알아보고, 히스토그램으로 분포를 살펴보겠습니다. min과 max 값을 보면 평균 0을 중심으로 해서 -3 (-3 sigma)과 +3 (+3 sigma)을 벗어나는 관측치가 있음을 알 수 있습니다.

 

 

# checking descriptive statistics and histogram

In [3]: x.describe()

Out[3]:

0

count 10000.000000

mean 0.005102

std 0.989713

min -3.621639

25% -0.652208

50% 0.013111

75% 0.675040

max 3.691489


In [4]: plt.hist(x)

Out[4]:

(array([ 15., 139., 583., 1626., 2733., 2679., 1606., 497.,

107., 15.]),

array([-3.62, -2.89, -2.16, ..., 2.23, 2.96, 3.69]),

<a list of 10 Patch objects>)

 

 

 

 

 

정규분포를 띠는 데이터셋의 경우 평균으로 부터 +3 sigma, -3 sigma 를 벗어나는 데이터의 경우 전체 데이터셋 중 99%가 존재하는 구간을 벗어나는 특이값, 이상값(outlier)로 간주할 수 있습니다.

 

이번 예제에서 x는 평균이 '0'이고 표준편차가 '1'인 정규분포를 따르므로, np.abs(x)와 any(1) 함수를 조합해서 사용하면 1만개의 관측치를 가지는 x로부터 +- 3 sigma를 벗어나는 특이값만 쏙 빼올 수 있습니다.  count() 메소드로 특이값 개수도 세볼 수 있구요.

 

 

# indexing outlier rows over mu + 3sigma, less mu - 3 sigma

In [5]: x[(np.abs(x) > 3).any(1)]

   ...:

Out[5]:

0

412 -3.204401

1036 -3.317669

1558 -3.112645

2190 3.609161

3948 3.454845

4912 -3.372347

5016 -3.393109

5158 3.193371

5618 3.177053

5750 3.158873

6135 3.077068

6303 3.142285

6689 -3.621639

6760 3.027240

6986 -3.303552

7353 -3.214030

7892 3.561219

8281 3.691489

9179 3.286370

9335 3.503309

 

# counting the number of outliers

In [6]: x[(np.abs(x) > 3).any(1)].count()

Out[6]:

0 20

dtype: int64

 

 

 

 

이번에는 np.sign(x) 함수를 곁들여 사용하여 +- 3 sigma를 벗어나는 관측치값을 모두 +-3 으로 대체해보겠습니다. (즉, +3 sigma보다 큰 특이값은 +3으로 대체, -3 sigma 보다 작은 특이값은 -3으로 대체) 

 

x.describe()로 요약통계량을 살펴보니 min -3, max 3으로 바뀌었지요? 히스토그램도 -3 ~ +3 까지 분포로 바뀌었구요.

 

 

In [7]: x[np.abs(x) > 3] = np.sign(x)*3


In [8]: x[(np.abs(x) >= 3).any(1)]

Out[8]:

0

412 -3.0

1036 -3.0

1558 -3.0

2190 3.0

3948 3.0

4912 -3.0

5016 -3.0

5158 3.0

5618 3.0

5750 3.0

6135 3.0

6303 3.0

6689 -3.0

6760 3.0

6986 -3.0

7353 -3.0

7892 3.0

8281 3.0

9179 3.0

9335 3.0


In [9]: x.describe()

Out[9]:

0

count 10000.000000

mean 0.004968

std 0.987624

min -3.000000

25% -0.652208

50% 0.013111

75% 0.675040

max 3.000000


In [10]: plt.hist(x)

Out[10]:

(array([ 76., 292., 755., 1554., 2269., 2299., 1648., 762.,

277., 68.]),

array([-3. , -2.4, -1.8, ..., 1.8, 2.4, 3. ]),

<a list of 10 Patch objects>)

 

 

 

통계 분포 방법 외에 특이값 찾는 방법이 서너가지 더 있는데요, 그건 다음번에 기회 될 때 별도로 포스팅을 하겠습니다. (언제가 될지는 기약 못하겠네요. ^^;)

 

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

 

Posted by R Friend R_Friend

댓글을 달아 주세요