함수(function)는 input을 받아서 특정 과업(들)을 수행하여 output을 반환하도록 짜여진, 잘 조직되고 재사용이 가능한 코드 블록을 말합니다.

 

그동안 파이썬의 내장형 함수(Built-in function), 여러 라이브러리의 함수에 대해서 소개를 했었는데요, 이번 포스팅부터는 사용자가 직접 함수를 정의해서 사용할 수 있는 '사용자 정의 함수 (User-Defined Function, UDF)' 에 대해서 소개하겠습니다.

 

[ 사용자 정의 함수의 유용성 ]

* 사용자 정의 함수를 재사용(reusable)할 수 있습니다.
* 코드를 구조화, 모듈화(modularization) 함으로써 관리하기 쉽습니다.
* 사용자 정의 함수를 사용하여 코드를 간결하게 하고 가독성을 높일 수 있습니다.
* 사용자 정의 함수를 분산해서 개별적으로 작성할 수 있으므로 애플리케이션 개발 속도를 높일 수 있습니다.


사용자 정의 함수는 (1) 사용자 정의 함수의 정의 (Definition), (2) 호출 (Call), (3) 반환 (Return) 의 절차를 따라서 이용할 수 있습니다.

 

 

사용자 정의함수를 정의(define) 할 때는

  • 첫 줄에는 def 로 시작하며
  • 사용자 정의 함수 이름을 쓰고,
  • 괄호 안에는 매개변수 목록을 쓰며,
  • 콜론(:)을 써줍니다.
  • 다음줄 부터는 들여쓰기(indentation)을 꼭 해주어야 하며,
  • 따옴표 세개("""함수 설명""")로 함수에 대한 부가 설명(Docstring)을 넣어주고 (optional)
  • 실행하고자 함는 작업에 대해서 코드블록을 작성합니다.
  • 마지막에 return 뒤에 반환하고자 하는 결과값을 써주면 됩니다.
  • 반환할 값이 없으면 return 은 생략 가능합니다.

 

(1) 숫자를 input으로 받아서 평균을 반환하는 간단한 사용자 정의 함수를 정의(define)해보겠습니다.

 

 

def my_avg(x1, x2):

    avg_val = (float(x1) + float(x2))/2

   

    return avg_val

 

 

 

(2) 위에서 만든 my_avg() 라는 사용자 정의 함수를 호출(call)하여 (2, 3), (2, 4) 의 두 쌍의 숫자들의 평균을 반환(return) 해보겠습니다.

 

 

In [2]: avg_val = my_avg(2, 3)


In [3]: avg_val

Out[3]: 2.5

 

In [4]: my_avg(2, 4)

Out[4]: 3.0

 

 

 

큰 따옴표 세개(""" Docstring """)로 사용자 정의 함수를 설명하는 Docstring을 추가하고, ?함수이름으로 Docstring을 불러와서 참고해보겠습니다.

 

 

def my_avg(x1, x2):

    """

    This function calculates average value of two numbers

    x1: first input number

    x2: second input number

    """

    avg_val = (float(x1) + float(x2))/2

 

    return avg_val


 

In [6]: ?my_avg()

Signature: my_avg(x1, x2)

Docstring:

This function calculates average value of two numbers

x1: first input number

x2: second input number

File: c:\users\admin\<ipython-input-5-d14cc1c6028b>

Type: function

 

 

 

사용자 정의 함수의 코드 블록에 if ~ else 조건문을 추가하여 좀더 복잡한 작업을 할 수도 있습니다. 위의 두 숫자를 input으로 받아서 평균을 반환하는 사용자 정의 함수에다가 '정수(integer) 혹은 부동소수형(float)'이 아니면 "This is not a number" 라는 메시지를 반환하도록 하는 조건문 코드를 추가해보겠습니다.

 

사용자정의함수와 조건문을 같이 쓰므로 콜론(:)으로 코드블록이 시작됨을 알려주고 들여쓰기(indentation)에 주의를 기울여야 합니다.

 

 

def my_avg(x1, x2):

    """

    This function calculates average value of two numbers

    x1: first input number

    x2: second input number

    """

    

    if isinstance(x1, (int, float)) and isinstance(x2, (int, float)):

        avg_val = (float(x1) + float(x2))/2

        return avg_val

    else:

        print("This is not a number")

      


In [8]: my_avg(2, 5)

Out[8]: 3.5


In [9]: my_avg('2', 5)

This is not a number

 

 

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

 

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  을 참고하시기 바랍니다.


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

 

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

 

Posted by R Friend R_Friend

이번 포스팅에서는 Python numpy 의 메소드, 함수 중에서 


- 최소값, 최대값, 혹은 조건에 해당하는 색인(index) 값을 찾기 

   : np.argmin(), np.argmax(), np.where()


