linear algebra

참고 : 무료 교재 http://www.kms.or.kr/board/list.html?num=6383&start=330&code=absinfo

스칼라 scalar

import numpy as np

a = np.array(1)  # 1차원 배열로 벡터를 나타낸다
print(a.ndim, a.shape)

벡터 vector

이미지참조 : https://ko.khanacademy.org/computing/computer-programming/programming-natural-simulations/programming-vectors/a/intro-to-vectors

$$ \vec{q} = (q_1, q_2, ..., q_n) $$

벡터 - numpy 1차원 배열

import numpy as np

a = np.array([1, 2, 3])  # 1차원 배열로 벡터를 나타낸다
print(a.ndim, a.shape)

행렬 matrix

이미지참조: https://minusi.tistory.com/entry/%ED%96%89%EB%A0%AC-%EB%8C%80%EC%88%98

행렬 - numpy 2차원 배열

import numpy as np

a = np.array([[1, 2, 3],
              [4, 5, 6]])  # 2×3의 행렬
print(a.ndim, a.shape)

텐서 tensor

이미지참조 : https://rekt77.tistory.com/102

3차원 텐서 - numpy 3차원 배열

import numpy as np

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

                     [[1, 2, 3, 4],
                      [3, 4, 5, 6],
                      [5, 6, 7, 8]]])  # (2, 3, 4)의 3차원 텐서
print(a.ndim, a.shape)

자연어 처리 예시

# Hi Foo
# Hi Bar
# Hi Baz
hi = np.array([1,0,0,0])
foo = np.array([0,1,0,0])
bar = np.array([0,0,1,0])
baz = np.array([0,0,0,1])

# matrix
hi_foo = np.array([hi,king])
hi_bar = np.array([hi,queen])
hi_baz= np.array([hi,jack])

# 3d-tensor
his = np.array([hi_foo, hi_bar, baz])
his.ndim, his.shape

백터의 내적

import numpy as np

a = np.array([1, 2, 3])
b = np.array([3, 2, 1])
r1 = np.dot(a,b)
r2 = np.sum(a*b)

벡터의 크기 : 놈(노름) norm

L2 놈

L1 놈

import numpy as np

a = np.array([1, 1, -1, -1])

print("--- L2놈 ---")
print(np.linalg.norm(a))  # L2놈(디폴트)
print("--- L1놈 ---")
print(np.linalg.norm(a, 1))  # L1놈

행렬의 곱

이미지참조: https://angeloyeo.github.io/2020/09/08/matrix_multiplication.html
import numpy as np

a = np.array([[0, 1, 2],
              [1, 2, 3]]) 

b = np.array([[2, 1],
              [2, 1],
              [2, 1]])
r1 = np.dot(a,b)
r2 = np.sum(a*b)

요소별 곱(아다마르 곱)

import numpy as np

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

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

print(a*b)

행렬 전치

import numpy as np

a = np.array([[1, 2, 3],
              [4, 5, 6]])  # 행렬

print(a.T)  # 전치

전치와 행렬곱 구현

import numpy as np

a = np.array([[0, 1, 2],
             [1, 2, 3]])  # 2×3의 행렬
b = np.array([[0, 1, 2],
             [1, 2, 3]])  # 2×3의 행렬 이대로는 행렬곱을 할 수 없다

# print(np.dot(a, b))  # 전치하지 않고 행렬곱을 취하면 에러

단위행렬과 역행렬

단위 행렬(항등 행렬)

import numpy as np

print(np.eye(2))  # 2×2의 단위 행렬
print()
print(np.eye(3))  # 3×3의 단위 행렬
print()
print(np.eye(4))  # 4×4의 단위 행렬
E = np.eye(2)
A = np.array([[1,2],[3,4]])
A == A.dot(E)

역행렬

역행렬 존재여부

iimport numpy as np

# 역행렬 존재
a = np.array([[1, 2],
              [3, 4]])
print(a[0,0]*a[1,1] - a[0,1]*a[1,0]) # ad - bc 
print(np.linalg.det(a))  # 행렬식이 0이 되지 않는 경우 

# 역행렬 미존재
b = np.array([[1, 3],
              [1, 3]])
print(b[0,0]*b[1,1] - b[0,1]*b[1,0]) # ad -bc
print(np.linalg.det(b))  # 행렬식이 0이 되는 경우

역행렬 구하기

import numpy as np

