728x90
반응형

연립일차방정식과 가우스 소거법

  • 앞서 행렬은 연립일차방정식의 계수와 변수를 분리하여 사용하게 되면서 등장하였다고 했다.
  • 앞서 행렬의 기본적인 성질은 배웠으니, 이제 연립일차방정식과 행렬이 어떻게 연결되는지에 대해 알아보자.
  • 연립일차방정식을 통해 첨가 행렬을 만들어보고, 가우스 소거법으로 연립일차방정식을 풀이해보자.

 

 

 

 

1. 연립일차방정식(System of Linear equations)

1.1. 일차방정식(Linear equation)

  • 미지수 $x_1, x_2, x_3, ..., x_n$에 관한 일차방정식은 상수 $b$와 계수 $a_1, a_2, a_3, ..., a_n$이 실수일 때, 다음과 같은 꼴로 나타나는 방정식이다.
  • 일차방정식이므로, 미지수 $x_1, x_2, x_3, ..., x_n$의 차수는 1이다.

$$a_1x_1 + a_2x_2 + a_3x_3 + \cdots a_nx_n = b$$

 

1.2. 연립일차방정식(System of Linear equations)

  • 미지수 $x_1, x_2, x_3, ..., x_n$에 대하여 유한개의 일차방정식 모임은 아래와 같다.

$$a_{11}x_1 + a_{12}x_2 + a_{13}x_3 + \cdots a_{1n}x_n = b_1$$

$$a_{21}x_1 + a_{22}x_2 + a_{23}x_3 + \cdots a_{2n}x_n = b_2$$

$$a_{31}x_1 + a_{32}x_2 + a_{33}x_3 + \cdots a_{3n}x_n = b_3$$

$$ \vdots $$

$$a_{m1}x_1 + a_{m2}x_2 + a_{m3}x_3 + \cdots a_{mn}x_n = b_m$$

  • 실수 $b_1, b_2, b_3, ..., b_m$이 모두 0이면 이 연립방정식을 동차(Homogeneous)라 하며, 반대의 경우에는 비동차(non-Homogeneous)라 한다.
  • 미지수 $x_1, x_2, x_3, ..., x_n$에 대하여 어떤 수 $s_1, s_2, s_3, ..., s_n$을 각각 대입하여, 각 방정식이 모두 성립하면 어떤 수 $s_1, s_2, s_3, ..., s_n$을 연립일차방정식의 해(Solution)이라 한다.
  • 연립일차방정식의 해 전체 집합을 연립일차방정식의 해집합(Solution set)이라 한다.
  • 동일한 해집합을 가지는 두 연립일차방정식을 동치(Equivalent)라고 한다.
  • 연립일차방정식의 해에 대하여, 일반적으로 다음 중 하나가 성립한다.
  1. 해를 갖지 않는다.
  2. 유일한 해를 갖는다.
  3. 무수히 많은 해를 갖는다.

 

1.3. 연립일차방정식과 행렬

  • 위 연립일차방정식을 행렬로 나타내면 다음과 같다.

$$A = \begin{pmatrix}
 A_{11}& A_{12} & A_{13}  & ... & A_{1n}\\ 
 A_{21}& A_{22} & A_{23}  & ... & A_{2n}\\ 
 A_{31}& A_{32} & A_{33}  & ... & A_{3n}\\ 
 \vdots & \vdots & \vdots & \ddots & \vdots\\
 A_{m1}& A_{m2} & A_{m3}  & ... & A_{mn}\\
\end{pmatrix},\ \ \  

X = \begin{pmatrix}
x_1\\ 
x_2\\ 
x_3\\ 
\vdots \\
x_n
\end{pmatrix},\ \ \ 

B = \begin{pmatrix}
b_1\\ 
b_2\\ 
b_3\\ 
\vdots \\
b_m
\end{pmatrix}$$

$$AX = B$$

  • 우리가 지금까지 봐왔던, 행렬은 바로 $A$로 이를 계수행렬(Coefficient matrix)라 한다.

 

 

 

 

2. 첨가행렬(Augmented matrix)

  • 계수행렬 $A$와 상수항들이 모여서 만들어진 행렬$B$를 붙이면 첨가행렬(Augmented matrix)가 만들어진다.

$$(A | B) = \begin{pmatrix}
 A_{11}& A_{12} & A_{13}  & ... & A_{1n} | b_1\\ 
 A_{21}& A_{22} & A_{23}  & ... & A_{2n} | b_2\\ 
 A_{31}& A_{32} & A_{33}  & ... & A_{3n} | b_3\\ 
 \vdots & \vdots & \vdots & \ddots & \ \ \ \vdots \ \ | \ \vdots \\
 A_{m1}& A_{m2} & A_{m3}  & ... & A_{mn} | b_m\\
\end{pmatrix}$$

  • 첨가행렬은 행렬 방정식의 풀이와 역행렬 구하기에 응용된다.
  • 가우스 소거법을 사용하여 연립일차방정식을 풀이해보자.

 

 

 

 

3. 가우스 소거법(Gaussian elimination)

  • 선형대수학에서, 가우스 소거법은 연립일차방정식을 풀이하는 알고리즘으로, 풀이 과정에서 일부 미지수가 차츰 소거되어, 남은 미지수에 대한 선형 결합으로 풀이가 완성된다.
  • 가우스 소거법은 보통 행렬을 사용하며, 첨가 행렬을 그와 풀이가 더 간단한 행렬로 변환하여 풀이를 완성한다.
  • 가우스 소거법은 행렬식과 역행렬의 계산에도 응용된다.
  • 가우스 소거법은 맨 위 일차방정식부터 임의의 k를 곱해가며 아래에 있는 일차방정식들을 하나하나 맨 앞의 계수부터 0으로 만들어가는 방법으로, 최종적으로 주대각선의 모든 값이 1인 상삼각행렬을 만들게 된다.
  • 내용이 조금 길기 때문에 손으로 풀어보겠다.

  • 가우스 소거법은 위에서부터 천천히 아래로 내려가면서, 주대각성분이 1인 상삼각행렬을 만들어가면 된다.
  • $①$, 최초 첨가행렬에서 첫 번째 행 $R_1$의 첫 원소인 $A_{11}=4$는 주대각성분이므로 이를 1로 만들어주기 위해, $R_1$에 $\frac{1}{4}$를 곱해주어, $A_{11}=1$로 만들어주었다.
  • $②$, 두 번째 행 $R_2$의 첫 원소인 $A_{21}=2$을 0으로 만들어주기 위해, $R_1$의 인자들에 $-2$를 곱하여 $R_2$에 더해주었다.
  • $③$, 세 번째 행 $R_3$의 첫 원소인 $A_{31}=3$을 0으로 만들어주기 위해, $R_1$의 인자들에 $-3$을 곱하여 $R_3$에 더해주었다.
  • $④$, 두 번째 행 $R_2$의 두 번째 원소인 $A_{22}=\frac{1}{2}$은 주대각성분이므로, $1$로 만들어주기 위해, $2$를 $R_2$에 곱해주었다.
  • $⑤$, 세 번째 행 $R_3$의 두 번째 원소인 $A_{32}=-\frac{33}{4}$를 0으로 만들어주기 위해, $R_2$에 $\frac{33}{4}$를 곱하여, $R_3$에 더해주었다.
  • 이를 통해, 연립일차방정식의 해인 $x=2,\ y=-1,\ z=3$을 찾았다.

 

 

 

 행렬이 연립일차방정식에서 어떻게 나오게 되었고, 행렬을 이용해서 연립일차방정식의 해를 쉽게 찾을 수 있는 가우스 소거법에 대해 간단하게 학습해보았다.

 다음 포스트에서는 가우스 소거법에 대해 좀 더 알아보도록 하자.

