728x90
반응형

역행렬(Inverse matrix)

  • $AA^{-1} = A^{-1}A = E$
  • 선형대수학에서 가역행렬(Invertible matrix)은 그와 곱한 결과가 단위행렬인 행렬$A^{-1}$을 갖는 행렬$A$를 말한다.
  • 이 행렬$A^{-1}$를 행렬 $A$의 역행렬이라고 한다.
  • 고등학교 행렬 문제에서는 교환법칙의 성립 유/무를 묻는 문제가 많이 나온다.
  • 수능 유형 예시)

$$A(A+B)=E \rightarrow AB = BA$$

$$put) A(A + B) = E = (A+B)A\ \rightarrow \ A^2+AB=E=A^2+BA \ \rightarrow \  AB=BA$$

 

 

 

 

1. 역행렬을 구하는 방법

  • 행렬 A가 이차 정사각 행렬일 땐 다음 방법으로 구할 수 있다.

$$A = \begin{pmatrix} a & b\\ c & d \end{pmatrix},\ \ \ A^{-1}=\frac{1}{ad-bc}\begin{pmatrix} d & -b\\ -c & a \end{pmatrix}$$

  • 위 역행렬을 구하는 방법에서 $ad-bc=0$인 경우, 분모가 0이 되므로 역행렬을 만들 수 없다.
  • 즉, $ad-bc$의 값을 통해 역행렬이 존재하는지를 확인할 수 있다.
  • $ad-bc \neq 0$: $A^{-1}$이 존재한다.
  • $ad-bc = 0$: $A^{-1}$이 존재하지 않는다.
  • Python으로 역행렬을 구해보자.
>>> mat = np.array([[2, 1, 5],[0,0,1],[-1,0,2]])
>>> inv_mat = np.linalg.inv(mat)
>>> np.dot(mat, inv_mat)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
  • 만약 역행렬이 존재하지 않는 행렬이라면, 다음과 같은 오류를 반환한다.
>>> mat = np.array([[2, 1],[2,1]])
>>> inv_mat = np.linalg.inv(mat)
---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-12-72ac304bfc31> in <module>
      1 mat = np.array([[2, 1],[2,1]])
----> 2 inv_mat = np.linalg.inv(mat)

...

---> 88     raise LinAlgError("Singular matrix")
     89 
     90 def _raise_linalgerror_nonposdef(err, flag):

LinAlgError: Singular matrix

 

 

 

 

2. 이차 정사각행렬 역행렬 공식의 증명

  • 역행렬 공식의 증명은 가우스 조던 소거법(Gauss-Jordan elimination method)로 구하는 방법과 전치행렬, 소행렬, 여인자를 이용해서 구하는 방법 두 가지가 있다.
  • 그러나 이차 정사각행렬은 비교적 공식이 간단하므로, 옳바른 증명 방법은 아니긴 하지만, 위 기법들을 사용하지 않고도 구할 수 있다.
  • 행렬 $A$와 역행렬 $A^{-1}$을 다음과 같이 정의하자.

$$A=\begin{pmatrix} a & b\\ c & d \end{pmatrix},\ \ A^{-1}=\begin{pmatrix} x & y\\ z & r \end{pmatrix}$$

$$AA^{-1}=E \rightarrow \begin{pmatrix} a & b\\ c & d \end{pmatrix}\begin{pmatrix} x & y\\ z & r \end{pmatrix} = \begin{pmatrix}1 & 0\\ 0 & 1 \end{pmatrix}$$

$$ax + bz = 1 \cdots ①$$

$$ay + br = 0 \cdots ②$$

$$cx + dz = 0 \cdots ③$$

$$cy + dr = 1 \cdots ④$$

  • 위 식을 기반으로 $(ad-bc)$가 만들어지도록 4개의 식을 유도해보자

$$①*c - ③*a = (acx+bcz-c)-(acx+adz)=0\  \rightarrow \ (bc-ad)z = c \cdots ⑤$$

$$①*d-③*b = (adx+bdz-d)-(bcx+bdz)=0\ \rightarrow \ (ad-bc)x = d \cdots ⑥$$

$$②*c-④*a=(acy+bcr)-(acy+adr-a)=0\ \rightarrow \ (bc-ad)r = -a \cdots ⑦$$

$$②*d-④*b=(ady+bdr)-(bcy+bdr-b)=0\ \rightarrow \ (ad-bc)y = -b \cdots ⑧$$

  • ⑤, ⑥, ⑦, ⑧을 볼 때, $ad-bc \neq 0$이다.
  • $ad-bc=0$인 경우, 행렬 $A$가 영행렬이기 때문에 전제가 성립하지 않는다.
  • ⑤, ⑥, ⑦, ⑧의 양변을 $ad-bc$로 나눠보자.

