행렬은 뭔가요?
행렬(matrix)은 벡터를 원소로 가지는 2차원 배열이다.
- 열 벡터를 원소로 가지는 2차원 배열
- numpy에서는 열벡터가 아니라 행벡터를 원소로 가져간다고 생각하시면 조금 더 이해가 쉬울 것 같다.
예시
import numpy as np
x = np.array([[1, -2, 3],
[7, 5, 0],
[-2, -1, 2]])
print(x)
[[ 1 -2 3]
[ 7 5 0]
[-2 -1 2]]
X=⎣⎢⎢⎢⎢⎡x1x2⋮xn⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2⋯⋯⋱⋯x1mx2m⋮xnm⎦⎥⎥⎥⎥⎤
아래와 같이 표기하기도 한다.
- i번째 행의 j번째 원소
X=(xij)
- 행렬은 행(row)과 열(column)이라는 인덱스(index)를 가짐
- 행렬의 특정 행(열)을 고정하면 행(열)벡터라고 부른다.
전치행렬(transpose matrix)은 행과 열의 인덱스가 바뀐 행렬을 의미한다.
XT=(xji)
** 벡터도 transpose 연산을 할 수 있다.
행렬을 이해하자
벡터가 공간에서 한 점을 의미한다면 행렬은 여러 점들을 나타낸다.
행렬의 행벡터 xi는 i번째 데이터를 의미한다.
- 행렬의 xij 는 i번째 데이터의 j번째 변수의 값을 말한다.
행렬의 덧셈, 뺄셈, 성분곱, 스칼라곱
행렬끼리 같은 모양을 가지면 덧셈, 뺄셈을 계산할 수 있다.
X±Y=(xij±yij)
위와 같으므로 아래의 예시로 이해해볼 수 있다.
X=⎣⎢⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2⋯⋯⋱⋯x1mx2m⋮xnm⎦⎥⎥⎥⎥⎤Y=⎣⎢⎢⎢⎢⎡y11y21⋮yn1y12y22⋮yn2⋯⋯⋱⋯y1my2m⋮ynm⎦⎥⎥⎥⎥⎤
이렇게 X와 Y가 있다고 가정한다면, 아래처럼 연산을 할 수 있게 된다.
X±Y=⎣⎢⎢⎢⎢⎡x11±y11x21±y21⋮xn1±yn1x12±y12x22±y22⋮xn2±yn2⋯⋯⋱⋯x1m±y1mx2m±y2m⋮xnm±ynm⎦⎥⎥⎥⎥⎤
행렬의 성분곱 또한 벡터와 같다.
X∘Y=(xijyij)
위와 같은 정의를 가졌기 때문에 아래와 같은 결과가 나올 수 있게 된다.
X∘Y=⎣⎢⎢⎢⎢⎡x11y11x21y21⋮xn1yn1x12y12x22y22⋮xn2yn2⋯⋯⋱⋯x1my1mx2my2m⋮xnmynm⎦⎥⎥⎥⎥⎤
행렬의 스칼라곱 또한 같다.
αX=(αxij)
정의는 위와 같게 되며, 적용된 행렬은 아래와 같다.
αX=⎣⎢⎢⎢⎢⎡αx11αx21⋮αxn1αx12αx22⋮αxn2⋯⋯⋱⋯αx1mαx2m⋮αxnm⎦⎥⎥⎥⎥⎤
행렬 곱셈
행렬의 곱셈은 벡터의 곱셈과 조금 다르다.
행렬 곱셈(matrix multiplication)은 i번째 행벡터와 j번째 열벡터 사이의 내적을 성분으로 가지는 행렬을 계산한다.
- 행렬곱은 X의 열의 개수와, Y의 행의 개수가 같아야 한다.
어떤 행렬을 앞에 놓을지, 뒤에 놓을지에 따라 결과가 달라지기 때문에 중요하다.
X=⎣⎢⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2⋯⋯⋱⋯x1mx2m⋮xnm⎦⎥⎥⎥⎥⎤Y=⎣⎢⎢⎢⎢⎡y11y21⋮ym1y12y22⋮ym2⋯⋯⋱⋯y1ℓy2ℓ⋮ymℓ⎦⎥⎥⎥⎥⎤
XY=(k∑xikykj)
예시
import numpy as np
x = np.array([[1, -2, 3],
[7, 5, 0],
[-2, -1, 2]])
y = np.array([[0, 1],
[1, -1],
[-2, 1]])
x @ y
array([[-8, 6],
[ 5, 2],
[-5, 1]])

