Programming/Python

[AI class day11] 파이썬 넘파이 python numpy TIL

makeitworth 2021. 5. 4. 12:10

오늘의 감상: 그래도 git과 numpy 모두 지난 <ssacxfast campus 빅데이터 분석가 과정> 에서 강의를 들었던 과정이라 week 1의 알고리즘 week2 인공지능을 위한 수학 수업 보다는 마음 편하게 들을 수 있었다.

지난 week2에서 배운 선형대수학 개념을 numpy로 구현하는 것은 numpy 문법 보다 선형대수학에 대한 복습이 필요한 것 같다.

 

행렬식

sigular matrix

고유값, 고유벡터

L@ norm

 

 

 

1. 파이썬의 컴퓨팅 라이브러리, numpy

numpy를 이용해서 데이터를 다뤄봅시다!

I. Numpy 시작하기

import numpy as np

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]
a = [1,2,3]
a*c # 그냥리스트는 연산이 되는게 아니라 리스트의 반복이 되어버린다.
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

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의 인덱싱

  • 리스트와 유사
  • 리스트와 달리 리스트 내 리스트를 불러올 때 [][]가 아니라 [,]로 인덱스한다
w= np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
print(w[0,0])
print(w[2,3])
1
12

array의 슬라이싱

  • 리스트와 유사
w= np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
# 일부 행 전체를 가져오고 싶을 때 -3가지 방법이 있음
w[0:2]
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
w[0:2,:]
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
w[0:2,0:4]
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
# 일부 열 전체를 가져오고 싶을 때 -2가지 방법이 있음
w[0:3, 2:4]
array([[ 3,  4],
       [ 7,  8],
       [11, 12]])
w[:, 2:4]
array([[ 3,  4],
       [ 7,  8],
       [11, 12]])
# 2,3 과 6,7 을 불러오고 싶을 때
# 행은 0,1행 -> [0:2] 열은1,2열 -> [1:3]에 있는 데이터들
print(w[0:2, 1:3])
[[2 3]
 [6 7]]

array 의 broadcasting

numpy의 연산을 진행하는 특수한 방법

기본적으로 같은 type의 data에 대해서만 연산 적용이 가능
그러나 만약 피연산자가 연산 가능하도록 변환이 가능하다면, 연산이 가능해집니다.
이를 broadcasting이라고 합니다.

  1. MxN, Mx1(열벡터) 행렬이 있는 경우 -> 뒷 행렬의 열을 복사시켜서 element-wise 계산할 수 있다. (행렬곱이 아니다)
  2. MxN, 1xN(행벡터) 행렬이 있는 경우 -> 뒷 행렬의 행을 복사시켜서 element-wise 계산할 수 있다. (행렬곱이 아니다)
  3. Mx1(열벡터), 1xN(행벡터) 행렬이 있는 경우 -> MxN 행렬의 연산이 진행됨
# 1. MxN, Mx1
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
x = np.array([0,1,0])
print(a+x)
[[1 3 3]
 [4 6 6]
 [7 9 9]]
# 기본적으로 행벡터이기 때문에 x를 열벡터로 transpose해줘야 한다.
x = x[:, None] #x를 전치
print(a+x)
[[1 2 3]
 [5 6 7]
 [7 8 9]]
#2. MxN, 1xN
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
y = np.array([0,1, -1])
print(a * y)
[[ 0  2 -3]
 [ 0  5 -6]
 [ 0  8 -9]]
#3. Mx1(열벡터), 1xN(행벡터)
t = np.array([1,2,3])
u = np.array([2,0,-2])
t = t[:,None] # 열벡터로 전치
print(t + u)
[[ 3  1 -1]
 [ 4  2  0]
 [ 5  3  1]]

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

영벡터(영행렬)

원소가 모두 0인 벡터(행렬)
np.zeros(dim)으로 생성
dim은 값 또는 튜플(,)

np.zeros(3)
array([0., 0., 0.])
np.zeros((3,3))
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

일벡터(일행렬)

원소가 모두 1인 벡터(행렬)
np.ones(dim)으로 생성
dim은 값 또는 튜플(,)

np.ones(3)
array([1., 1., 1.])
np.ones((3,3))
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

대각행렬 (diagonal matrix)

main diagonal을 제외한 성분이 0인 행렬
np.diag((main_diagonals))을 통해 생성

np.diag((2,4))
array([[2, 0],
       [0, 4]])