728x90
반응형

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

역행렬(Inverse matrix)  (0) 2021.02.26
영인자(Zero Divisor)  (0) 2021.02.25
행렬의 성질  (0) 2021.02.25
행렬(Matrix)  (0) 2021.02.25
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
반응형

영인자(Zero Divisor)

  • $A \neq O,\ B \neq O,\ AB = O$
  • $ A \neq O,\ A^2 = O$
  • 행렬 $A$와 행렬 $B$가 영행렬이 아님에도 불구하고, 행렬 $AB$를 행렬곱하였을 때, 영행렬이 나오는 경우
  • 위에서 보듯 $A$는 제곱하였을 때, 영행렬이 나왔다. 영인자의 존재로 인해 행렬에서는 방정식의 근, 지수법칙을 사용할 수 없다.
  • 고등학교 행렬 문제에서 영인자의 존재는 수많은 반례를 가지고 오므로, 요주의 대상이다.

 

 

1. 영인자의 곱 순서

$$AB = O\ \overset{F}{\rightarrow} BA = O$$

$$ AB = O\ \overset{F}{\rightarrow} BA \neq O $$

  • 영인자는 특정한 배열의 곱에서만 영행렬이 된다.
  • 물론, 예외 역시 존재하기 때문에 $AB = BA = O$이 되는 경우도 존재한다.
>>> mat1 = np.array([[0, 0],[2, -2]])
>>> mat2 = np.array([[1, 0],[1, 0]])
>>> np.dot(mat1, mat2)
array([[0, 0],
       [0, 0]])
       
>>> np.dot(mat2, mat1)
array([[0, 0],
       [0, 0]])

 

 

 

 

2. 영인자는 역행렬을 가지지 않는다.

2.1. 증명

  • 다음과 같은 정사각행렬 $A$가 있다고 하자.
  • $ A \neq O \rightarrow A^2 = O $
  • 위 조건을 만족하는 행렬 $A$는 영행렬이 아니므로, 영인자이다.
  • 정사각행렬이므로, 케일리 헤밀턴의 정리를 사용해보자
  • $ A^2 - (a+d)A + (ad - bc)E = O $
  • $A^2 = O$이고, $A \neq O,\ E \neq O$이므로, $(ad-bc)E = (a+d)A$가 성립해야한다.
  • 그러나, 단위행렬의 배수는 제곱하여 영행렬이 될 수 없으므로, 영인자인 행렬 $A$는 단위행렬의 배수가 아니다.
  • 그러므로, $(a+b)=0, (ad-bc)=0$이 성립한다.
  • $ad-bc=0$이므로, 역행렬 생성 법칙에 따라, 영인자 $A$는 역행렬을 가질 수 없다.

 

2.2. 케일리 헤밀턴 정리(Cayley–Hamilton theorem)

  • 이차 정사각행렬 $A$에 대하여 케일리 헤밀턴 정리를 사용하면, 행렬의 거듭제곱을 아주 쉽게 구할 수 있다.
  • $A \neq kE$일 때 사용 가능하다(행렬 $A$가 단위행렬의 배수가 아닐 때).

$$ A = \begin{pmatrix}
a & b\\ 
c & d
\end{pmatrix} \neq kE $$

$$ A^2 - (a+d)A + (ad - bc)E = O $$

  • 케일리 헤밀턴 정리 사용 예시

$$A = \begin{pmatrix}
1 & 2\\ 
3 & 4
\end{pmatrix}$$

$$A^2 - 5A -2E = O \rightarrow A^2 = 5A + 2E$$

 

2.3. 영인자와 역행렬 관계

  • 위에서 봤듯이 영인자인 행렬은 역행렬이 존재할 수 없다.
  • 반대로 말하자면, 역행렬이 존재하는 행렬은 영인자가 아니라는 소리다.
  • 만약 행렬 $A$와 $B$가 역행렬이 존재한다면 영인자가 아니라는 의미이므로, 다음 공식이 성립한다.

$$(AB)^2 = A^2B^2 \ \overset{T}{\rightarrow}\ AB=BA$$

$$ABAB = AABB$$

$$A^{-1}ABABB^{-1} = A^{-1}AABBB^{-1}$$

$$BA = AB$$

  • 그러나 행렬은 3차 이상에서부터는 성립하지 않는 경우가 많으므로 위 공식도 주의해야한다.

$$(AB)^3 = A^3B^3 \ \overset{F}{\rightarrow}\ AB=BA$$

$$ABABAB = AAABBB$$

$$A^{-1}ABABABB^{-1} = A^{-1}AAABBBB^{-1}$$

$$BABA = AABB$$

  • $BABA = ABAB$와 $BA = AB$는 다르다.

 

 

 

 

3. 영인자와 지수법칙

  • 영인자의 존재로 인해 행렬에서는 지수법칙을 사용하기가 어렵다.
  • 영인자의 존재로 인해 행렬은 지수에 대하여 다음과 같은 성질을 갖는다.

$$A^n(n\geq 3)\ \overset{F}{\rightarrow}\ A=O$$

$$A^n(n\geq 3)\ \overset{T}{\rightarrow}\ A^2=O$$

  • 영인자의 존재로 인해, 위 명제에서 행렬 $A=O$이라고 할 수 없다.
  • 행렬 $A$가 영인자인 경우 $A^2=O$이므로, 그 이상의 차수에서도 모두 영행렬이 나오게 된다.

 

