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