- 최소값, 최대값, 혹은 조건에 맞는 값 찾기 

   : np.min(), np.max(), x[np.where()]


에 대해서 소개하겠습니다. 


분석할 때 꽤 많이 사용되므로 기억해두시면 좋겠습니다. 





  (1) 최소값(min), 최대값(max): np.min(), np.max()


x.min(), np.min(x), min(x) 모두 동일한 결과를 반환합니다. 



In [1]: import numpy as np


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


In [3]: x.min()

Out[3]: 0


In [4]: np.min(x)

Out[4]: 0


In [5]: x.max()

Out[5]: 5


In [6]: np.max(x)

Out[6]: 5

 




  (2) 최소값, 최대값의 색인 위치: np.argmin(), np.argmax()



In [7]: x.argmin()

Out[7]: 5


In [8]: np.argmin(x)

Out[8]: 5


In [9]: x.argmax()

Out[9]: 0


In [10]: np.argmax(x)

Out[10]: 0

 




  (3) 조건에 맞는 값의 색인 위치: np.where()


배열에서 3과 같거나 큰 값을 가지는 색인의 위치를 알고 싶을 때, 


 

In [11]: np.where(x >= 3)

Out[11]: (array([0, 1, 2], dtype=int64),)




(4) 조건에 맞는 값을 indexing 하기: x[np.where()] 


배열에서 3과 같거나 큰 값을 indexing 하고 싶을 때, 



In [12]: x[np.where(x >= 3)]

Out[12]: array([5, 4, 3])

 




  (5) 조건에 맞는 값을 특정 다른 값으로 변환하기

     : np.where(조건, 조건에 맞을 때 값, 조건과 다를 때 값)


배열의 값이 3과 같거나 크면 3으로 변환하고, 3보다 작으면 그대로 값을 유지하고 싶을 때, 

(for loop & if else 조건문을 사용하는 것보다 수십배 빠르므로 매우 유용함)



In [13]: np.where(x >= 3, 3, x)

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

 


 

참고로, 위의 np.where를 사용한 배열 값 변환을 for loop & if else 조건문을 사용해서 써보면 아래와 같습니다. for loop은 데이터 사이즈가 커질 경우 속도가 매우 느려지므로, 위의 대용량 데이터는 벡터화된 연산을 하는 np.where() 함수 사용을 권합니다. .

 

 

In [14]: x_2 = []

    ...: for i in list(x):

    ...: if i >= 3:

    ...: x_2.append(3)

    ...: else:

    ...: x_2.append(i)

    ...:

    ...:


In [15]: x_2 = np.asarray(x_2)


In [16]: type(x_2)

Out[16]: numpy.ndarray


In [17]: x_2

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

 

 

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

 

Posted by R Friend R_Friend

이번 포스팅에서는 Python numpy 의 집합함수(set functions)에 대해서 알아보겠습니다.

 

한 개, 혹은 두 개의 1차원 ndarray 집합에 대해서

 

(1) unique(x) : 배열 내 중복된 원소 제거 후 유일한 원소를 정렬하여 반환
(2) intersect1d(x, y) : 두 개의 배열 x, y 의 교집합을 정렬하여 반환
(3) union1d(x, y) : 두 개의 배열 x, y의 합집합을 정렬하여 반환
(4) in1d(x, y) : 첫번째 배열 x가 두번째 배열 y의 원소를 포함하고 있는지 여부의 불리언 배열을 반환
(5) setdiff1d(x, y) : 첫번째 배열 x로 부터 두번째 배열 y를 뺀 차집합을 반환
(6) setxor1d(x, y) : 두 배열 x, y의 합집합에서 교집합을 뺀 대칭차집합을 반환

 

해주는 다양한 집합함수가 있습니다.

 

[ Python numpy 집합 함수 (set functions) ]

 

 

 

순서대로 예를 들어서 설명하겠습니다.  위의 벤다이어그램을 참고하시기 바랍니다.

 

 (1) np.unique(x) : 배열 내 중복된 원소 제거 후 유일한 원소를 정렬하여 반환

 

 

In [1]: import numpy as np


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


In [3]: np.unique(x)

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

 

 

참고로, pure python의 sorted(set(x)) 와 np.unique(x) 는 동일합니다.

 

In [4]: sorted(set(x))

Out[4]: [1, 2, 3, 4]

 

 

 

 

 

 (2) np.intersect1d(x, y) : 두 개의 배열 x, y 의 교집합을 정렬하여 반환

 

 

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


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


In [7]: np.intersect1d(x, y)

Out[7]: array([3, 4])

 

 

 

 

 (3) np.union1d(x, y) : 두 개의 배열 x, y의 합집합을 정렬하여 반환

 

 

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


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