3.1. 지수법칙이 반드시 성립불가한 것은 아니다.

  • 하나의 행렬에서는 지수법칙이 성립한다.

$$A^m*A^n = A^{m+n},\ (m, n \in N)$$

$$(A^m)^n = A^{mn}$$

  • 그러나, 하나의 행렬이 아닌 경우에는 성립하지 않는다.
  • 이는 교환법칙이 성립하지 않기 때문이다.

$$(AB)^n \neq A^nB^n$$

$$ABABABAB \neq AAAABBBB$$

 

3.2. 영인자와 지수법칙

$$(AB)^n = A^nB^n \overset{F}{\rightarrow} AB = BA$$

  • 영인자의 존재로 인해 위 명제는 성립하지 않는다.

 

3.2.1. 증명

  • $AB = O$로 영인자라고 가정해보자.
  • 영인자의 성질로 인해 $BA \neq O$일 수 있다.

$$(AB)^n = O,\ A^nB^n = AA\cdots AABB\cdots BB = O$$

  • 영인자 AB의 존재로 인해 $(AB)^n = A^nB^n$은 성립하였으나, $AB=BA$는 성립하지 않는다.

 

3.2.2. 역은 성립한다.

$$(AB)^n = A^nB^n \overset{T}{\leftarrow} AB = BA$$

  • $AB = BA$라는 말은 $AB$가 영인자인 경우라 할지라도 $AB=BA=O$이 성립하고, 교환 법칙이 성립할수도 있다는 의미이기 때문이다.
728x90
반응형

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

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

행렬의 성질

  • 전제: $M_{(m*n)},\ A \in M,\ B \in M, \ C \in M$

 

 

1. 기본 연산

1.1. 행렬의 덧셈과 뺄셈

  • $A + B \in M$, $A - B \in M$
  • 동형인 행렬끼리만 +, -가 가능하다(행렬은 덧셈 뺄셈에 대하여 닫혀 있다.)
>>> Mat1 = np.arange(0, 15).reshape((3,5))
>>> Mat2 = np.full((3,5), 3)
>>> Mat1 + Mat2
array([[ 3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12],
       [13, 14, 15, 16, 17]])
       
>>> Mat1 - Mat2
array([[-3, -2, -1,  0,  1],
       [ 2,  3,  4,  5,  6],
       [ 7,  8,  9, 10, 11]])

 

1.2. 행렬의 곱셈

  • $AB^T \notin M$
  • 행렬끼리 곱을 하면 행과 열의 모양이 바뀐다.
  • 행렬끼리 곱을 하려면, 앞의 행렬의 열과 뒤의 행렬의 행의 크기가 동일해야 한다.
  • 위 조건을 만족할 때, 출력된 행렬의 모양은 앞 행렬의 행($l$)과 뒤 행렬의 열($n$)의 모양인 행렬($l*n$)이 나온다.
  • $(l * m) * (m * n) = (l * n) $ 
  • 행렬은 행렬끼리의 곱에 대하여 닫혀있지 않다고 할 수 있으나, 정방 행렬 간의 곱에 대해서는 닫혀 있다고 할 수 있다.
    $m = n,\ AB \in M$
# 행렬 곱 시, 행렬의 모양이 바뀐다.
>>> Mat1 = np.arange(0, 15).reshape((3,5))
>>> Mat2 = np.full((3,5), 3)
>>> np.dot(Mat1, Mat2.T)
array([[ 30,  30,  30],
       [105, 105, 105],
       [180, 180, 180]])
       
# 정방행렬끼리의 곱을 하는 경우, 행렬 모양이 유지된다.
>>> Mat3 = np.arange(0, 9).reshape((3,3))
>>> Mat4 = np.full((3,3), 3)
>>> np.dot(Mat3, Mat4)
array([[ 9,  9,  9],
       [36, 36, 36],
       [63, 63, 63]])

 

 

 

 

2. 결합 법칙

2.1. 덧셈의 결합 법칙

  • $(A+B)+C = A+(B+C)$
  • 행렬의 덧셈과 뺄셈은 각 행렬의 형태가 동일해야 하며, 그 순서를 어떻게 하는지는 상관없다.
>>> Mat1 = np.arange(0, 15).reshape((3,5))
>>> Mat2 = np.repeat(np.array([1,2,3]), 5).reshape((3,5))
>>> Mat3 = np.array([[1,3,5,7,9],[2,4,6,8,10],[3,6,9,12,15]])
>>> (Mat1 + Mat2) + Mat3 == Mat1 + (Mat2 + Mat3)
array([[ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True]])

 

2.2 곱셈의 결합 법칙

  • $A(B^TC) = (AB^T)C$
>>> Mat1 = np.arange(0, 15).reshape((3,5))
>>> Mat2 = np.array([[1,3],[2,4],[3,6],[4,8],[5,10]])
>>> Mat3 = np.array([[1,3,5,7,9,11,13],[2,4,6,8,10,12,14]])
>>> np.dot(np.dot(Mat1,Mat2),Mat3) == np.dot(Mat1,np.dot(Mat2,Mat3))
array([[ True,  True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True]])

 

 

 

 

3. 항등원(Identity Elementa)

3.1 행렬의 덧셈의 항등원

  • $ A + O = O + A = A$
  • 영행렬은 행렬의 덧셈의 항등원이다.
  • 뺄셈은 부호가 바뀌게 되므로 항등원이 없다.
>>> Mat1 = np.arange(0, 15).reshape((3,5))
>>> Mat2 = np.zeros((3,5))
>>> Mat1 + Mat2 == Mat2 + Mat1
array([[ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True]])

 

3.2. 행렬의 곱셈의 항등원

  • $AE = EA = A$
  • 모든 정방 행렬 $A$에 대하여 단위행렬 $E$를 곱하면 행렬 $A$가 나온다.
>>> Mat1 = np.arange(0, 16).reshape((4,4))
>>> Mat2 = np.identity(4)
>>> np.dot(Mat1, Mat2) == Mat1
array([[ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]])
       
>>> Mat1 == np.dot(Mat1, Mat2)
array([[ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True]])

 

 

 

 

4. 역원

4.1. 덧셈에 대한 역원

  • $A+(-A) = (-A) + A = O$
>>> Mat1 = np.arange(0, 12).reshape((4,3))
>>> Mat1 + (-Mat1) == (-Mat1) + Mat1
array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]])
       
>>> Mat1 + (-Mat1)
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

 

