-
[Python] 넘파이(Numpy)프로그래밍/Python 2020. 11. 23. 16:43
넘파이
※ 라이브러리 사용법
import numpy A = numpy.array([1, 2]) print("A == ", A, ", type == ", type(A))
# 결과 A == [1 2] , type == <class 'numpy.ndarray'>
import numpy as np A = np.array([1, 2]) print("A == ", A, ", type == ", type(A))
# 결과 A == [1 2] , type == <class 'numpy.ndarray'>
from numpy import exp result = exp(1) print("result == ", result, ", type == ", type(result))
# 결과 result == 2.718281828459045 , type == <class 'numpy.float64'>
from numpy import * result = exp(1) + log(1.7) + sqrt(2) print("result == ", result, ", type == ", type(result))
# 결과 result == 4.663123641894311 , type == <class 'numpy.float64'>
넘파이(Numpy)
vector / matrix 생성
- numpy는 머신러닝 코드 개발할 경우 자주 사용되는 벡터, 행렬 등을 표현하고 연산할 때 반드시 필요한 라이브러리
- 머신러닝에서는 숫자, 사람, 동물 등의 인식을 하기 위해서는 이미지(image) 데이터를 행렬(matrix)로 변환하는 것이 중요
- 행렬을 나타내기 위해서 리스트를 사용할 수도 있지만, 행렬 연산이 직관적이지 않고, 오류 가능성이 높기 때문에 행렬 연산을 위해서 numpy 사용이 필수!
# numpy vs list import numpy as np # list A = [[1, 0], [0, 1]] B = [[1, 1], [1, 1]] print(A + B) # numpy A = np.array([[1, 0], [0, 1]]) B = np.array([[1, 1], [1, 1]]) print(A + B)
# 결과 [[1, 0], [0, 1], [1, 1], [1, 1]] [[2 1] [1 2]]
- 머신러닝 코드 구현시, 연산을 위해서 vector, matrix 등의 형상(shape), 차원(dimension)을 확인하는 것이 필요!
A = np.array([1, 2, 3]) B = np.array([4, 5, 6]) # vector A, B 출력 print("A == ", A, ", B == ", B) # vector A, B 형상 출력 => shape print("A.shape == ", A.shape, ", B.shape == ", B.shape) # vector A, B 차원 출력 => dimension print("A.ndim == ", A.ndim, ", B.ndim == ", B.ndim)
# 결과 A == [1 2 3] , B == [4 5 6] A.shape == (3,) , B.shape == (3,) A.ndim == 1 , B.ndim == 1
- 벡터간 사칙연산(+, -, *, /)은 벡터의 각각의 원소에 대해서 수행됨
print("A + B == ", A + B) print("A - B == ", A - B) print("A * B == ", A * B) print("A / B == ", A / B)
# 결과 A + B == [5 7 9] A - B == [-3 -3 -3] A * B == [ 4 10 18] A / B == [0.25 0.4 0.5 ]
- 행렬은 벡터와 마찬가지로
np.array[[...], [...], [...])
를 사용하여 생성 - reshape() 함수를 사용하여 벡터를 행렬로 변경하거나, 행렬을 다른 현상의 행렬로 변경할 수 있음
C = np.array([1, 2, 3]) # 벡터 형상 출력 print("C.shape == ", C.shape) # 벡터를 1x3 행렬로 형 변환 C = C.reshape(1, 3) # 행렬 형상 출력 print("C.shape == ", C.shape)
# 결과 C.shape == (3,) C.shape == (1, 3)
행렬 곱 (dot product)
- A 행렬과 B 행렬의 곱 (dot product)는 np.dot(A, B) 으로 나타내며, 행렬 A의 열벡터와 행렬 B의 행벡터가 같아야 함
- 만약 같지 않다면, reshape() 또는 전치행렬(transpose) 등을 사용하여 형 변환을 한 후에 행렬 곱 실행
A = np.array([[1, 2, 3], [4, 5, 6]]) # 2x3 행렬 B = np.array([[-1, -2], [-3, -4], [-5, -6]]) # 3x2 행렬 # (2x3) dot product (3x2) = (2x2) 행렬 C = np.dot(A, B) # matrix A, B 형상 출력 => shape print("A.shape == ", A.shape, ", B.shape == ", B.shape) print("C.shape == ", C.shape) print(C)
# 결과 A.shape == (2, 3) , B.shape == (3, 2) C.shape == (2, 2) [[-22 -28] [-49 -64]]
- 행렬 곱은 행렬의 원소 개수가 같아야만 계산할 수 있는 사칙연산의 한계를 벗어남
- 행렬 곱 조건을 만족하는 다양한 크기의 행렬을 연속으로 만들고
- 행렬 곱을 연속으로 계산하면서
- 결과 값을 만들 수 있기 때문에 머신러닝과 이미지 프로세싱 분야에서 자주 사용됨
- 만약 행렬 곱을 사용하지 않으면, 똑같은 크기를 가지는 특성 값만을 사용해야 하기 때문에 다양한 특성을 갖는 필터 개발이 불가
전치행렬(transpose)
- 원본 행렬의 행은 열, 열은 행으로 바꾼 행렬
- 원본 행렬을 A라고하면 전치행렬은 A^T로 나타냄
A = np.array([[1, 2], [3, 4], [5, 6]]) # 3x2 행렬 B = A.T # A의 전치행렬 2x3 print("A.shape == ", A.shape, ", B.shape == ", B.shape) print(A) print(B)
# 결과 A.shape == (3, 2) , B.shape == (2, 3) [[1 2] [3 4] [5 6]] [[1 3 5] [2 4 6]]
# vector 전치행렬 C = np.array([1, 2, 3, 4, 5]) D = C.T # C가 vector이므로 transpose X E = C.reshape(1, 5) # 1x5 matrix F = E.T # E의 전치행렬 5x1 print("C.shape == ", C.shape, ", D.shape == ", D.shape) print("E.shape == ", E.shape, ", F.shape == ", F.shape) print(F)
# 결과 C.shape == (5,) , D.shape == (5,) E.shape == (1, 5) , F.shape == (5, 1) [[1] [2] [3] [4] [5]]
broadcast
- 행렬의 사칙연산은 기본적으로 두 개의 행렬의 크기가 같은 경우에만 수행이 가능
- 그러나 numpy에서는 크기가 다른 두 행렬 간의 사칙연산(+, -, *, /)을 할 수 있는데, 이를 브로드캐스트(broadcast) 라고 함
- 차원이 작은 쪽이 큰 쪽의 행 단위로 반복적으로 크기를 맞춘 후 계산
A = np.array([[1, 2], [3, 4]]) # [ [1, 2], [3, 4] ] B = 5 # [ [5, 5], [5, 5] ] C = np.array([4, 5]) # [ [4, 5] ] print(A + B) print(A + C)
# 결과 [[6 7] [8 9]] [[5 7] [7 9]]
index / slice / iterator
- 행렬 원소를 명시적으로 접근하기 위해서는 리스트에서 처럼 index / slice 모두 사용 가능함
A = np.array([10, 20, 30, 40, 50, 60]).reshape(3, 2) print("A.shape == ", A.shape) print(A)
# 결과 A.shape == (3, 2) [[10 20] [30 40] [50 60]]
print("A[0, 0] == ", A[0, 0], ", A[0, 1] == ", A[0, 1]) print("A[1, 0] == ", A[1, 0], ", A[1, 1] == ", A[1, 1]) print("A[2, 0] == ", A[2, 0], ", A[2, 1] == ", A[2, 1])
# 결과 A[0, 0] == 10 , A[0, 1] == 20 A[1, 0] == 30 , A[1, 1] == 40 A[2, 0] == 50 , A[2, 1] == 60
print("A[0:-1, 1:2] == ",A[0:-1, 1:2])
# 결과 A[0:-1, 1:2] == [[20] [40]]
print("A[ :, 0] == ", A[ :, 0]) print("A[ :, :] == ", A[ :, :])
# 결과 A[ :, 0] == [10 30 50] A[ :, :] == [[10 20] [30 40] [50 60]]
- 명시적 index / slice 이외에, 행렬 모든 원소를 access 하는 경우에는 iterator 사용 가능
- numpy iterator는 next() 함수를 통해 데이터 값을 처음부터 끝까지 읽어 들이는 방법을 제공
A = np.array([[10, 20, 30, 40], [50, 60, 70, 80]]) print(A, "\n") print("A.shape == ", A.shape, "\n") # 행렬 A의 iterator 생성 # flags = ['multi_index'] : iterator 생성후 반복할때 행렬처럼 (row, column) 형태의 multi_index 형태로 동작 # op_flags = ['readwrite'] : iterator 를 R/W 형태로 생성 it = np.nditer(A, flags = ['multi_index'], op_flags = ['readwrite']) while not it.finished: idx = it.multi_index print("current value => ", A[idx]) it.iternext()
# 결과 [[10 20 30 40] [50 60 70 80]] A.shape == (2, 4) current value => 10 current value => 20 current value => 30 current value => 40 current value => 50 current value => 60 current value => 70 current value => 80
concatenate
- 행렬에 행(row) 또는 열(column)을 추가하기 위해 사용하는 함수
- 머신러닝의 회귀(regression) 코드 구현시 가중치(weight)와 바이어스(bias)를 별도로 구분하지 않고 하나의 행렬로 취급하기 위한 프로그래밍 구현 기술
# 행렬에 열과 행 추가 A = np.array([[10, 20, 30], [40, 50, 60]]) print(A.shape) # A matrix에 행(row) 추가할 행렬, 1x3 reshape # 행을 추가하기 때문에 우선 열을 3열로 만들어야 함 row_add = np.array([70, 80, 90]).reshape(1, 3) # A matrix에 열(column) 추가할 행렬, 2x1 reshape # 열을 추가하기 때문에 우선 행을 2행으로 만들어야 함 column_add = np.array([1000, 2000]).reshape(2, 1) # numpy.concatenate 에서 axis = 0 (행 기준) B = np.concatenate((A, row_add), axis = 0) print(B) # numpy.concatenate 에서 axis = 1 (열 기준) C = np.concatenate((A, column_add), axis = 1) print(C)
# 결과 (2, 3) [[10 20 30] [40 50 60] [70 80 90]] [[ 10 20 30 1000] [ 40 50 60 2000]]
useful functions (loadtxt(), rand(), argmax() ... )
loadtxt()
- seperator로 구분된 파일에서 데이터를 읽기 위해 사용하는 함수
- 리턴 값은 행렬이기 때문에 index / slice 이용하여 데이터를 분리할 수 있음
- 머신러닝 코드에서 입력 데이터와 정답 데이터를 분리하는 프로그래밍 기법
# 데이터는 25x4 행렬이라고 가정 loaded_data = np.loadtxt('./data-01.csv', delimiter = ',', dtype = np.float32) x_data = loaded_data[ :, 0:-1] # 모든 행, 3열까지의 데이터 t_data = loaded_data[ :, [-1]] # 모든 행, 4열의 데이터 print("x_data.ndim == ", x_data.ndim, ", x_data.shape == ", x_data.shape) print("t_data.ndim == ", t_data.ndim, ", t_data.shape == ", t_data.shape) # 결과 # x_data.ndim == 2, x_data.shape == (25, 3) # t_data.ndim == 2, x_data.shape == (25, 1)
rand()
- 0과 1 사이 임의의 실수 값을 리턴해주는 함수
- 가중치(weight)나 바이어스(bias)를 임의로 설정할 때 자주 사용하는 함수
# 0 ~ 1 사이의 random number 발생 random_number1 = np.random.rand(3) random_number2 = np.random.rand(1, 3) random_number3 = np.random.rand(3, 1) print("random_number1 == ", random_number1, ", random_number1.shape == ", random_number1.shape) print("random_number2 == ", random_number2, ", random_number2.shape == ", random_number2.shape) print("random_number3 == ", random_number3, ", random_number3.shape == ", random_number3.shape)
# 결과 random_number1 == [0.19724608 0.20855116 0.58046355] , random_number1.shape == (3,) random_number2 == [[0.33375994 0.84088436 0.94006071]] , random_number2.shape == (1, 3) random_number3 == [[0.8197173 ] [0.91239959] [0.30047281]] , random_number3.shape == (3, 1)
max(), min(), argmax(), argmin()
- max(), min() : 최대 최소를 리턴
- argmax(), argmin() : 최대 최소의 인덱스를 리턴
X = np.array([2, 4, 6, 8]) print("np.max(X) == ", np.max(X)) print("np.min(X) == ", np.min(X)) print("np.argmax(X) == ", np.argmax(X)) print("np.argmin(X) == ", np.argmin(X))
# 결과 np.max(X) == 8 np.min(X) == 2 np.argmax(X) == 3 np.argmin(X) == 0
X = np.array([[2, 4, 6], [1, 2, 3], [0, 5, 8]]) print("np.max(X) == ", np.max(X, axis = 0)) # 열 기준 print("np.min(X) == ", np.min(X, axis = 0)) # 열 기준 print("np.max(X) == ", np.max(X, axis = 1)) # 행 기준 print("np.min(X) == ", np.min(X, axis = 1)) # 행 기준 print("np.argmax(X) == ", np.argmax(X, axis = 0)) # 열 기준 print("np.argmin(X) == ", np.argmin(X, axis = 0)) # 열 기준 print("np.argmax(X) == ", np.argmax(X, axis = 1)) # 행 기준 print("np.argmin(X) == ", np.argmin(X, axis = 1)) # 행 기준
# 결과 np.max(X) == [2 5 8] np.min(X) == [0 2 3] np.max(X) == [6 3 8] np.min(X) == [2 1 0] np.argmax(X) == [0 2 2] np.argmin(X) == [2 1 1] np.argmax(X) == [2 2 2] np.argmin(X) == [0 0 0]
ones(), zeros()
A = np.ones([3, 3]) print("A.shape == ", A.shape, ", A == ", A) B = np.zeros([3, 2]) print("B.shape == ", B.shape, ", B == ", B)
# 결과 A.shape == (3, 3) , A == [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]] B.shape == (3, 2) , B == [[0. 0.] [0. 0.] [0. 0.]]
matplotlib
- 실무에서는 머신러닝 코드를 구현하기 전에, 입력 데이터의 분포와 모양을 먼저 그래프로 그려보고, 데이터의 특성과 분포를 파악한 후, 어떤 알고리즘을 적용할 지 결정하고 있음
- 데이터 시각화를 위해 matplotlib 라이브러리를 사용함
- 일반적으로 line plot, scatter plot 등을 통해 데이터의 분포와 형태를 파악함
import matplotlib.pyplot as plt import numpy as np # 주피터 노트북을 사용하는 경우 노트북 내부에 그림 표시 %matplotlib inline # x data, y data 생성 x_data = np.random.rand(100) y_data = np.random.rand(100) plt.title('scatter plot') plt.grid() plt.scatter(x_data, y_data, color = 'b', marker = 'o') plt.show()
# x data, y data 생성 x_data = [x for x in range(-5, 5)] y_data = [y*y for y in range(-5, 5)] plt.title('line plot') plt.grid() plt.plot(x_data, y_data, color = 'b') plt.show()
# x data, y data 생성 x_data = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] y_data = [-8, -13, 0, 3, 6, -1, -5, -7, 1, 8, 7, 12, 13] plt.title('line plot') plt.grid() plt.plot(x_data, y_data, color = 'b') plt.show()
참고
www.youtube.com/playlist?list=PLS8gIc2q83OjStGjdTF2LZtc0vefCAbnX
'프로그래밍 > Python' 카테고리의 다른 글
[Python] 파이썬 문법 정리 (0) 2022.01.22 [Python] 클래스, 예외처리 (0) 2020.11.21 [Python] 함수, 람다 (0) 2020.11.21 [Python] 조건문, 반복문 (0) 2020.11.21 [Python] 데이터 타입(Data Type) (0) 2020.11.21