In [10]: np.union1d(x, y)

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

 

 

 

 

 (4) np.in1d(x, y) : 첫번째 배열이 두번째 배열의 원소를 포함하고 있는지 여부의

                         불리언 배열을 반환

 

 

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


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


In [13]: np.in1d(x, y)

Out[13]: array([False, True, False, True, False, False])

 

 

 

 

 (5) np.setdiff1d(x, y) : 첫번째 배열 x로 부터 두번째 배열 y를 뺀 차집합을 반환

 

 

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


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


In [16]: np.setdiff1d(x, y)

Out[16]: array([1, 2])

 

 

 

 

 (6) np.setxor1d(x, y) : 두 배열 x, y의 합집합에서 교집합을 뺀 대칭차집합을 반환

 

 

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


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


In [19]: np.setxor1d(x, y)

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

 

 

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

Posted by R Friend R_Friend

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


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

   : np.r_[a, b]

   : np.hstack([a, b])


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

   : np.r_[[a], b]

   : np.vstack([a, b])


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

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

   : np.c_[a, b]

   : np.column_stack([a, b])



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




처음에 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])


 

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



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

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

   : np.vstack([a, b])



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

 



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

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

   : np.c_[a, b]

   : np.column_stack([a, b])



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



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

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



Posted by R Friend R_Friend

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


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


기계학습 알고리즘 학습하다보면 가끔씩 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

외국의 블로그에 소프트엔지니어 채용 과정 중에 코딩 인터뷰에서 있을 법한 문제로 회자되는 "FizzBuzz" 문제가 있습니다. 


"FizzBuzz"문제는 


 - 1에서 100까지의 숫자를 출력하되, 

 - 만약 해당 숫자가 '3'으로 나누어지면 숫자 대신에 "Fizz"를 출력하고, 

 - 만약 해당 숫자가 '5'로 나누어지면 숫자 대신에 "Buzz"를 출력하며, 

 - 만약 해당 숫자가 '3'과 '5'로 모두 나누어지면 숫자 대신에 "FizzBuzz"를 출력


하는 코드는 짜라는 것입니다.  


1~100까지 하기에는 좀 길기 때문에 1~30까지의 숫자에 대해서만 FizzBuzz 문제를 풀어보면 아래의 Original -> FizzBuzz 변환 전/후 비교를 보시면 이해가 쉬울 것입니다. 




위의 FizzBuzz 문제를 푸는 방법이 여러가지가 있을 수 있을 텐데요, (1) if, elif, else 조건문 사용, (2) if, elif, else 조건문을 포함한 사용자 정의 함수, (3) 문자열 합치기 (concatenating strings) 의 세 가지 방법을 소개합니다. 



  (1) if, elif, else 조건문을 사용한 FizzBuzz 코딩



# (1) if, elif, and else

for num in range(1, 31):

    if num % 3 == 0 and num % 5 == 0:

        print('FizzBuzz')

    elif num % 3 == 0:

        print('Fizz')

    elif num % 5 == 0:

        print('Buzz')

    else:

        print(num)

 




  (2) if, elif, else 조건문과 사용자 정의 함수(UDF)을 사용한 FizzBuzz 코딩


사용자 정의 함수에 대해서는 조만간 포스팅 하겠습니다. ^^



# (2) User Defined Function

def fizzbuzz(num):

    if num % 3 == 0 and num % 5 == 0:

        return 'FizzBuzz'

    elif num % 3 == 0:

        return 'Fizz'

    elif num % 5 == 0:

        return 'Buzz'

    else:

        return str(num)

    

print("\n".join(fizzbuzz(num) for num in range(1, 31)))

 




  (3) 문자열 합치기(Concatenating Strings)을 이용한 FizzBuzz 코딩



# (3) Concatenating Strings

for num in range(1, 31):

    string = ""

    if num % 3 == 0:

        string = string + "Fizz"

    if num % 5 == 0:

        string = string + "Buzz"

    if num % 5 != 0 and num % 3 != 0:

        string = string + str(num)

    print(string)

 



아래 링크는 취업 인터뷰에서 FizzBuzz 코딩 문제를 듣고서 Tensorflow로 딥러닝 모형을 적용했다가 취업 실패했다는 (가상의?) 블로그 내용입니다.  


Fizz Buzz in Tensorflow (http://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow/)


간단한 '주먹지르기'로 해결할 수 있는 문제를 단지 '최신 유행'하는 기술이라는 이유만으로  '공중 3회전 날아 뒤돌아 발 차고 손목날로 목 가로지르기' 기술을 적용할 필요가 있는가에 대해서 우스개 (가상?) 사례로 소개한 포스팅인 듯 합니다.  Interviewer 의 반응을 유심히 보면서... 인터뷰 과정을 한번 보시는 것도 재미있을 것 같습니다. ㅋㅋ


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

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



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