연산 결과는 아래와 같이 계산은 해보면 된다.
-
첫 번째 행의 첫 번째 열의 결과인 -8이 어떻게 나오게 된 건지 알아보자.
-8 = (1 * 0) + (-2 * 1) + (3 * -2) = 0 + (-2) + (-6)
-
첫 번째 행의 두 번째 열의 결과인 6은 어떻게 나왔을까
6 = (1 * 1) + (-2 * -1) + (3 * 1) = 1 + 2 + 3
-
그렇다면 세 번째 행의 두 번째 열인 1의 결과는 어떨까?
1 = (-2 * 1) + (-1 * -1) + (2 * 1) = (-2) + 1 + 2
이렇게 나올 수 있다.
아마 직접 세 번 정도 해보면 쉽게 풀 수 있을 것이라고 생각한다.
행렬도 내적이 있을까?
numpy의 np.inner는 i번째 행벡터와 j번째 행벡터 사이의 내적을 성분으로 가지는 행렬을 계산한다.
수학에서 말하는 내적과는 다르므로 주의하자.
X=⎣⎢⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2⋯⋯⋱⋯x1mx2m⋮xnm⎦⎥⎥⎥⎥⎤Y=⎣⎢⎢⎢⎢⎡y11y21⋮yn1y12y22⋮yn2⋯⋯⋱⋯y1my2m⋮ynm⎦⎥⎥⎥⎥⎤
XY⊤=(k∑xikyjk)
예시
import numpy as np
X = np.array([[1, -2, 3],
[7, 5, 0],
[-2, -1, 2]])
Y = np.array([[0, 1, -1],
[1, -1, 0]])
np.inner(X, Y)
array([[-5, 3],
[ 5, 2],
[-3, -1]])

위의 계산 결과가 어떻게 나오게 된 것인지 알아보자
계산을 하기 위해서는 두 행렬의 행벡터의 크기가 같아야 계산이 가능하다.
- 첫 번째 행의 첫 번째 원소인
-5
-5 = 1 · 0 + (-2) · 1 + 3 · (-1) = 0 + -2 + -3
- 두 번째 행의 두 번째 원소인
2의 경우
2 = 7 · 1 + 5 · -1 + 0 · 0 = 7 + (-5) + 0
행렬을 이해하자 (2)
행렬은 벡터공간에서 사용되는 연산자(operator)로 이해한다.
이번에는 데이터를 저장하는 것이 아니라 서로 다른 데이터들을 연결시켜주는 연산자 역할로 알아보자.
- 행렬곱을 통해 벡터를 다른 차원의 공간으로 보낼 수 있다.
zi=j∑aijxj
⎣⎢⎢⎢⎢⎡z1z2⋮zn⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡a11a21⋮an1a12a22⋮an2⋯⋯⋱⋯a1ma2m⋮anm⎦⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎡x1x2⋮xm⎦⎥⎥⎥⎥⎤
z=Ax
A는 n개의 행과 m개의 열로 이뤄져 있다.
결과물인 Z는 n개의 행으로 이뤄져 있는 열벡터가 된다.
- Z의 i번째 원소는
X의 j번째 원소(xj)와 행렬 A의 각 성분(Aij)을 곱해서
모든 j에 대해 더한 값으로 만들어진다.
zi=j=1∑maijxj⟺z=Ax
행렬 A와 벡터 X 사이의 곱으로 표현되는 연산과 같다.
- 행렬곱을 통해 벡터를 다른 차원의 공간으로 보낼 수 있다.
- 행렬곱을 통해 패턴을 추출할 수 있고 데이터를 압축할 수도 있다.
모든 선형변환(linear transform)은 행렬곱으로 계산할 수 있다.
딥러닝은 선형변환과 비선형변환으로 이루어져 있기 때문에 연산이 어떻게 이뤄지는지 정확하게 이해를 해야 한다.
역행렬 이해하기
어떤 행렬 A의 연산을 거꾸로 되돌리는 행렬을 역행렬(inverse matrix)이라 부르고 A−1 라 표기한다.
역행렬은 행과 열 숫자가 같고 행렬식(determinant)이 0이 아닌 경우에만 계산할 수 있다.
AA−1=A−1A=I
I=⎣⎢⎢⎢⎢⎢⎢⎡100⋮0010⋮0001⋮0⋯⋯⋯⋱⋯000⋮1⎦⎥⎥⎥⎥⎥⎥⎤
numpy에서는 numpy.linalg.inv로 구할 수 있다.
주어진 행렬의 역행렬을 이용할 수 있다.
역행렬과 원래 주어진 행렬을 곱해주게 되면,
대각선에 오는 원소들은 거의 1이고, 나머지는 0에 가까운 숫자가 나오게 된다.

만일 역행렬을 계산할 수 없다면, 유사역행렬(pseudo-inverse) 또는 무어-펜로즈(Moore-Penrose) 역행렬 A+을 이용한다.
-
n >= m 인 경우
A+=(A⊤A)−1A⊤
-
n <= m인 경우
A+=A⊤(AA⊤)−1
- n >= m 이면 A+A=I가 성립하고
n <= m 이면 AA+=I만 성립한다.
응용 부분은.. 이어서 수정해놓겠습니다.
너무너무어려웠고요,. 망한재수시절에 기하 안했으면 진짜 영영 못 알아들었을 것만 같은 내용이었어요..
Reference