$$⑤ \rightarrow z = \frac{-c}{ad-bc}$$

$$⑥ \rightarrow x = \frac{d}{ad-bc}$$

$$⑦ \rightarrow r = \frac{a}{ad-bc}$$

$$⑧ \rightarrow y = \frac{-b}{ad-bc}$$

  • ⑤, ⑥, ⑦, ⑧으로부터 유도된 $x,y,z,r$를 $A^{-1}$에 대입하자.

$$A^{-1}=\frac{1}{ad-bc} \begin{pmatrix} d & -b\\ -c & a \end{pmatrix}$$

  • 이차 정사각행렬의 역행렬을 구하는 공식이 유도 되었다.

 

 

 

 

3. 역행렬의 성질

3.1. $(A^{-1})^{n} = (A^{n})^{-1}$

  • $A$의 역행렬이 존재하면, $A^n$의 역행렬도 존재한다.
  • 즉, $A^{100}$의 역행렬이 존재한다면, $A^{20}$의 역행렬도 존재한다는 소리다.

 

3.2. $(kA)^{-1} = \frac{1}{k}A^{-1}$

  • 역원의 개념이므로, 상수 k가 뒤집어진다.
  • $k=0$인 경우, 어차피 영행렬이므로, 역행렬이 존재하지 않는다.

 

3.3. $(AB)^{-1} = B^{-1}A^{-1},\ \ (APB)^{-1} = B^{-1}P^{-1}A^{-1}$

 

3.4. 차수가 같은 두 행렬 A,B 모두 역행렬이 존재한다면, AB역시 역행렬이 존재한다.

  • 역, 대우 모두가 참인 성질이다.
  • 역) A, B중 적어도 하나가 역행렬이 존재하지 않는다면, AB의 역행렬 또한 존재하지 않는다.
  • 대우) AB가 역행렬이 없으면, A, B 중 적어도 하나는 반드시 역행렬이 존재하지 않는다.
728x90
반응형

'Python으로 하는 기초 수학 > 행렬' 카테고리의 다른 글

연립일차방정식과 가우스 소거법(Gaussian elimination)  (0) 2021.02.26
영인자(Zero Divisor)  (0) 2021.02.25
행렬의 성질  (0) 2021.02.25
행렬(Matrix)  (0) 2021.02.25
728x90
반응형

지금까지 행렬 생성과 행렬에 대한 기본적인 조작, 데이터 접근, 행렬 연산 등에 대해 학습해 보았다.

이번에는 포스트에선 역행렬, 가운데 행렬과 같은 약간 독특한 행렬들에 대해 학습해보자.

 

역행렬(Inverse Matrix)

  • 역행렬은 행렬의 역수라고 할 수 있으며, 행렬 A와 곱했을 때 단위 행렬 E가 나오게 하는 행렬을 A의 역행렬이라고 한다.
  • 역행렬은 정방행렬(n x n)에 대해서만 구할 수 있다. 장방행렬(n x m)에 대해서는 구할 수 없다.
  • solve()
    : 수식 A %*% X = B에서 X인 행렬을 구한다. 즉, A와 행렬곱 하여 B가 만들어지게 하는 행렬 X를 구한다.
  • 주요 Parameter
    : solve(A, B, ...)
    B의 자리를 공란으로 넣는다면, A의 역행렬을 구한다.
vt3 = c(4, 2, 3, 0, 1, 0, 2, 3, 0, 2, 1, 4, 0, 2, 1, 3)
mat3 = matrix(vt3, nrow = 4, byrow = TRUE)
mat3
##      [,1] [,2] [,3] [,4]
## [1,]    4    2    3    0
## [2,]    1    0    2    3
## [3,]    0    2    1    4
## [4,]    0    2    1    3
solve(mat3)
##             [,1]       [,2]  [,3]       [,4]
## [1,]  0.33333333 -0.3333333  2.00 -2.3333333
## [2,]  0.08333333 -0.3333333 -0.25  0.6666667
## [3,] -0.16666667  0.6666667 -2.50  2.6666667
## [4,]  0.00000000  0.0000000  1.00 -1.0000000

 

 

 

전치행렬(Transpose Matrix)

  • R(기초) 행렬(Matrix)(2부)에서 잠깐 다뤘던 전치행렬에 대해서 다시 한번 정리하겠다.
  • m*n 행렬의 행과 열을 서로 바꾼 n*m 행렬로 만든 것을 전치 행렬이라고 한다.
  • 주대각선(Main Diagonal)을 기준으로 하여 뒤집은 것을 가리킨다.
    ※ (1,1), (2,2), (3,3).... 과 같이 행과 열의 값이 같은 행렬의 가운데 부분을 주대각선(대각성분)이라 한다.
  • t()
    : 전치행렬로 만든다.