4.2. 곱셈에 대한 역원

  • $AA^{-1} = A^{-1}A = E$
  • 역행렬을 갖지 않는 경우도 존재하므로, 항상 성립하는 것은 아니다.
  • $AB = BA = E$인 경우 B는 A의 역행렬이다.
>>> Mat = np.array([[0, 1],[2, 3]])
>>> Inv_Mat = np.linalg.inv(Mat)
>>> np.dot(Mat, Inv_Mat)
array([[1., 0.],
       [0., 1.]])

 

4.3. 곱셈에 대한 역원에서 파생된 행렬 성질

  • $A(A+B) = E \Rightarrow AB = BA$

4.3.1. 증명

  • $A(A+B) = E$이므로, $A^{-1}$은 존재한다. $A^{-1} = (A+B)$이므로, 다음 식이 성립한다.

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

 

 

 

 

5. 교환 법칙

5.1. 행렬의 교환 법칙은 성립하지 않는다.

  • $AB \neq BA$
  • 교환법칙이 성립하지 않으므로 곱셈법칙, 지수법칙을 적용할 수 없다(항상은 아니며, 가능한 경우도 있으므로, 부분적으로 사용 가능하다).
  • 대우: 곱셈법칙이 성립한다면 $AB = BA$가 성립한다. [거짓]
  • 행렬에서는 대우 명제마저도 성립하지 않을 수 있다.

5.1.1 증명

$$(A+B)^2 = A^2 + 2AB + B^2\ \overset{T}{\rightarrow} \ AB = BA \cdots (1)$$

$$(A+B)^3 =  A^2 + 3A^2B + 3AB^2 + B^3 \ \overset{F}{\rightarrow} \ AB = BA \cdots (2)$$

  • $AB$가 영인자인 경우, $A^2 + 3AAB + 3ABB + B^3 = A^3 + B^3 =  A^2 + 3A^2B + 3AB^2 + B^3$은 성립한다.
  • $AB$는 영인자이므로, $AB=O$은 성립하나, $BA \neq O$이다.
  • 행렬에서는 영인자의 존재로 인해 2차 함수에서 성립하는 것이 3차 함수 이상에서는 성립하지 않을 수 있다.

 

5.2. 교환 법칙 관련 재밌는 공식

  • $A + B = AB$라면 $AB = BA$이다.

5.2.1. 증명

$$A + B = AB \rightarrow AB - A - B = O \rightarrow (A-E)(B-E)-E=O$$

$(A-E)(B-E)=E$이므로, $(A-E)^{-1},\ (B-E)^{-1}$이 존재한다.

$$ (A-E)(B-E)=E=(B-E)(A-E)\rightarrow BA -A-B=O $$

$$ \therefore AB = BA $$

 

 

 

728x90
반응형
728x90
반응형

 

행렬(Matrix)

 수학에서 행렬은 1개 이상의 수 또는 다항식 등을 사각형 모양으로 배열한 것이다. 가로 줄은 행(Row), 세로 줄은 열(Column)이라 부른다.

 아서 케일리와 윌리엄 로원 해밀턴이 발명했으며, 행렬식의 값에 따라 연립방정식의 해가 다르게 나오는 것을 보고, 연립 방정식의 계수와 변수를 분리하여 사용하게 되면서 행렬이 등장하게 되었다.

 

 

 

1. 행렬의 정의

  • $m * n$ 행렬은 각 행 $i \in \{1,...,m\}$ 및 열 $j \in \{1,...,n\}$의 순서쌍 $(i, j)$에 대하여, 원소 $A_{ij} \in R$을 대응시키는 함수 $A = (A_{ij})_{ij}$이다.
  • 행렬 $A$는 모든 성분을 사각형으로 배열하고 소괄호 또는 대괄호를 추가하여 다음과 같이 표기한다.

$$ A = \begin{bmatrix}
 A_{11}& A_{12} & A_{13}  & ... & A_{1n}\\ 
 A_{21}& A_{22} & A_{23}  & ... & A_{2n}\\ 
 A_{31}& A_{32} & A_{33}  & ... & A_{3n}\\ 
 \vdots & \vdots & \vdots & \ddots & \vdots\\
 A_{m1}& A_{m2} & A_{m3}  & ... & A_{mn}\\
\end{bmatrix} $$

 

$$ A = \begin{pmatrix}
 A_{11}& A_{12} & A_{13}  & ... & A_{1n}\\ 
 A_{21}& A_{22} & A_{23}  & ... & A_{2n}\\ 
 A_{31}& A_{32} & A_{33}  & ... & A_{3n}\\ 
 \vdots & \vdots & \vdots & \ddots & \vdots\\
 A_{m1}& A_{m2} & A_{m3}  & ... & A_{mn}\\
\end{pmatrix} $$

  • $A_{ij}$를 $A$의 $i$번째 행 $j$번째 열의 성분(Entry) 또는 원소(Element) 또는 계수(Coefficient)라 한다.
  • 행렬 $A$의 각 성분은 행과 열의 번째 수를 첨수로 사용해, $A_{ij},\ A_{i,j},\ a_{ij},\ a_{i,j},\ A(i,j),\ A[i,j]$ 등과 같이 표현한다.
  • 행렬은 실수에 대해 닫혀 있으며, 행렬 연산 시 실수가 나온다.
  • 행과 열의 번째수가 동일한 성분 $A_{ii}\ (i \in \{1, ..., min\{m,n\}\})$을 $A$의 대각 성분(Diagonal entry) 또는 대각 원소(Diagonal element), 대각 요소, 주대각 성분이라고 한다.

 

  • 행렬 $A$의 크기(Size)는 행과 열의 수의 순서쌍 $(m,n)$ 또는 $m*n$으로 나타낸다.
  • 만약 행과 열의 수가 같다면($m=n$) 행렬$A$를 정사각 행렬(Square matrix) 또는 정방 행렬이라 부른다.
  • 행과 열의 수가 다르다면($m \neq n$) 직사각 행렬(Rectangular matrix) 또는 장방 행렬이라 부르는데, 일반적으로 행렬은 직사각형이므로, 정방 행렬과 구분하고자 하는 경우가 아니라면 그냥 행렬이라 부른다.

 

  • 만약, $m=1$이라면 행렬 $A$를 $1*n$ 행 백터(Row vector)라고 한다.
  • 만약, $n=1$이라면 행렬 $A$를 $m*1$ 열 벡터(Column vector)라고 한다.
  • 만약, $m=1,\ n=1$인 행렬 $A$는 스칼라(Scalar)라고 한다.

