함수(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

이번 포스팅에서는 Python의 for loop 반복문에서 사용할 수 있는 일정 간격, 혹은 일정 개수의 수를 생성하는 함수를 소개하겠습니다.

 

(1) range() 함수

   : start, stop, step 을 인수로 받아 일정 간격의 정수 생성

 

(2) enumerate() 함수

   : 순서가 있는 자료형(리스트, 튜플, 문자열)을 인수로 받아 인덱스(index)를 포함하는 객체를 반환

 

(3) np.linspace() 함수

   : start, stop, num 을 인수로 받아 일정 개수/간격의 샘플을 반환

 

(4) linrange() 사용자정의 함수

  : start, stop, step 을 인수로 받아 일정 간격의 샘플을 반환

 

 

[ Python의 for loop 문에 사용할 수 있는 함수들 예시 ]

 

 

 

 (1) range() : start, stop, step 을 인수로 받아 일정 간격의 정수 생성

 

for loop 문을 작성할 때 일반적으로 같이 사용하는 함수가 range() 함수 입니다. 3개의 parameter 값을 입력받게 되는데요, range(start, stop, step) 의  

 - start : 순열의 처음 시작하는 수

 - end : 순열의 끝나는 수, 단 이 숫자는 포함하지 않음

 - step : 순열 안의 각 숫자들 간의 간격

을 의미합니다.

  • 1개의 parameter 만을 입력하는 경우 그 수는 end 의 값으로 인식되며(해당 값은 미포함), start=0, step=1 의 디폴트 값이 자동으로 설정됩니다.  

# One parameter

In [1]: for i in range(10):

   ...: print(i)

   ...:

   ...:

0

1

2

3

4

5

6

7

8

9

 

 

  • 2개의 parameter를 입력하는 경우, 각 값은 start와 end 로 인식되고, step=1 로 자동 설정됩니다.

# Two parameters

In [2]: for i in range(5, 10):

   ...: print(i)

   ...:

   ...:

5

6

7

8

9

 

 

  • 3개의 parameter를 입력하는 경우, 각 값은 start, end, step의 값이 됩니다. end에 입력한 값은 포함되지 않는 다는 점에 주의하세요.

# Three parameters

In [3]: for i in range(0, 10, 2):

   ...: print(i)

   ...:

   ...:

0

2

4

6

8

 

 

  • step 위치에 음수(-) 값을 입력하면 그 수만큼 줄어드는 방향으로 순열을 생성합니다.

# Going backwards

In [4]: for i in range(5, -5, -2):

   ...: print(i)

   ...:

   ...:

5

3

1

-1

-3

 

 

  • List 에 대해서도 len() 함수로 리스트 안의 원소 개수를 파악하고 range() 함수를 적용하여 for loop으로 List 안의 원소를 indexing 해오는 반복문을 만들 수 있습니다.

 

In [5]: my_list = ['a', 'b', 'c', 'd', 'e']

   ...: for i in range(0, len(my_list)):

   ...: print(my_list[i])

   ...:

   ...:

a

b

c

d

e

 

 

 

 

 (2) enumerate() : 순서가 있는 자료형(리스트, 튜플, 문자열)을 인수로 받아
                         인덱스(index)를 포함하는 객체를 반환

 

enumerate() 함수는 아래의 예제처럼 객체의 index 를 파악하고자 할 때 사용하면 매우 유용합니다.

 

 

In [6]: name_list = ['Lee', 'Kim', 'Park', 'Choi']

   ...: for i, name in enumerate(name_list):

   ...: print(i+1, name)

   ...:

   ...:

(1, 'Lee')

(2, 'Kim')

(3, 'Park')

(4, 'Choi')

 

 

 

아래의 예제처럼 enumerate()와 format() 함수를 적절히 같이 사용하면 꽤 쓸만합니다.

 

 

In [7]: for i, name in enumerate(name_list):

   ...: print("idx: {} , name: {} ".format(i+1, name))

   ...:

   ...:

idx: 1 , name: Lee

idx: 2 , name: Kim

idx: 3 , name: Park

idx: 4 , name: Choi

 

 

 

 

 (3) np.linspace() : start, stop, num 을 인수로 받아 일정 개수/간격의 샘플을 반환

 

numpy 패키지의 linspace() 함수는 그래프의 x 축 설정할 때나 혹은 for loop을 써서 시뮬레이션 할 때 꽤 자주 사용하는 편입니다. start, stop, num 의 세 개의 parameter를 입력받아 num 개수, 일정 간격의 샘플을 반환합니다.

 

 - start : 순열의 시작 값

 - stop : 순열의 끝 값, endpoint=True가 기본 설정, 만약 endpoint=False인 경우 미포함

 - num : 생성되는 샘플의 개수

 

  • endpoint=True 가 기본값으로 설정 (stop 값을 포함하여 num 개수만큼의 등간격 순열 생성)

# endpoint=True (default setting)

In [8]: import numpy as np

   ...: np.linspace(start=0, stop=10, num=5)

   ...:

Out[8]: array([ 0. , 2.5, 5. , 7.5, 10. ])

 

 

 

  • retstep=True 를 설정하면 각 샘플 간의 간격을 배열 다음에 표시해줍니다.

# retstep: If True, return (samples, step), where step is the spacing between samples.

In [9]: np.linspace(start=0, stop=10, num=5, retstep=True)

   ...:

Out[9]: (array([ 0. , 2.5, 5. , 7.5, 10. ]), 2.5)

 

 

  • endpoint=False 를 설정하면 stop 매개변수값을 포함하지 않은 등간격의 num 개수 샘플을 생성합니다.
# endpoint: If True, stop is the last sample. Otherwise, it is not included. Default is True.

In [10]: np.linspace(start=0, stop=10, num=5, retstep=True, endpoint=False)

    ...:

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

 

 

 

  • for loop 반복문에 np.linspace() 사용한 예제

 

In [11]: for i in np.linspace(start=0, stop=10, num=5):

    ...: print(i)

    ...:

    ...:

0.0

2.5

5.0

7.5

10.0

 

 

 

 

 (4) linrange() 사용자정의 함수 : start, stop, step을 인수로 받아 일정 간격의 샘플 반환

 

위의 (3)번에서 소개한 np.linspace() 함수를 응용하여 일정 간격(step) 의 샘플을 생성해주는 linrange() 사용자정의 함수를 소객합니다. (1)번의 range() 함수와 매우 유사하긴 한데요, stop 값이 포함되어서 step 만큼의 간격으로 순열을 생성해주는게 조금 다릅니다.

 

 

In [12]: def linrange(start=0, stop=1, step=1):

    ...: n = np.round((stop - start) / step)

    ...: array = np.linspace(start, stop, int(n+1)) # endpoint=True

    ...: return array

    

In [13]: for i in linrange(start=0, stop=10, step=2):

    ...: print(i)

    ...:

    ...:

0.0

2.0

4.0

6.0

8.0

10.0

 

 

 

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

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

 

 

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