카테고리 없음

[KMU SUMMER AI] 파이썬의 컴퓨팅 라이브러리, numpy

프로틴형님 2022. 7. 16. 06:28

I. Numpy 시작하기


Remind : 리스트

Python의 리스트

arr = [1, "two", 3.0]

print(arr)

numpy 모듈 불러오기

코드를 보다 편하게 쓰기 위해 np라는 alias 사용

import numpy as np

왜 numpy를 사용해야 할까 ?

  • List의 경우
L = range(1000)

%timeit [i**2 for i in L]

The slowest run took 6.16 times longer than the fastest.
This could mean that an intermediate result is being cached.
1000 loops, best of 3: 260 µs per loop

  • numpy.array의 경우
N = np.arange(1000)

%timeit N\*\*2

The slowest run took 493.16 times longer than the fastest.
This could mean that an intermediate result is being cached.
100000 loops , best of 3: 2.15 µs per loop

보다 많은 루프를 더 빠른 연산 안에 처리한다. 그래서 numpy를 쓴다 !


numpy.array

numpy의 Container, array

  • 1차원 배열
arr = np.array(\[1,2,3\])

arr 
# 결과 : array(\[1, 2, 3\])

arr.shape 
# 결과 : (3,)
  • 2차원 배열
arr_2d = np.array([[1,2,3],[4,5,6],[7,8,9]])

arr_2d
# 결과
# array([[1, 2, 3],
#        [4, 5, 6],
#        [7, 8, 9]])

arr_2d.shape
# (3, 3)

II. Numpy로 연산하기


Vector와 Scalar 사이의 연산

벡터의 각 원소에 대해서 연산을 진행

x = np.array([1,2,3])
c = 5

print("더하기 : {}".format(x + c))
print("빼기 : {}".format(x - c))
print("곱하기 : {}".format(x * c))
print("나누기 : {}".format(x / c))

더하기 : [6 7 8]
빼기 : [-4 -3 -2]
곱하기 : [ 5 10 15]
나누기 : [0.2 0.4 0.6]


Vector와 Vector 사이의 연산

벡터의 같은 인덱스끼리 연산이 진행

y = np.array([1,3,5])
z = np.array([2,9,20])

print("더하기 : {}".format(y + z))
print("빼기 : {}".format(y - z))
print("곱하기 : {}".format(y * z))
print("나누기 : {}".format(y / z))

더하기 : [ 3 12 25]
빼기 : [ -1 -6 -15]
곱하기 : [ 2 27 100]
나누기 : [0.5 0.33333333 0.25 ]


Array Indexing

Python의 리스트와 유사하게 진행

W = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])

W[0, 0] # 1

# 7을 가져오려면 ?
W[1, 2]

Array Slicing

Python의 리스트와 유사하게 진행

W = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])

W[0:2, 1:3] # array([[2, 3], [6, 7]])
W[0:2, ] # == W[0:2], W[0:2, :] 
# array([[1, 2, 3, 4], [5, 6, 7, 8]])
W[,2:4] # SyntaxError: invalid syntax
W[:, 2:4] array([[ 3,  4], [ 7,  8], [11, 12]])

Array의 Broadcasting

기본적으로 같은 Type의 data에 대해서만 연산이 적용 가능
하지만 만약에 피연산자가 연산 가능하도록 변환이 가능하다면 연산이 가능합니다.
이를 Broadcasting이라고 합니다

1. M by N, M by 1

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
x = np.array([0,1,0])

x = x[:, None]
print(a+x)

2. M by N, 1 by N

y = np.array([0,1,-1])

print(a*y)

3. M by 1, 1 by N

t = np.array([1,2,3]) # 열벡터로 바꿔줘야 함!
t = t[:, None] # Transpose

u = np.array([2,0,-2])

print(t + u)

III. Numpy로 선형대수 지식 끼얹기


A.basics


영벡터(행렬)

  • 원소가 모두 0인 벡터(행렬)
  • np.zeros(dim)을 통해 생성, dim은 값 혹은 tuple(,)
np.zeros(3) # 길이가 3인 1차원 영벡터
np.zeros((3,3,3)) # 축의 길이가 3인 3차원 행렬

일벡터(일행렬)

  • 원소가 모두 1인 벡터(행렬)
  • np.ones(dim)을 통해 생 성, dim은 값 혹은 tuple(,)
np.ones(2) # 길이가 2인 1차원 영벡터
np.ones((3,3,)) # 축의 길이가 3인 3차원 행렬

대각행렬

  • Main Diagonal을 제외한 성분이 0인 행렬
  • np.diag((main_diagonals))을 통해 생성할 수 있음.
  • np.diag((2,4)) ## 대각선 원소가 2,4인 2차원 대각행렬 np.diag((1,3,5,)) ## 대각선 원소가 1,3,5인 3차원 대각행렬

항등행렬

  • Main Diagonal == 1인 diagonal matrix(대각 행렬)
  • np.eye(n, (dtype=int, uint, float, complex, ... ))을 통해 생성할 수 있음.
np.eye(2, dtype=int) # data type을 int형으로 (default : double)

행렬곱

  • 행렬간에 정의되는 곱 연산(dot product)
  • np.dot(), @을 사용
mat_1 = np.array([[1,4], [2,3]])
mat_2 = np.array([[7,9], [0,6]])

mat_1.dot(mat_2)
mat_1 @ mat_2
# array([[ 7, 33], [14, 36]])

B. Furthermore


트레이스

  • Main Diagonal의 Sum
  • np.trace()을 사용
arr = np.array([[1,2,3], [4,5,6], [7,8,9]])

arr.trace() # 15
np.eye(2, dtype=int).trace() # 2

행렬식

  • 행렬을 대표하는 값 중 하나
  • 선형변환 과정에서 Vector의 Scaling 척도
  • np.linalg.det() 으로 계산
arr_2 = np.array([[2,3], [1,6]])

np.linalg.det(arr_2) # 9.000000000000002 부동소수점 오차

역행렬

  • 행렬 A에 대해 AB = BA = I를 만족하는 행렬 B = A^-1
  • np.linalg.inv() 으로 계산
mat = np.array([[1,4], [2,3]])

mat_inv = np.linalg.inv(mat)

mat_inv # array([[-0.6,  0.8], [ 0.4, -0.2]])

고유값과 고유벡터

  • 정방행렬 A에 대해서 $Ax = \lambda x$을 만족하는 $\lambda$와 x를 각각 고유값과 고유벡터라 한다.
  • np.linalg.eig() 로 계산
mat = np.array([[2,0,-2], [1,1,-2], [0,0,1]])

np.linalg.eig(mat)

Validation

eig_val, eig_vec = np.linalg.eig(mat)

eig_val

mat @ eig_vec[:, 0] # Ax

eig_val[0] * eig_vec[:, 0] # (lambda)x