$$X = \begin{bmatrix} x_1 & x_2 & x_3 & ... &x_n \end{bmatrix}$$

$$X = \begin{bmatrix}
x_1\\ 
x_2\\ 
x_3\\ 
\vdots \\
x_n
\end{bmatrix}$$

$$X = \begin{bmatrix} x_1 \end{bmatrix}$$

  • 즉, 벡터와 스칼라 역시 수학적으로는 행렬에 속한다.

 

 

 

 

2. Python과 다양한 형태의 행렬

  • Python에서는 Numpy 라이브러리를 사용해서 행렬, 벡터를 만든다.
  • Python의 Numpy라이브러리를 사용해서 다양한 형태의 행렬을 만들어보도록 하겠다.
import numpy as np

2.1. 직사각 행렬(Rectangular matrix)

>>> np.arange(0, 18).reshape((3,6))
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17]])
       
       
# 랜덤한 값으로 만들수도 있다.
>>> np.random.randint(0, 20, size=(3, 6))
array([[16,  9,  1,  6,  7, 18],
       [ 4, 15, 15, 16, 13, 16],
       [ 8,  1,  2,  8, 11,  8]])
  • 직사각형 모양의 행렬로, 장방 행렬이라고도 부르며, 가장 일반적인 행렬이다.

2.2. 정사각 행렬(Square matrix)

>>> np.arange(0, 16).reshape((4,4))
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
       
       
>>> np.random.randint(0, 20, size=(3, 3))
array([[ 5,  8,  7],
       [13,  9,  0],
       [ 8, 17,  8]])
  • 정사각형 모양의 행렬로, 정방 행렬이라고도 부른다.

2.3. 영행렬(Zero matrix)

>>> np.zeros((4, 5))
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
  • 모든 원소가 0인 행렬로, 행렬 곱에서 영원으로 작용하는 행렬이다.

2.4. 항등행렬(Identity matrix)

>>> np.identity(4)
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])
  • 대각 성분은 모두 1이며, 나머지 원소는 0인 행렬이다.
  • 행렬 곱셈에서 항등원으로 작용하며, 다른 행렬에 곱하면, 곱한 행렬이 그대로 나오게 된다.
  • 단위행렬이라고도 부른다.

2.5. 대각행렬(Diagonal matrix)

# 대각행렬 만들기
>>> diag_M = np.diag((4, 2, 2, 5, 1, 6))
>>> diag_M
array([[4, 0, 0, 0, 0, 0],
       [0, 2, 0, 0, 0, 0],
       [0, 0, 2, 0, 0, 0],
       [0, 0, 0, 5, 0, 0],
       [0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 6]])

# 대각성분 뽑기
>>> np.diagonal(diag_M)
array([4, 2, 2, 5, 1, 6])

# 대각성분이 1인 행렬 만들기
>>> np.eye(3, 3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
       
# 장방행렬로 만들기
>>> np.eye(5, 3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.],
       [0., 0., 0.],
       [0., 0., 0.]])
  • 대각행렬은 주대각선 원소를 제외한 모든 원소가 0인 정방행렬이다.
  • 영행렬, 단위 행렬은 대각 행렬에 포함된다.
  • 장방행렬 역시 주대각 성분을 제외한 나머지 원소가 0인 경우 대각행렬에 포함된다.

2.6. 스칼라 행렬(Scalar matrix) 

# 대각 성분이 모두 1인 대각행렬
>>> np.identity(4)
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])
       
# 대각 성분이 모두 같은 대각행렬
>>> np.diag(np.full(4, 5))
array([[5, 0, 0, 0],
       [0, 5, 0, 0],
       [0, 0, 5, 0],
       [0, 0, 0, 5]])
  • 주대각 성분이 모두 같은 원소로 된 대각행렬

2.7. 삼각행렬(Triangular matrix)

# 정방행렬
>>> Mat = np.arange(0, 36).reshape((6,6))
>>> Mat
array([[ 0,  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, 32, 33, 34, 35]])
       
# 상삼각행렬
>>> np.triu(Mat, 0)
array([[ 0,  1,  2,  3,  4,  5],
       [ 0,  7,  8,  9, 10, 11],
       [ 0,  0, 14, 15, 16, 17],
       [ 0,  0,  0, 21, 22, 23],
       [ 0,  0,  0,  0, 28, 29],
       [ 0,  0,  0,  0,  0, 35]])
       
# 하삼각행렬
>>> np.tril(Mat, 0)
array([[ 0,  0,  0,  0,  0,  0],
       [ 6,  7,  0,  0,  0,  0],
       [12, 13, 14,  0,  0,  0],
       [18, 19, 20, 21,  0,  0],
       [24, 25, 26, 27, 28,  0],
       [30, 31, 32, 33, 34, 35]])
  • 정방행렬의 특수한 경우로, 주대각선을 기준으로 대각항의 위쪽이나 아래쪽 항들의 값이 모두 0인 경우를 의미한다.
  • 주대각선 성분을 기준으로 아래가 모두 0이면 상삼각행렬(Upper Triangular matrix)이다.
  • 주대각선 성분을 기준으로 위가 모두 0이면 하삼각행렬(Lower Triangular matrix)이다.

2.8. 전치행렬(Transpose Matrix)

>>> Mat = np.arange(0, 16).reshape((4,4))
>>> Mat
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
       
# 전치행렬 만들기
>>> Mat.T
array([[ 0,  4,  8, 12],
       [ 1,  5,  9, 13],
       [ 2,  6, 10, 14],
       [ 3,  7, 11, 15]])
       
>>> np.transpose(Mat)
array([[ 0,  4,  8, 12],
       [ 1,  5,  9, 13],
       [ 2,  6, 10, 14],
       [ 3,  7, 11, 15]])
  • 행렬 $A$의 전치행렬은 $A^T$로 표기한다.
  • 주대각 성분을 기준으로 행과 열을 대칭으로 바꾼 행렬
  • 주대각 성분을 기준으로 하므로, 주대각 성분은 변하지 않는다.
  • 정사각행렬 $A$가 $A^T=A$를 만족하면 행렬 $A$는 대칭행렬이다.
    (전치행렬인 $A^T$는 주대각 성분을 기준으로 행과 열을 대칭으로 바꾸기 때문이다.)
  • 반대로, $A^T=-A$를 만족하면 반대칭행렬(Skew symmetric matrix) 또는 교대행렬(Alternating matrix)이라 한다.

2.9. 직교행렬(Orthogonal matrix)