# 역행렬 존재
a = np.array([[1, 2],
              [3, 4]])
check = (a[0,0]*a[1,1] - a[0,1]*a[1,0]) # ad - bc 
if check != 0:
    print('a check : ', np.linalg.inv(a))  # 행렬식이 0이 되지 않는 경우 

# 역행렬 미존재
b = np.array([[1, 3],
              [1, 3]])
check = (b[0,0]*b[1,1] - b[0,1]*b[1,0]) # ad -bc
if check != 0:
    print('b check : ', np.linalg.inv(b))  # 행렬식이 0이 되는 경우

선형변환

quiver() : 벡터 그리기

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline


# 화살표를 그리는 함수
def arrow(start, size, color):
    plt.quiver(start[0], start[1], 
               size[0], size[1], 
               angles="xy", 
               scale_units="xy", 
               scale=1, color=color)

# 화살표의 시작점
s = np.array([0, 0])  # 원점

# 벡터
v = np.array([2, 3])  # 세로 벡터를 나타낸다

arrow(s, v, color="black")

# 그래프 표시
plt.xlim([-3,3])  # x의 표시 범위
plt.ylim([-3,3])  # y의 표시 범위
plt.xlabel("x", size=14)
plt.ylabel("y", size=14)
plt.grid()
plt.gca().set_aspect("equal")  # 가로세로비를 같게
plt.show()

선형변환

$$ A = {2 -1 \choose 2 -2} , \hat{a} = {2 \choose 3} $$

$$ \hat{b} = A\hat{a} = A = {2 -1 \choose 2 -2} {2 \choose 3} $$

import numpy as np
import matplotlib.pyplot as plt

a = np.array([2, 3])  # 변환 전의 벡터

A = np.array([[2, -1],
                     [2, -2]])

b = np.dot(A, a)  # 선형변환

print("변환 전의 벡터(a):", a)
print("변환 후의 벡터(b):", b)

def arrow(start, size, color):
    plt.quiver(start[0], start[1], size[0], 
               size[1], angles="xy", scale_units="xy", scale=1, color=color)

s = np.array([0, 0])  # 원점

arrow(s, a, color="black")
arrow(s, b, color="blue")

# 그래프 표시
plt.xlim([-3,3])  # x의 표시 범위
plt.ylim([-3,3])  # y의 표시 범위
plt.xlabel("x", size=14)
plt.ylabel("y", size=14)
plt.grid()
plt.gca().set_aspect("equal")  # 가로세로비를 같게
plt.show()

표준기저

import numpy as np
import matplotlib.pyplot as plt

a = np.array([2, 3])
e_x = np.array([1, 0])  # 표준기저
e_y = np.array([0, 1])  # 표준기저

print("a:", a)
print("e_x:", e_x)
print("e_y:", e_y)

def arrow(start, size, color):
    plt.quiver(start[0], start[1], size[0], 
               size[1], angles="xy", 
               scale_units="xy", scale=1, color=color)

s = np.array([0, 0])  # 원점

arrow(s, a, color="blue")
arrow(s, e_x, color="black")
arrow(s, e_y, color="black")

# 그래프 표시
plt.xlim([-3,3])  # x의 표시 범위
plt.ylim([-3,3])  # y의 표시 범위
plt.xlabel("x", size=14)
plt.ylabel("y", size=14)
plt.grid()
plt.gca().set_aspect("equal")  # 가로세로비를 같게
plt.show()

고윳값과 고유벡터

$$ A\vec{x} = \lambda\vec{x} $$

import numpy as np

a = np.array([[3, 1],
              [2, 4]])

ev = np.linalg.eig(a)  # 고유값과 고유 벡터를 동시에 구한다

print(ev[0])  # 첫 요소는 고유값 

print()

print(ev[1])  # 다음 요소는 고유 벡터

코사인 유사도

import numpy as np

def cos_sim(vec_1, vec_2):
    return np.dot(vec_1, vec_2) / (np.linalg.norm(vec_1) * np.linalg.norm(vec_2))  

a = np.array([2, 2, 2, 2])
b = np.array([1, 1, 1, 1])  # a와 같은 방향
c = np.array([-1, -1, -1, -1])  # a와 반대 방향

print("--- a와 b의 코사인 유사도 ----")
print(cos_sim(a, b))

print("--- a와 c의 코사인 유사도 ----")
print(cos_sim(a, c))