일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Redux
- nodejs
- CentOS
- mariadb
- nginx
- Redis
- deep learning
- Go
- 기초 수학
- linux
- NCP
- Switch
- Backbone.js
- webpack
- php
- React
- fastapi
- Babel
- laravel
- Node
- 블레이드 템플릿
- SQL
- rabbitmq
- AWS
- Machine Learning
- phpredis
- docker
- For
- javascript
- python
- Today
- Total
개발일기
기초 수학 - 고유 벡터와 고유값 본문
고유벡터
어떤 벡터에 선형 변환이 일어났을 때, 벡터의 방향이 바뀌지 않고 변환 결과가 자기 자신의 상수배이며 0이 아닌 벡터를 고유벡터라 한다. 여기서 선형 변환이란 벡터의 크기 변화없이 돌리거나 뒤집거나 뒤트는 등 벡터를 변형시키는걸 의미한다.
왼쪽 그림을 오른쪽 방향으로 전단 변형하면 그래프는 위와 같이 변형된다. 높이는 유지하되 오른쪽 방면으로 찌그러진 모양의 그림이 나오게 된다. 흰색 벡터는 방향을 그대로 유지하지만 노란색과 초록색 벡터는 방향이 바뀐다. 위의 변형의 결과로 흰색 벡터는 고유 벡터가 된다.
만약 위 그림을 2배로 확대시키는 변형을 가하면 그림이 커진만큼 그래프의 선의 길이도 2배 증가한다. 기존 벡터의 크기가 5, 확대된 벡터의 크기가 10이라 가정했을 때, 확대된 벡터에서 기존 벡터의 크기를 나누면 고유값이 나오게 된다. 이 경우 이 변형에서 고유값은 2가 된다. 수식에서는 고유 벡터를 $ v $, 고유값을 $ \lambda $로 표시한다.
고유 벡터와 고유값의 특징으로는 기존 행렬을 변형시켜도 고유 벡터와 고유값을 활용하여 기존 행렬 값을 찾아낼 수 있다는 특징을 가지고 있다. 수학 공식에 따르면 $ Av = \lambda v $, 즉 행렬에 고유 벡터를 곱하면 고유값에 고유벡터를 곱한 것과 같은 값이 반환되기에 이러한 특징이 존재한다.
Numpy
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[-6, 3],
[4, 5]])
lam, v = np.linalg.eig(A) # 고유값, 고유벡터 구하기
print("EigenVector: ", lam)
print("EigenValue: ", v)
"""
EigenVector: [-7. 6.]
EigenValue: [[-0.9486833 -0.24253563]
[ 0.31622777 -0.9701425 ]]
"""
numpy에서 제공하는 eig()메서드로 고유 벡터와 고유값을 구할 수 있다. 수식에서 고유값을 lambda로 표시하는데 lambda라는 함수가 파이썬에 존재하므로 lam으로 표시하였다.
# 열에 따른 고유값, 고유 벡터
import numpy as np
A = np.array([[-6, 3],
[4, 5]])
lam, v = np.linalg.eig(A)
print("1 EigenVector, Value: ", lam[0], v[:, 0])
print("2 EigenVector, Value: ", lam[1], v[:, 1])
# print( np.dot(A, v), np.dot(lam, v) )
"""
1 EigenVector, Value: -7.0 [-0.9486833 0.31622777]
2 EigenVector, Value: 6.0 [-0.24253563 -0.9701425 ]
"""
계산된 고유 벡터와 고유값을 살펴보면 A의 열 개수 만큼의 고유 벡터를 가지고 있다. A는 두 개의 열을 가지고 있으며 각 열에 고유 벡터가 하나씩 지정된다. 또한 각 열에 상응하는 고유값 또한 2개가 있다. 즉, 1열 고유벡터는 고유값이 7, 2열 고유벡터는 고유값이 6으로 서로 대응된다. 이를 통해 행렬의 열 개수에 따라 고유 벡터와 고유값의 개수가 바뀐다는 것을 확인할 수 있다.
각각의 고유 벡터와 고유값으로 $ Av = \lambda v $식이 올바른지 증명해보자.
# 열에 따른 고유값, 고유 벡터
import numpy as np
A = np.array([[-6, 3],
[4, 5]])
lam, v = np.linalg.eig(A)
print("첫번째: ", np.dot(A, v[:, 0]), np.dot(lam[0], v[:, 0]))
print("두번째: ", np.dot(A, v[:, 1]), np.dot(lam[1], v[:, 1]))
"""
첫번째: [ 6.64078309 -2.21359436] [ 6.64078309 -2.21359436]
두번째: [-1.45521375 -5.820855 ] [-1.45521375 -5.820855 ]
"""
$ Av = \lambda v $ 를 적용하여 각 열에 따라 계산을 진행하니 두 경우 모두 동일한 값이 나와 식이 올바르다는게 증명된다.
그래프로 이해하기
import numpy as np
import matplotlib.pyplot as plt
v = np.array([3, 1]) # 기존 벡터 (6, 1)
lam = 2 # EigenValue
plot_vectors([np.dot(v, lam), v], ['lightblue', 'blue'])
plt.xlim(-6, 6)
plt.ylim(0, 5)
고유 벡터에 고유값을 구한 기존 행렬 A는 lightblue 색상으로 그리고 고유 벡터는 blue 색상으로 그린 그래프를 생성한다. blue 그래프에 고유값 2를 곱하면 기존 행렬과 동일해진다.
Pytorch
# Pytorch
import torch
A = torch.tensor([[-6, 3],
[4, 5]])
A = A.type(torch.float64)
eigens = torch.linalg.eig(A)
print("EigenVectors: ", eigens.eigenvectors)
print("EigenValues: ", eigens.eigenvalues)
"""
EigenVectors: tensor([[-0.9487+0.j, -0.2425+0.j],
[ 0.3162+0.j, -0.9701+0.j]], dtype=torch.complex128)
EigenValues: tensor([-7.+0.j, 6.+0.j], dtype=torch.complex128)
"""
Pytorch도 numpy의 eig를 사용하여 고유 벡터, 고유값을 구할 수 있다. pytorch는 정수형이 아닌 float형에서만 고유 벡터, 고유값을 구할 수 있기 때문에 type() 메서드로 형 변환이 필요하다.
Tensorflow
# Tensorflow
import tensorflow as tf
A = tf.Variable([[-6, 3],
[4, 5]], dtype=tf.float64)
lam, v = tf.linalg.eigh(A)
print("EigenVectors: ", v)
print("EigenValues: ", lam)
"""
EigenVectors: tf.Tensor(
[[-0.95098267 -0.30924417]
[ 0.30924417 -0.95098267]], shape=(2, 2), dtype=float64)
EigenValues: tf.Tensor([-7.30073525 6.30073525], shape=(2,), dtype=float64)
"""
tensorflow도 pytorch와 마찬가지로 float형을 사용하며 eig() 메서드로 고유 벡터와 고유값을 구할 수 있다.
2차원 행렬이 아닌 다차원 행렬에서도 고유 벡터와 고유값을 구하는 방법은 동일하다.
다차원 행렬의 고유 벡터과 고유값
# 다차원 행렬
import numpy as np
A = np.array([[5, 3, 6],
[1, 2, 4],
[2, 8, 3]])
lam, v = np.linalg.eig(A)
lam_1 = lam[0]
lam_2 = lam[1]
lam_3 = lam[2]
v_1 = v[:, 0]
v_2 = v[:, 1]
v_3 = v[:, 2]
# A * v = v * lambda
print("첫번쨰: ", np.dot(A, v_1), np.dot(v_1, lam_1))
print("두번쨰: ", np.dot(A, v_2), np.dot(v_2, lam_2))
print("세번쨰: ", np.dot(A, v_3), np.dot(v_3, lam_3))
"""
첫번쨰: [8.14013518 3.65173275 5.90794349] [8.14013518 3.65173275 5.90794349]
두번쨰: [ 2.42678298 -0.57104223 -0.69048417] [ 2.42678298 -0.57104223 -0.69048417]
세번쨰: [ 1.22708822 1.68901766 -2.53940768] [ 1.22708822 1.68901766 -2.53940768]
"""
(3 x 3), (4 x 4), (5 x 5) 처럼 열이 커질 수록 생성되는 고유 벡터와 고유값의 개수는 증가한다. (2 x 2) 행렬에서 했던 것처럼 각 열에 상응하는 고유 벡터와 고유값을 구한 후, $ Av = \lambda v $가 올바른지 검증하여 일치하는지 확인한다.
참고 사이트:
https://www.mathsisfun.com/algebra/eigenvalue.html
https://www.visiondummy.com/2014/03/eigenvalues-eigenvectors/
https://colab.research.google.com/drive/1UJ3-otIG7Qer2V4YyJYH5yFpZMCM5BzN?usp=sharing
'Deep Learning, Machine Learning > 기초 수학' 카테고리의 다른 글
기초 수학 - 고유값의 특성 (0) | 2024.03.31 |
---|---|
기초 수학 - 행렬 판별식 (0) | 2024.03.31 |
기초 수학 - 행렬 (0) | 2024.03.27 |
기초수학 - 텐서의 전치와 내적 (0) | 2024.03.24 |
기초 수학 - 선형대수학 Tensor, Vector, Norm (0) | 2024.03.23 |