>>> Ort_M = np.array([[0,0,1],[1,0,0],[0,1,0]])
>>> Ort_M
array([[0, 0, 1],
       [1, 0, 0],
       [0, 1, 0]])
       
# 행렬 Ort_M과 전치행렬 Ort_M을 행렬곱하였을 때, 단위 행렬이 나오는 행렬 Ort_M
>>> np.dot(Ort_M, Ort_M.T)
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])
  • 행렬 A의 역행렬이 A의 전치행렬인 행렬 A를 직교행렬이라 한다.
  • 직교행렬과 직교행렬의 전치행렬을 행렬곱하면 단위행렬이 나온다.
  • $A^{-1} = A^T, \ A^TA = I$
728x90
반응형
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
728x90
반응형

저번 포스트에선 행렬 생성과 행과 열의 이름 변경, 행렬의 정보 얻기 등을 공부해보았다.
이번 포스트에선 행렬 데이터 접근, 행렬의 연산에 대해 학습해보자.

 

행렬 데이터 접근하기

  • 행렬은 색인 또는 행과 열의 이름을 통해서 접근할 수 있다.
  • 행렬은 벡터와 같게 [] 대괄호를 이용해서 데이터에 접근한다.
  • 단 행렬은 벡터와 다르게 2개의 차원인 행(Row), 열(Column)으로 구성되어 있으므로, 2개의 index를 부여해야한다.
  • Matrix[행index,열index]로 행렬 데이터에 접근할 수 있다.
  • Indexing 예시는 다음과 같다.
    • Matrix[row_id, col_id]
      : 행렬의 row_id 행과 col_id 열에 지정된 값을 가지고 온다. 이 때, row_id나 col_id에 벡터를 사용하여 여러 값을 지정할 수 있다. row_id나 col_id 둘 중 하나를 생략하면 전체 행이나 열을 뜻한다.
    • Matrix[1:3,]
      : 1~3 행의 데이터를 가지고 온다.
    • Matrix[-3,]
      : 3행의 데이터를 제외하고 모두 가지고 온다.
    • Matrix[c(1,3),]
      : 1, 3 행만 가지고 온다.
    • Matrix[,c("col5", "col3")]
      : 행렬 또한 행과 열에 부여된 이름으로 불러올 수 있다.

      ※ 접근한 행렬의 색인이나 이름의 순서에 따라서 행렬의 배열은 바뀌게 된다!
# 행렬에서 내가 원하는 데이터만 가지고 와보자.
vt = c(80, 60, 70, 75,
       90, 70, 60, 60,
       85, 90, 40, 70,
       80, 75, 90, 80,
       85, 80, 70, 65)
mat <- matrix(vt, nrow = 5, byrow = TRUE, dimnames = list(c("민철", "재성", "기훈", "재빈", "현희"), c("수학", "영어", "국어", "탐구")))
mat

※ 행렬과 같은 형태로 벡터를 생성한다면, 행렬 생성이 보다 편리하다.

##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 재성   90   70   60   60
## 기훈   85   90   40   70
## 재빈   80   75   90   80
## 현희   85   80   70   65
# 행렬에서 민철, 기훈, 현희의 수학 점수와 국어 점수를 가지고 와보자..
mat[c("민철", "기훈", "현희"), c("수학", "국어")]
##      수학 국어
## 민철   80   70
## 기훈   85   40
## 현희   85   70
# 행렬에서 2번 행부터 4번 행까지 가지고 와보자.
mat[2:4,]
##      수학 영어 국어 탐구
## 재성   90   70   60   60
## 기훈   85   90   40   70
## 재빈   80   75   90   80
# 행렬에서 3번째 행만 제외하고 가지고 와보자.
mat[-3,]
##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 재성   90   70   60   60
## 재빈   80   75   90   80
## 현희   85   80   70   65
# 행렬에서 1, 3 행만 가지고 와보자.
mat[c(1,3),]
##      수학 영어 국어 탐구
## 민철   80   60   70   75
## 기훈   85   90   40   70
# 행렬에서 국어 점수와 수학 점수 순서로 가지고 와보자.
mat[,c("국어", "수학")]
##      국어 수학
## 민철   70   80
## 재성   60   90
## 기훈   40   85
## 재빈   90   80
## 현희   70   85

 

 

 

 

행렬의 연산

: 행렬 내부에서 할 수 있는 연산과 행렬과 스칼라 간의 연산, 행렬과 행렬 간의 연산에 대해 알아보자.

행렬 내 연산

  • rowMeans() / colMeans()
    : 행의 평균을 구한다. / 열의 평균을 구한다.
  • rowSums() / colSums()
    : 행의 합을 구한다. / 열의 합을 구한다.
  • 위 행렬을 기반으로 실습을 해보자.
    ※ Indexing과 조합하여 내가 원하는 값만 가지고 와서 연산해보도록 하자.
# 위 행렬이 1반이라고 가정할 때, 1반 학생들 개개인의 총 점수를 구하자.
rowSums(mat)
## 민철 재성 기훈 재빈 현희 
##  285  280  285  325  300
# 1 반 학생들의 과목별 평균 점수를 구하자.
colMeans(mat)
## 수학 영어 국어 탐구 
##   84   75   66   70
# 민철, 기훈, 현희의 평균 점수를 구하자.
rowMeans(mat[c("민철", "기훈", "재빈"),])
##  민철  기훈  재빈 
## 71.25 71.25 81.25
# 재성, 재빈, 현희의 수학, 국어 점수의 평균 점수를 구하자.
rowMeans(mat[c("재성", "재빈", "현희"),c("수학", "국어")])
## 재성 재빈 현희 
## 75.0 85.0 77.5
# 1반의 수학 총점과 평균 점수를 구하자.
math_Vt = mat[,"수학"]
sum(math_Vt)
## [1] 420
mean(math_Vt)
## [1] 84

 

 

행렬과 스칼라 간의 연산

  • 행렬과 스칼라 간의 연산은 아주 간단하다.
  • + - * / ^ 등을 그대로 사용하면 된다.
mat1 = matrix(c(1:12), nrow = 3, byrow = TRUE)
mat1 + 10
##      [,1] [,2] [,3] [,4]
## [1,]   11   12   13   14
## [2,]   15   16   17   18
## [3,]   19   20   21   22
mat1 - 10
##      [,1] [,2] [,3] [,4]
## [1,]   -9   -8   -7   -6
## [2,]   -5   -4   -3   -2
## [3,]   -1    0    1    2
mat1 * 10
##      [,1] [,2] [,3] [,4]
## [1,]   10   20   30   40
## [2,]   50   60   70   80
## [3,]   90  100  110  120
mat1 / 10
##      [,1] [,2] [,3] [,4]
## [1,]  0.1  0.2  0.3  0.4
## [2,]  0.5  0.6  0.7  0.8
## [3,]  0.9  1.0  1.1  1.2

 

 