np.diag((1,3,5))
array([[1, 0, 0],
       [0, 3, 0],
       [0, 0, 5]])

항등행렬 (identity matrix)

main diagonal이 1인 행렬
np.eye(n, (dtype))을 통해 생성 (default는 float)
dtype을 파라미터로 넣을 수 있다 (int, float, uint, complex...)

np.eye(2)
array([[1., 0.],
       [0., 1.]])
np.eye(2, dtype=int).dtype
dtype('int64')
np.eye(3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

행렬곱 (dot product)

np.dot() or @ 사용

mat_1 = np.array([[1,4],[2,3]])
mat_2 = np.array([[7,9],[0,6]])
mat_1.dot(mat_2)
array([[ 7, 33],
       [14, 36]])
mat_1 @ mat_2
array([[ 7, 33],
       [14, 36]])

트레이스 (trace)

main diagonal의 합
np.trace()

arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
arr.trace()
15
arr = np.eye(2, dtype=int)
arr.trace()
2

행렬식 (determinat)

  • 행렬을 대표하는 값들 중 하나
  • 선형변환 과정에서 어떤 벡터의 스케일링 척도
  • 선형변화를 진행했을 때 얼마나 원벡터가 변화하는가
    ad-bc (2x2 일때)
    np.linalg.det()
arr_2 = np.array([[2,3],[1,6]])
arr_2
array([[2, 3],
       [1, 6]])
np.linalg.det(arr_2)
9.000000000000002
arr_3 = np.array([[1,4,7],[2,5,8], [3,6,9]])
arr_3
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])
np.linalg.det(arr_3) # det = 0 -> 즉 full rank 가 아니고 선형변환에서 차원의 손실이 일어난다.
0.0

역행렬 (Inverse Matrix)

  • 행렬A에 대해 AB = BA = I를 만족하는 행렬
  • B = A^-1
  • np.linalg.inv()
mat = np.array([[1,4],[2,3]])
mat
array([[1, 4],
       [2, 3]])
mat_inv = np.linalg.inv(mat)
mat_inv
array([[-0.6,  0.8],
       [ 0.4, -0.2]])
mat @ mat_inv
array([[1., 0.],
       [0., 1.]])

고유값과 고유벡터 (engenvalue eigenvecter)

  • 정방 행렬A에 대해 $Ax = (\lambda)x$ 를 만족하는 상수 $(\lambda)$와 이에 대응하는 벡터
  • np.linalg.eig()
mat = np.array([[2,0,-2],[1,1,-2],[0,0,1]])
mat
array([[ 2,  0, -2],
       [ 1,  1, -2],
       [ 0,  0,  1]])
np.linalg.eig(mat) 
(array([1., 2., 1.]),
 array([[0.        , 0.70710678, 0.89442719],
        [1.        , 0.70710678, 0.        ],
        [0.        , 0.        , 0.4472136 ]]))
###validation
eigen_val, eigen_vec = np.linalg.eig(mat) 
mat @ eigen_vec[:,0] #Ax
array([0., 1., 0.])
eigen_val[0] * eigen_vec[:,0] # (lambda)x
array([0., 1., 0.])

IV. Exercises

1. 어떤 벡터가 주어졌을 때 L2 norm을 구하는 함수 get_L2_norm()을 작성하세요

  • 매개변수 : 1차원 벡터 (np.array)
  • 반환값 : 인자로 주어진 벡터의 L2 Norm값 (number)

L2-norm이란?

http://taewan.kim/post/norm/

def get_L2_norm(arr):
    return (sum(arr**2))**0.5
arr = np.array([1,2,3])
get_L2_norm(arr)
3.7416573867739413
L2_norm = np.linalg.norm(arr, 2)
print(L2_norm)
3.7416573867739413
(sum(arr**2))**0.5
array([4.12310563, 5.38516481, 6.70820393])

2. 어떤 행렬이 singular matrix인지 확인하는 함수 is_singular() 를 작성하세요

  • 매개변수 : 2차원 벡터(np.array)
  • 반환값 : 인자로 주어진 벡터가 singular하면 True, non-singular하면 False를 반환

sigular matrix : 역행렬이 존재하지 않는 행렬
행렬식 = 0인 행렬

def is_singular(arr):
    return np.linalg.det(arr) == 0
arr = np.array([[1,2],[2,4]])
is_singular(arr)
True