지난번 포스팅에서는 파이썬의 사용자 정의 함수를 사용하면 좋은 점, 함수를 정의하고 호출하는 기본 문법과 예제를 다루었습니다. 


이번 포스팅에서는 파이썬 함수의 입력(input) 값을 받아서 함수가 정의된 작업을 할 수 있도록 해주는 매개변수(Arguments)에 대해서 알아보겠습니다. 


함수를 호출하는데 사용하는 파이썬의 매개변수에는 아래의 4가지 유형이 있습니다. 

  • 위치 매개변수 (Positional Arguments)
  • 키워드 매개변수 (Keyword Arguments)
  • 기본값 매개변수 (Default Arguments)
  • 가변 매개변수 (Arbitrary Arguments)




이중에서 위치, 키워드, 기본값 매개변수까지만 이번 포스팅에서 소개하고, 가변 매개변수는 다음번 포스팅에서 소개하겠습니다. 



  위치 매개변수 (Positional Arguments)


위치 매개변수(Positional Arguments)는 함수 내 매개변수의 위치별 순서와 데이터 타입에 맞게 정확하게 입력을 해주어야만 하는 매개변수를 말합니다.  아래에 '2개'의 숫자를 매개변수로 받아서 평균을 계산해주는 my_avg() 라는 함수가 있다고 했을 때, 입력 매개변수로 '1개'의 숫자만을 입력받게 되었을 때 'TypeError: my_avg() takes exactly 2 arguments (1 given)' 이라는 에러 메시시가 떴습니다. 



In [1]: def my_avg(x1, x2):

   ...: avg_val = (x1 + x2)/ 2

   ...: return avg_val


In [2]: my_avg(2, 4)

Out[2]: 3


In [3]: my_avg(2) # TypeError

Traceback (most recent call last):


File "<ipython-input-3-69b7a0a22718>", line 1, in <module>

my_avg(2)


TypeError: my_avg() takes exactly 2 arguments (1 given)

 




  키워드 매개변수 (Keyword Arguments)


키워드 매개변수는 함수 호출과 관련이 있는데요, 키워드 매개변수를 이용하여 프로그래머는 함수를 호출할 때 매개변수의 이름(parameter name)으로 매개변수를 지정합니다. 


키워드 매개변수를 이용하면 함수를 정의할 때 썼던 매개변수의 입력 순서를 바꾸어서 함수를 호출할 수도 있으며, 코드 가독성도 높아지는 좋은 점이 있습니다. 


아래에 회사명(company)과 임직원 이름(name)을 출력하는 함수로 예를 들어보았습니다. 두번째 호출 예시에서 매개변수 순서를 바꾸어서 입력했음에도 불구하고 출력은 함수에서 정의했던 순서대로 출력되었음을 알 수 있습니다. 



# Keyword Arguments : The caller identifies the arguments by the parameter name

In [4]: def print_me(company, name):

   ...: print("Company : ", company)

   ...: print("Name : ", name)


In [5]: print_me(company="ABCD Co.", name="Mr.Jack")

('Company : ', 'ABCD Co.')

('Name : ', 'Mr.Jack')


# The order of parameters does not matter

In [6]: print_me(name="Mr.Jack", company="ABC Co.")

('Company : ', 'ABC Co.')

('Name : ', 'Mr.Jack')

 



만약 키워드 매개변수를 이용하지 않는 다면 입력 순서와 데이터 타입을 꼭 함수에서 정의한 순서와 맞추어 주어야 합니다. 아래의 2번째 예에서 보면 함수를 호출할 때 매개변수의 입력 순서가 바뀌면 함수를 정의할 때와의 의도와는 다르게 엉뚱한 순서로 값이 출력되었습니다. 



In [7]: print_me("ABCD Co.", "Mr.Jack")

('Company : ', 'ABCD Co.')

('Name : ', 'Mr.Jack')


# Without parameter name, the order matters

In [8]: print_me("Mr.Jack", "ABCD Co.")

('Company : ', 'Mr.Jack')

('Name : ', 'ABCD Co.')

 




  기본값 매개변수 (Default Arguments)


기본값 매개변수는 함수를 호출할 때 매개변수 입력이 없을 경우에 함수를 정의할 때 입력한 기본값(default value)을 사용할 수 있게 해줍니다.  함수를 정의할 때 기본값 설정이 안되어 있는 상태에서 함수 호출 시 매개변수 값 입력을 빼먹으면 TypeError가 나는데요, 기본값 매개변수를 사용하면 TypeError 없이 사용할 수 있게 됩니다. 대신, 기본값 설정을 잘 지정해주어야 겠지요. 


아래의 예에서는 name 매개변수에 "Who?"라는 기본값(default value)을 지정해서 함수를 print_me2 라는 함수를 정의를 했구요, 함수 호출 시 name 매개변수 값을 입력하지 않았더니 => 기본값이 "Who?"가 출력되었네요. 



# Default Argument Value

In [9]: def print_me2(company, name="Who?"):

   ...: print("Company : ", company)

   ...: print("Name : ", name)


In [10]: print_me2(company="ABC Co.") # No TypeError

('Company : ', 'ABC Co.')

('Name : ', 'Who?')

 



단, 기본값 매개변수는 매개변수의 첫번째에는 사용할 수 없습니다. 만약 첫번째 매개변수에 기본값을 지정하려고 하면 아래처럼 'SyntaxError: non-default argument follows default argument)' 라는 에러가 발생합니다. 



# SyntaxError: non-default argument follows default argument

In [11]: def print_me2(company="ABCD Co.", name):

    ...: print("Company : ", company)

    ...: print("Name : ", name)

    ...:

    ...:

File "<ipython-input-11-c9e7590bf632>", line 1

def print_me2(company="ABCD Co.", name):

SyntaxError: non-default argument follows default argument

 



마지막으로, 매개변수는 숫자로 시작할 수 없습니다. 아래처럼 '3_company' 처럼 숫자 '3'으로 매개변수 이름을 시작했더니 'SyntaxError: invalid syntax'라는 에러가 떴습니다. 



In [12]: def print_me3(3_company, name):

    ...: print("Company : ", company)

    ...: print("Name : ", name)

    ...:

    ...:

File "<ipython-input-12-46388f3578d8>", line 1

def print_me3(3_company, name):

^

SyntaxError: invalid syntax

 



다음번 포스팅에서는 가변 매개변수(arbitrary arguments)에 알아보겠습니다. 


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


728x90
반응형
Posted by Rfriend
,

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

 

 

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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 로 표기해주는 방식이 저한테는 더 이해하기가 쉽네요. 


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


728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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.savez_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.savez_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.]])

 


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


728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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 를 참고하세요. 


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

 

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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])

 

 

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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])

 

 

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

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 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]])




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

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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 파이썬에서 다차원 배열(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') 함수에 대해서 알아보았습니다. 


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

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



728x90
반응형
Posted by Rfriend
,

외국의 블로그에 소프트엔지니어 채용 과정 중에 코딩 인터뷰에서 있을 법한 문제로 회자되는 "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 의 반응을 유심히 보면서... 인터뷰 과정을 한번 보시는 것도 재미있을 것 같습니다. ㅋㅋ


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

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



728x90
반응형
Posted by Rfriend
,