행렬과 행렬의 연산

  • 행렬과 행렬의 연산은 다양한 전제 조건이 붙는다.
  • 행렬의 합과 차를 하려면 두 행렬의 크기가 서로 같아야 하며, 행렬의 곱을 하려면 앞 행렬과 뒤 행렬의 열과 행의 수가 동일해야한다. 
  • 행렬의 합과 차는 +, -로 기존 연산자와 동일하나 행렬간 곱은 %*%로 연산자가 다르다.
  • 전치행렬을 이용하면 언제든지 행렬 곱을 할 수 있다.
    • 전치행렬은 각 원소의 행과 열을 바꾼 행렬로, 어떤 크기의 행렬이라도 전치 행렬을 만들 수 있다.
    • 전치 행렬은 행과 열을 교환한 것이므로, 언제든지 행렬곱을 할 수 있다.
      보다 엄밀히 말하면, 주대각선을 축으로 하는 반사 대칭을 가하여 얻은 행렬이라고 할 수 있다.
    • 전치 행렬은 t(행렬)을 하면 생성할 수 있다.
mat1 = matrix(c(1:12), nrow = 3, byrow = TRUE)
mat2 = matrix(c(12:1), nrow = 3, byrow = TRUE)

# 행렬간 합과 차를 해보자
mat1 + mat2
##      [,1] [,2] [,3] [,4]
## [1,]   13   13   13   13
## [2,]   13   13   13   13
## [3,]   13   13   13   13
mat1 - mat2
##      [,1] [,2] [,3] [,4]
## [1,]  -11   -9   -7   -5
## [2,]   -3   -1    1    3
## [3,]    5    7    9   11
# 전치행렬 곱을 해보자
mat1 %*%t(mat1)
##      [,1] [,2] [,3]
## [1,]   30   70  110
## [2,]   70  174  278
## [3,]  110  278  446

 

 

 

이번 포스트에서는 행렬의 Indexing과 행렬의 연산 등에 대하여 학습해보았다.

다음 포스트에선 역행렬을 비롯한 약간 독특한 형태의 행렬들에 대해 가볍게 학습해보자.

728x90
반응형

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

R(기초) 배열(Array)  (0) 2020.06.19
R(기초) 행렬(Matrix)(3부)  (0) 2020.06.19
R(기초) 행렬(Matrix)(1부)  (0) 2020.06.18
R(기초) 연산자와 변수 타입  (0) 2020.06.18
R(기초) 데이터 타입: 벡터(Vector)(2부)  (0) 2020.06.18
728x90
반응형

이번에는 행렬(matrix)에 대해 학습 해보자, 행렬은 통계 분석부터 요즘 핫한 딥러닝까지 두루 쓰이는 것으로, 행렬에 대해 자세히 파고 들어간다면, 몇 주 동안 행렬에 대해서만 다뤄도 부족할 것이다.

지금은 행렬에 대해 기초적인 수준에서 접근을 해볼 것이며, 총 3개의 파트로 나눠 학습해보고자 한다.

파트1에선 R에서 행렬의 생성과 기본적인 접근법, 파트2에선 행렬의 Indexing과 행렬 연산 등을 공부하고, 파트3에선 가운데 행렬과 같은 조금 특이한 행렬에 대해 학습하도록 하자.

행렬(Matrix)

: 벡터를 행과 열로 갖는 표 형식으로 확장한 것이 행렬이다.

  • 행렬에는 한 가지 유형의 스칼라만 사용할 수 있다.
  • 행렬에 들어가는 Data는 일반적으로 벡터가 들어간다.
    (즉, 1차원인 벡터를 2차원으로 바꾼 것을 행렬이라고 할 수 있다.)

 

행렬 생성

  • matrix()
    : 행렬을 생성한다.
  • 주요 Parameter
    : matrix(data, nrow: 행의 수, ncol: 열의 수, byrow: 행부터 데이터를 채움, dimnames: 행렬의 각 차원에 부여할 이름)
# matrix를 만들어보자.
vt = seq(from = 1, by = 2, length = 12)
mat = matrix(vt, nrow = 4, byrow = TRUE, dimnames = list(c("r1", "r2", "r3", "r4"), c("c1", "c2", "c3")))
mat

※ dimnames에 들어간 list는 추후 공부할 데이터 타입으로, n개의 데이터  타입을 담을 수 있는 형태라고 보면 된다.
자세한 것은 추후 학습하도록 하자.

##    c1 c2 c3
## r1  1  3  5
## r2  7  9 11
## r3 13 15 17
## r4 19 21 23

 

 

행렬의 크기와 벡터의 길이가 다를 경우

  • 만약, 벡터의 길이가 행렬을 구성하기에 적합하지 않은 길이인 경우, 오류 메시지가 발생하고 벡터의 앞부분부터 행렬의 빈자리에 들어가게 된다.
# matrix를 만들어보자.
vt_diff = seq(from = 1, by = 2, length = 10)
mat_diff = matrix(vt_diff, nrow = 5, ncol = 4, byrow = TRUE)
mat_diff
##      [,1] [,2] [,3] [,4]
## [1,]    1    3    5    7
## [2,]    9   11   13   15
## [3,]   17   19    1    3
## [4,]    5    7    9   11
## [5,]   13   15   17   19
  • 위 행렬에서 볼 수 있듯이 3행 3열부터 Data로 들어간 벡터가 처음부터 값이 입력되었다.

 

 

행렬의 기본적인 정보를 가지고 와보자.

# 대상이 될 행렬.
vt = seq(from = 1, by = 2, length = 12)
mat <- matrix(vt, nrow = 4, byrow = TRUE, dimnames = list(c("r1", "r2", "r3", "r4"), c("c1", "c2", "c3")))

1) 행렬의 차원별 이름 가지고 오기.

  • dimnames()
    : 객체의 각 차원 이름을 가지고 온다.(dim = dimension)
  • rownames()
    : 행렬의 행 이름을 가지고 온다.
  • colnames()
    : 행렬의 열 이름을 가지고 온다.