※ 대각성분(주대각선)인 (1,1), (2,2), (3,3)을 기준으로 뒤집은 것이 전치 행렬이다.

mat <- matrix(c(1:12), nrow = 4, byrow = TRUE)
mat
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
## [4,]   10   11   12
t(mat)
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12

 

 

 

대칭행렬(Symmetric Matrix)

  • 대각성분을 중심으로 대칭인 정방행렬(n*n)을 가리킨다.
  • 대각성분을 중심으로 대칭이므로, 원래 행렬과 전치행렬은 동일하다.
  • 대칭행렬을 만들고 싶다면, 일반 행렬을 생성하고, 상삼각행렬 혹은 하삼각행렬의 위치에 대하여, 그 전치행렬의 값을 덮어 씌우면 된다.
    (무슨 말인지 모르겠지만, 실습을 하며 천천히 따라와보면 이해하게 될 것이다.)
# 대칭행렬을 만들어보자
mat = matrix(c(1:16), nrow = 4, byrow = TRUE)
mat
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
## [3,]    9   10   11   12
## [4,]   13   14   15   16
  •  c(1:16)으로 1~16까지 값이 들어간 벡터로, 정방행렬(4*4)을 만들었다.
# 하삼각행렬의 값들을 가져와보자
lower.tri(mat, diag = FALSE)
##       [,1]  [,2]  [,3]  [,4]
## [1,] FALSE FALSE FALSE FALSE
## [2,]  TRUE FALSE FALSE FALSE
## [3,]  TRUE  TRUE FALSE FALSE
## [4,]  TRUE  TRUE  TRUE FALSE
  •  lower.tri()는 하삼각행렬을 만들 때 사용하는 함수로, 뒤에서 다시 한번 다루겠지만, 가운데 성분을 기준으로하여, 아랫쪽을 TRUE로 Masking한다.
    (상삼각행렬을 쓰는 경우엔, upper.tri()를 쓰면 되며, 방법은 동일하다.)
  •  lower.tri()의 parameter인 diag는 대각성분을 포함할 것인지 여부이다.
mat[lower.tri(mat, diag = FALSE)]
## [1]  5  9 13 10 14 15
  • 벡터, 행렬에서 Indexing을 할 때, 우리는 대괄호를 사용하여 가져왔었는데, 이 대괄호는 TRUE로 Masking된 값들을 가져오는 것이다.
# 전치행렬에 대한 하삼각행렬의 위치의 값을 본 행렬의 하삼각행렬 위치에 넣도록 하자.
mat[lower.tri(mat, diag = FALSE)] <- t(mat)[lower.tri(mat, diag = FALSE)]
mat
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    2    6    7    8
## [3,]    3    7   11   12
## [4,]    4    8   12   16
  • 조금 복잡해보이지만, 원리는 되게 단순하다.
  • 대칭행렬은 대각성분을 중심으로 대칭인 행렬이고, 전치행렬은 대각성분을 중심으로 반전된 행렬이다.
  • 즉, 원래의 행렬의 하삼각행렬(or 상삼각행렬)에 전치행렬의 하삼각행렬(or 상삼각행렬)의 위치의 값을 넣으면, 대칭행렬이 만들어지는 것이다.
  • 이를 더 풀어서 써보면 가운데 성분 아래(하삼각행렬의 위치 = TRUE로 Masking 된 곳)에 가운데 성분 위의 값을 가운데 성분을 중심으로 뒤집어서(전치 행렬) 가운데 성분 아래에 그대로 넣었다고 생각하면 된다.

 

 

 

대각 행렬(Diagonal Matrix)

  • 대각행렬은 대칭행렬과 비슷해보이지만, 생성 난이도는 보다 쉬운 행렬이다.
  • 대각행렬은 정방행렬(n*n)에서 대각성분을 제외한 모든 값이 0인 경우를 말한다.
  • diag()
    : 행렬의 대각성분을 가지고 오거나, 대각성분에 다른 값을 넣을 수 있게 해주는 함수, diag(Vector)를 하는 경우, 대각행렬이 생성된다.
  • 항등행렬(Identity Matrix)는 대각성분이 1이고 나머지 원소는 0인 행렬이므로, 대각성분을 모두 1로 생성하면 된다.
