[Python으로 데이터 다루기 I - numpy]2강:Numpy와 선형대수

3 minute read

영벡터(영행렬)

원소가 모두 0인 벡터(행렬)
np.zeros(dim)을 통해 생성. dim은 값, 혹은 튜플( , )이어야 한다.

np.zeros(2)
# array([0., 0.])

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



일벡터(일행렬)

원소가 모두 1인 벡터(행렬)
np.ones(dim)을 통해 생성. dim은 값 혹은 튜플( , )

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



대각행렬(diagonal matrix)

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

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=int, uint, float, complex, ...)를 사용. dtype으로 데이터타입을 같이 지정해줄 수도 있다.지정하지 않아도 상관없다.

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



행렬곱(dot product)

행렬간의 곱연산
np.dot() or @ 사용
.dot()은 메서드처럼 사용하고, @는 연산자처럼 사용한다.

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의 합 -> $\sum a_{ii}$ 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

np.eye(2, dtype=int)
# array([[1, 0],
#        [0, 1]])

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



행렬식(determinant)

행렬을 대표하는 값들 중 하나 -> 선형변환 선형변환 과정에서 벡터의 scaling 척도
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_2 = 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)
# 0.0 -> det값이 0이면 full rank가 아님, 즉 선형변환 과정에서 차원의 손실이 일어남을 알 수 있음. 즉 column(열)들간에 선형 종속관계가 존재한다.

선형대수에서 계산하는 것도 중요하지만, 계산의 결과와 각각의 값들이 어떤 의미를 가지는지 아는 것이 중요하다.


역행렬(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.00000000e+00,  0.00000000e+00],
#        [-1.11022302e-16,  1.00000000e+00]])
# 행렬 * 역행렬 = I(항등행렬)임을 알 수 있다.



고유값과 고유벡터(eigenvalue and eigenvector)

정방행렬 A에 대해 Ax = (\lambda)x를 만족하는 상수 (\lambda)와 이에 대응하는 벡터
$Ax = \lambda x$가 있을 때, 이를 만족하는 람다가 고유값, x가 고유벡터이다.
선형변환 관점에서 보면, 선형 변환을 진행하는 과정에서 span되는 비율이 고유값, span되는 영역이 고유벡터이다. 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 ]]))
# column을 기준으로 봐야 하기 때문에, 고유벡터는 각각
# 1에 대응되는 고유벡터 [0., 1., 0]
# 2에 대응되는 고유벡터 [0.70710678, 0.70710678, 0.]
# 1에 대응되는 고유벡터 [0.89442719, 0., 0.4472136]

Validation

eig_val, eig_vec = np.linalg.eig(mat)
eig_val
# array([1., 2., 1.])

eig_vec
# array([[0.        , 0.70710678, 0.89442719],
#        [1.        , 0.70710678, 0.        ],
#        [0.        , 0.        , 0.4472136 ]])

mat @ eig_vec[:, 0] # Ax를 계산
# column을 기준으로 가져와야 한다. eig_vec을 0번째 열 것만 가져와서 한다.
# 행으로는 전부, 열로는 0번째.
# array([0., 1., 0.])

eig_val[0] * eig_vec[:, 0] # (lambda)x를 계산
# eig_val은 1by1 matrix, 벡터가 아닌 값이다. 따라서 @연산을 적용하면 충분한 dimension이 없다는 오류가 난다. 행렬곱이 아닌 그냥 곱하기를 써줘야 한다.
# 스칼라 * 벡터 의 형태임.
# array([0., 1., 0.])

검증을 통해 $Ax = \lambda x$가 올바름을 알 수 있다.



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

  • 매개변수 : 1차원 벡터 (np.array)
  • 반환값 : 인자로 주어진 벡터의 L2 Norm값 (number)
    import numpy as np
    mat = ([1,2,3,4])
    def get_L2_norm(mat):
      return np.linalg.norm(mat, 2)
    get_L2_norm(mat)
    


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

  • 매개변수 : 2차원 벡터(np.array)
  • 반환값 : 인자로 주어진 벡터가 singular하면 True, non-singular하면 False를 반환
    # det값이 0이면 singular matrix(특이 행렬)이다!
    mat = ([1,2],[3,4])
    def is_singular(mat):
      answer = np.linalg.det(mat)
      if answer == 0:
          return True
      else:
          return False
    is_singular(mat)