# 행렬의 각 차원 이름을 모두 가지고 와보자.
dimnames(mat)
## [[1]]
## [1] "r1" "r2" "r3" "r4"
## 
## [[2]]
## [1] "c1" "c2" "c3"
# 행렬에서 행 이름을 가져와보자.
rownames(mat)
## [1] "r1" "r2" "r3" "r4"
# 행렬에서 열 이름을 가져와보자.
colnames(mat)
## [1] "c1" "c2" "c3"

 

2) 행렬에 다른 이름을 부여해보자.

  • 행렬의 차원별 이름 바꾸기는 들어가는 데이터 타입만 다를 뿐 벡터와 동일하다.
# 행렬에 다른 이름을 부여해보자.
dimnames(mat) <-list(c("a1", "a2", "a3", "a4"), c("b1", "b2", "b3"))
mat
##    b1 b2 b3
## a1  1  3  5
## a2  7  9 11
## a3 13 15 17
## a4 19 21 23
# 행의 이름을 바꿔보자.
rownames(mat) <- c("행1", "행2", "행3", "행4")
mat
##     b1 b2 b3
## 행1  1  3  5
## 행2  7  9 11
## 행3 13 15 17
## 행4 19 21 23
#열의 이름을 바꿔보자.
colnames(mat) <- c("열1", "열2", "열3")
mat
##     열1 열2 열3
## 행1   1   3   5
## 행2   7   9  11
## 행3  13  15  17
## 행4  19  21  23

 

3) 행렬의 크기에 관한 정보를 가지고 와보자.

  • nrow()
    : 행렬의 행의 갯수
  • ncol()
    : 행렬의 열의 갯수
  • dim()
    : 행렬의 차원별 크기
  • length()
    : 행렬 내 원소들의 수 (벡터의 길이와 동일하다!)
  • mode()
    : 행렬 내 원소의 타입 확인
  • str()
    : 행렬뿐만 아니라 벡터, 데이터 프레임 등에서도 사용되는 것으로, 원소의 양, 차원, 차원 이름, 원소의 타입 등 데이터의 전반적인 정보를 가지고 온다.
# 행렬의 행의 갯수를 가지고 와보자.
nrow(mat)
## [1] 4
# 행렬의 열의 갯수를 가지고 와보자.
ncol(mat)
## [1] 3
# 행렬의 차원별 크기를 가지고 와보자.
dim(mat)
## [1] 4 3
# 행렬에 있는 원소의 수를 가지고 와보자
length(mat)
## [1] 12
# 행렬의 원소 타입을 확인해보자.
mode(mat)
## [1] "numeric"
# 행렬의 정보들을 정리해서 봐보자!
str(mat)
##  num [1:4, 1:3] 1 7 13 19 3 9 15 21 5 11 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:4] "r1" "r2" "r3" "r4"
##   ..$ : chr [1:3] "c1" "c2" "c3"

 

4) 행렬의 형태를 바꿔보자.
: 행렬의 차원 변경은 원소의 수가 같다면 쉽게 할 수 있다.

# 행렬의 차원을 바꿔보자.
dim(mat) <- c(2,6)
mat
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1   13    3   15    5   17
## [2,]    7   19    9   21   11   23

 

 

 

벡터들을 합쳐서 행렬을 만들어보자.

  • 두 개 이상의 벡터를 묶어서 행렬을 만들어보자.
  • cbind()
    : 열로 벡터들을 묶는다.
  • rbind()
    : 행으로 벡터들을 묶는다.
  • rbind()나 cbind()는 Matrix뿐만 아니라 R에서 가장 많이 쓰이는 데이터 타입인 DataFrame에서도 쓰인다.
  • 만약 벡터의 길이가 동일하지 않는다면, 경고문을 띄운 후 길이가 가장 긴 벡터에 맞게 다른 벡터들은 앞부분부터 뒤에 추가하여 생성된다.
vt1 = c(1:6)
vt2 = c(8:3)
vt3 = rep(c(1,2,3), times = 2)
vt4 = c("a", "b", "c", "d", "e", "f")
vt5 = c(1:10)
# 열로 묶어보자
cbind(vt1, vt2, vt3)
##      vt1 vt2 vt3
## [1,]   1   8   1
## [2,]   2   7   2
## [3,]   3   6   3
## [4,]   4   5   1
## [5,]   5   4   2
## [6,]   6   3   3
# 행으로 묶어보자
rbind(vt1, vt2, vt3)
##     [,1] [,2] [,3] [,4] [,5] [,6]
## vt1    1    2    3    4    5    6
## vt2    8    7    6    5    4    3
## vt3    1    2    3    1    2    3
# 숫자 벡터에 문자 벡터를 섞어보자
cbind(vt1, vt2, vt3, vt4)
##      vt1 vt2 vt3 vt4
## [1,] "1" "8" "1" "a"
## [2,] "2" "7" "2" "b"
## [3,] "3" "6" "3" "c"
## [4,] "4" "5" "1" "d"
## [5,] "5" "4" "2" "e"
## [6,] "6" "3" "3" "f"

※ 숫자형 벡터와 문자형 벡터를 하나의 행렬로 묶는 경우, 행렬엔 하나의 변수 타입만 들어갈 수 있으므로 character형으로 바뀐 것을 볼 수 있다.

# 길이가 다른 벡터를 추가해보자
cbind(vt1, vt2, vt3, vt5)
## Warning in cbind(vt1, vt2, vt3, vt5): number of rows of result is not a multiple
## of vector length (arg 1)
##       vt1 vt2 vt3 vt5
##  [1,]   1   8   1   1
##  [2,]   2   7   2   2
##  [3,]   3   6   3   3
##  [4,]   4   5   1   4
##  [5,]   5   4   2   5
##  [6,]   6   3   3   6
##  [7,]   1   8   1   7
##  [8,]   2   7   2   8
##  [9,]   3   6   3   9
## [10,]   4   5   1  10

※ 길이가 다른 벡터가 추가 되면, 길이가 짧은 벡터들은 앞 부분부터 반복하여 생성되는 것을 알 수 있다.

 

 

 

지금까지 행렬에 대한 기본적인 정보를 가지고 노는 법에 대해 학습해보았다.

눈치가 빠른 사람이라면, 행렬의 이름 부여, 크기 보기 등이 꽤나 비슷한 것을 알 수 있는데, R에서 사용하는 대부분의 데이터 형태 조작 방법이, 이 틀에서 크게 벗어나지 않는다는 점이, R로 데이터를 가지고 놀 때 매우 편리한 부분이다.

다음 포스트에선 행렬 데이터 접근(Indexing), 행렬의 연산에 대하여 다뤄보도록 하겠다.

 

 

 

728x90
반응형

+ Recent posts