# 대각행렬을 만들어보자.
diag(c(1:5))
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    0    0    0    0
## [2,]    0    2    0    0    0
## [3,]    0    0    3    0    0
## [4,]    0    0    0    4    0
## [5,]    0    0    0    0    5
  • 가운데 성분을 제외하고 모두 0인 대각행렬을 만들어보았다.
# 대각성분을 가지고 와보자
mat <- matrix(c(1:16), nrow = 4)
mat
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16
diag(mat)
## [1]  1  6 11 16
  • diag() 함수를 이용하면, 행렬의 대각성분만 벡터로 가지고 올 수 있다.
# 대각성분의 원소를 모두 0으로 만들자
diag(mat) <- 0
mat
##      [,1] [,2] [,3] [,4]
## [1,]    0    5    9   13
## [2,]    2    0   10   14
## [3,]    3    7    0   15
## [4,]    4    8   12    0
  • 행렬의 대각성분에 스칼라 값을 넣어서 대각성분이 0인 행렬을 만들어보았다.
  • 대칭행렬 만들기와 대각성분을 0으로 만들기를 조합하여 코드를 짜면 대칭행렬이면서 대각성분이 0인 행렬을 만들 수 있다.

 

 

 

하삼각행렬(Lower Triangular Matrix)과 상삼각행렬(Upper Triangular Matrix)

  • 하삼각행렬은 대각성분을 중심으로, 그 윗 부분이 모두 0인 정방행렬을 말한다.
  • 상삼각행렬은 대각성분을 중심으로, 그 아랫 부분이 모두 0인 정방행렬을 말한다.
  • lower.tri()
    : 행렬의 가운데 성분을 기점으로(가운데 성분 포함 가능), 아랫 부분을 TRUE로 Masking하는 함수
  • upper.tri()
    : 행렬의 가운데 성분을 기점으로(가운데 성분 포함 가능), 윗 부분을 TRUE로 Masking하는 함수
  • 상삼각행렬은 대각성분을 중심으로, 아랫 부분이 0이므로, lower.tri()함수를 이용해 대각성분 아래쪽을 indexing하여 0을 집어넣으면 된다.
  • 하삼각행렬은 대각성분을 중심으로, 윗 부분이 0이므로, upper.tri()함수를 이용해 대각성분 위쪽을 indexing하여 0을 집어넣으면 된다.
# 상삼각행렬을 만들어보자.
mat = matrix(c(1:16), 4)
lower.tri(mat, diag = FALSE)
  • diag = FALSE 로 Parameter를 부여하여, 가운데 성분은 Masking하지 않도록 하자.
##       [,1]  [,2]  [,3]  [,4]
## [1,] FALSE FALSE FALSE FALSE
## [2,]  TRUE FALSE FALSE FALSE
## [3,]  TRUE  TRUE FALSE FALSE
## [4,]  TRUE  TRUE  TRUE FALSE
mat[lower.tri(mat, diag = FALSE)] <- 0
mat
  • 선택된 가운데 성분의 아랫부분에 0을 넣어서 상삼각행렬을 만들었다.
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    0    6   10   14
## [3,]    0    0   11   15
## [4,]    0    0    0   16
# 하삼각행렬을 만들어보자.
mat = matrix(c(1:16), 4)
upper.tri(mat, diag = FALSE)
##       [,1]  [,2]  [,3]  [,4]
## [1,] FALSE  TRUE  TRUE  TRUE
## [2,] FALSE FALSE  TRUE  TRUE
## [3,] FALSE FALSE FALSE  TRUE
## [4,] FALSE FALSE FALSE FALSE
mat[upper.tri(mat, diag = FALSE)] <- 0
mat
##      [,1] [,2] [,3] [,4]
## [1,]    1    0    0    0
## [2,]    2    6    0    0
## [3,]    3    7   11    0
## [4,]    4    8   12   16

 

 

자, 지금까지 역행렬, 전치행렬, 대각행렬, 대칭행렬, 상삼각행렬, 하삼각행렬에 대해 알아보았다. 행렬은 이 것보다 훨씬 심도 깊은 분야기 때문에, R의 기초인 데이터 타입 공부에선 기본적으로 알아야하는 부분만 짚고 넘어가도록 하겠다.

다음 포스트에선 배열(Array)에 대해 학습해보도록 하겠다.

728x90
반응형

'R > Basic' 카테고리의 다른 글

R(기초) 데이터프레임(Data Frame)(1부)  (0) 2020.06.21
R(기초) 배열(Array)  (0) 2020.06.19
R(기초) 행렬(Matrix)(2부)  (0) 2020.06.19
R(기초) 행렬(Matrix)(1부)  (0) 2020.06.18
R(기초) 연산자와 변수 타입  (0) 2020.06.18

+ Recent posts