2.5 행렬(matrix)

학습목표: 행렬, 배열, 요인형과 테이블에 대해 살펴보고, 이들 객체에 대한 연산과 연관된 함수에 대해 익힌다.

행렬의 정의

  • 동일한 데이터 타입의 원소로 구성된 2차원 데이터 구조
  • \(n \times 1\) 차원 벡터 \(p\)개로 묶여진 데이터 덩어리 \(\rightarrow\) \(n \times p\) 행렬로 명칭함
  • 행렬의 형태

\[\begin{bmatrix} x_{11} & x_{12} & \cdots & x_{1p} \\ x_{21} & x_{22} & \cdots & x_{2p} \\ \vdots & \vdots & \cdots & \vdots \\ x_{n1} & x_{n2} & \cdots & x_{np} \end{bmatrix} \]

  • R에서 행렬은 동일한 유형의 데이터 타입으로 구성 가능 \(\rightarrow\) 첫 번째 행은 숫자형, 두 번째 행은 문자열로 입력해도 행렬을 만들 수 있지만, 표현력이 더 높은 문자형 행렬 반환
  • 행렬의 내부 저장공간은 “열 우선 배열”
  • 행렬 생성을 위한 R 함수는 matrix() 함수이고 사용 형태는 아래와 같음
# matrix(): 행렬 생성 함수
# 상세 내용은 help(matrix)를 통해 확인

matrix(data, # 행렬을 생성할 데이터 벡터 
       nrow, # 행의 개수 (정수)
       ncol, # 열의 개수 (정수)
       byrow, # TRUE: 행 우선, FALSE: 열 우선
              # default = FALSE
       dimnames # 행렬읠 각 차원에 부여할 이름 (리스트)
       )

  • 행렬 생성 예시
# byrow = FALSE
x <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3, ncol = 3)
x
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
# byrow = TRUE
x <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3, ncol = 3, byrow = T)
x
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

  • 행의 개수(nrow)나 열의 개수(ncol)로 나머지를 추정 가능하다면 둘 중 어떤 인수도 생략 가능
x <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), ncol = 3)
x
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
x <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3)
x
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

  • nrow \(\times\) ncol 이 입력한 데이터(벡터)의 길이보다 작거나 큰 경우
# length(x) < nrow * ncol 인 경우 
# nrow * ncol에 해당하는 길이 만큼
# x의 원소를 사용해 행렬 생성
x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9)
y <- matrix(x, nrow = 3, ncol = 4)
Warning in matrix(x, nrow = 3, ncol = 4): 데이터의 길이[9]가 열의 개수[4]의
배수가 되지 않습니다
y
     [,1] [,2] [,3] [,4]
[1,]    1    4    7    1
[2,]    2    5    8    2
[3,]    3    6    9    3
# length(x) > nrow * ncol 인 경우 
# x의 첫 번쨰 원소부터 초과하는 만큼 
# x 원소의 값을 재사용
z <- matrix(x, nrow = 2, ncol = 3)
Warning in matrix(x, nrow = 2, ncol = 3): 데이터의 길이[9]가 행의 개수[2]의
배수가 되지 않습니다
z
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

  • 행렬 구성 시 길이에 대한 약수가 아닌 값을 nrow 또는 ncol의 인수로 받은 경우
# x (length=9)로 행렬 생성 시 nrow=4 를
# 인수로 입력한 경우
h <- matrix(x, nrow = 4)
Warning in matrix(x, nrow = 4): 데이터의 길이[9]가 행의 개수[4]의 배수가 되지
않습니다
h
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6    1
[3,]    3    7    2
[4,]    4    8    3
# x (length=9)로 행렬 생성 시 ncol=2 만 
# 인수로 입력한 경우
h <- matrix(x, nrow = 2)
Warning in matrix(x, nrow = 2): 데이터의 길이[9]가 행의 개수[2]의 배수가 되지
않습니다
h
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8    1

2.5.1 행렬의 연산

  • 선형대수(linear algebra)에서 배우는 행렬-스칼라, 행렬-행렬 간 연산 가능

행렬-스칼라 연산

합 연산: 스칼라가 자동적으로 행렬의 차원에 맞춰서 재사용

\[\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} + 4 = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} + \begin{bmatrix} 4 & 4 & 4 \\ 4 & 4 & 4 \\ 4 & 4 & 4 \end{bmatrix} = \begin{bmatrix} 5 & 6 & 7 \\ 8 & 9 & 10 \\ 11 & 12 & 13 \end{bmatrix} \]

x <-matrix(1:9, 3, 3, byrow = T)
x + 4
     [,1] [,2] [,3]
[1,]    5    6    7
[2,]    8    9   10
[3,]   11   12   13

곱 연산

\[\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} \times 4 = \begin{bmatrix} 4 & 8 & 12 \\ 16 & 20 & 24 \\ 28 & 32 & 36 \end{bmatrix} \]

x*4
     [,1] [,2] [,3]
[1,]    4    8   12
[2,]   16   20   24
[3,]   28   32   36

행렬-행렬 연산

  • 행렬 간 연산에서 스칼라 연산(일반 연산)과 다른 점은 차원이 개입

행렬 간 합(차)

  • 두 행렬의 동일 차원 간 합 연산 수행(+ 또는 - 연산자 사용)

\[\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} + \begin{bmatrix} 1 & -1 & ~~~2 \\ 3 & ~~~2 & ~~~4 \\ -6 & ~~~3 & -7 \end{bmatrix} = \begin{bmatrix} 2 & 1 & 5 \\ 7 & 7 & 10 \\ 1 & 11 & 2 \end{bmatrix} \]

x <- matrix(1:9, 3, 3, byrow = T)
y <- matrix(c(1, 3, -6, -1, 2, 3, 2, 4, -7), ncol = 3)
x + y
     [,1] [,2] [,3]
[1,]    2    1    5
[2,]    7    7   10
[3,]    1   11    2

행렬 곱/나누기(elementwise product/division)

  • 연산자 * 또는 / 사용

\[\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} * \begin{bmatrix} ~~~1 & -1 & ~~~2 \\ ~~~3 & ~~~2 & ~~~4 \\ -6 & ~~~3 & -7 \end{bmatrix} = \begin{bmatrix} ~~~~~ 1 & -2 & ~~~~6 \\ ~~~ 12 & ~10 & ~~~24 \\ -42 & ~24 & -63 \end{bmatrix} \]

x * y
     [,1] [,2] [,3]
[1,]    1   -2    6
[2,]   12   10   24
[3,]  -42   24  -63

  • 행렬-행렬 합(차) 또는 곱(나누기) 연산 시 행렬의 열단위 원소가 재사용되지 않음

동일 차원 간 연산만 가능!!

z <- y[, 1:2] # y 행렬에서 1-2 번째 열 추출
z # 3 by 2 행렬
     [,1] [,2]
[1,]    1   -1
[2,]    3    2
[3,]   -6    3
x + z
Error in x + z: 배열의 크기가 올바르지 않습니다
x * z
Error in x * z: 배열의 크기가 올바르지 않습니다
x / z
Error in x/z: 배열의 크기가 올바르지 않습니다

행렬 간 곱(matrix product)

  • 두 행렬 \(\mathrm{\mathbf X}_{n\times m}\), \(\mathrm{\mathbf Y}_{m\times k}\) 이 주어졌을 때 두 행렬의 곱(matrix product) \(\mathrm{\mathbf Z} = \mathrm{\mathbf {X\cdot Y}}\)\(n \times k\) 행렬이고 \(\mathrm{\mathbf Z}\) 원소 \(z_{ij}\) (\(i={1,\ldots,n}\), \(j={1,\ldots,k}\)) 아래와 같이 정의됨

\[ z_{ij} = \sum_{r=1}^{m}x_{ir}y_{rj},~~~~\forall~\{i, j\} \] - R에서 위와 같은 연산은 %*%를 사용

  • 예시: 행렬 \(\mathrm{\mathbf X}_{2\times 4}\), \(\mathrm{\mathbf Y}_{4\times 3}\) 이 아래와 같이 주어졌을 때 두 행렬의 곱 \(\mathrm{\mathbf Z}_{2\times 3} = \mathrm{\mathbf{X}}_{2\times 4}\mathrm{\mathbf{Y}}_{4 \times 3}\)는 아래와 같음

\[ \mathrm{\mathbf X}= \begin{bmatrix} 1 &~~~ 1 & -1 & 1 \\ 1 & -1 &~~~ 1 & 1 \end{bmatrix}, ~~~~~ \mathrm{\mathbf{Y}}= \begin{bmatrix} 1 & -2 & -1 \\ 1 &~~~1 &~~~2 \\ 1 &~~~3 &~~~1 \\ 1 &~~~2 &~~~2 \end{bmatrix} \]

\[ \mathrm{\mathbf{Z}} = \mathrm{\mathbf{X}}\mathrm{\mathbf{Y}} = \begin{bmatrix} 1 &~~~ 1 & -1 & 1 \\ 1 & -1 &~~~ 1 & 1 \\ \end{bmatrix} \cdot \begin{bmatrix} 1 & -2 & -1 \\ 1 &~~~1 &~~~2 \\ 1 &~~~3 &~~~1 \\ 1 &~~~2 &~~~2 \end{bmatrix} = \begin{bmatrix} 2 & -2 & 2 \\ 2 &~~~2 & 0 \end{bmatrix} \]

X <- matrix(c(1,1,1,-1,-1,1,1,1), nrow = 2, ncol = 4)
Y <- matrix(c(1,1,1,1, -2, 1, 3, 2, -1, 2, 1, 2), nrow = 4, ncol = 3)
Z <- X %*% Y
Z
     [,1] [,2] [,3]
[1,]    2   -2    2
[2,]    2    2    0

행렬-벡터 연산

  • 행렬 \(\mathrm{\mathbf{X}}\)의 행 길이와 벡터 \(\mathrm{\mathbf y}\)의 길이가 같은 경우 \(\rightarrow\) \(\mathrm{\mathbf y}\)를 열 단위로 재사용

\[\mathrm{\mathbf{X}} = \begin{bmatrix} 1 & 2 & 4\\ 1 & 3 & 2\\ 1 & 2 & 1 \end{bmatrix}, ~~~~~ \mathrm{\mathbf y} = [20, 18, 23]^T \]

\[\mathrm{\mathbf{X}} + \mathrm{\mathbf{y}} = \begin{bmatrix} 1 & 2 & 4\\ 1 & 3 & 2\\ 1 & 2 & 1 \end{bmatrix} + \begin{bmatrix} 20 & 20 & 20\\ 18 & 18 & 18\\ 23 & 23 & 23 \end{bmatrix} = \begin{bmatrix} 21 & 22 & 24\\ 19 & 21 & 20\\ 24 & 25 & 24 \end{bmatrix} \]

#행렬-벡터 합 연산
# X = 3 by 3 행렬; y = 3 by 1 벡터
x <- c(1, 1, 1, 2, 3, 2, 4, 2, 1)
X <- matrix(x, nrow = 3)
y <- c(20, 18, 23)# 재사용

X + y
     [,1] [,2] [,3]
[1,]   21   22   24
[2,]   19   21   20
[3,]   24   25   24

  • 행렬 \(\mathrm{\mathbf{X}}\)의 길이와 벡터 \(\mathrm{\mathbf y}\)의 길이가 같은 경우 \(\rightarrow\) 벡터 \(\mathrm{\mathbf y}\)를 자동으로 원소를 행렬(열단위)로 변환

\[\mathrm{\mathbf{X}} = \begin{bmatrix} 1 & 2 & 3\\ 4 & 5 & 6\\ 7 & 8 & 9 \end{bmatrix}, ~~~~~ \mathrm{\mathbf y} = [1, 2, \ldots, 9]^T \]

\[\mathrm{\mathbf{X}} + \mathrm{\mathbf{y}} = \begin{bmatrix} 1 & 4 & 7\\ 2 & 5 & 8\\ 3 & 6 & 9 \end{bmatrix} + \begin{bmatrix} 1 & 4 & 7\\ 2 & 5 & 8\\ 3 & 6 & 9 \end{bmatrix} = \begin{bmatrix} 2 & 8 & 14\\ 4 & 10 & 16\\ 6 & 12 & 18 \end{bmatrix} \]

#행렬-벡터 합 연산
# 행렬 X의 길이와 벡터 y의 길이가 같은 경우
x <- c(1:9); X <- matrix(x, nrow = 3)
length(X); y <- x
[1] 9
X + y
     [,1] [,2] [,3]
[1,]    2    8   14
[2,]    4   10   16
[3,]    6   12   18
# 길이가 다른 경우
# 1) 행렬 길이보다 큰 경우
y <- c(1:10)
X + y
Warning in X + y: 두 객체의 길이가 서로 배수관계에 있지 않습니다
Error in eval(expr, envir, enclos): dims [product 9]가 객체 [10]의 길이와 일치하지 않습니다
# 1) 행렬 길이의 약수가 아닌 경우
# y 재사용
y <- c(1:4)
X + y
Warning in X + y: 두 객체의 길이가 서로 배수관계에 있지 않습니다
     [,1] [,2] [,3]
[1,]    2    8   10
[2,]    4    6   12
[3,]    6    8   10

  • 행렬-벡터 %*% 적용 시 벡터는 \(n \times 1\) 행렬로 간주하고 행렬 곱 연산 수행(단 \(\mathrm{\mathbf X}\)와 벡터 \(\mathrm{\mathbf y}\)의 길이는 같아야 함).

\[\mathrm{\mathbf{X}}_{4\times 3} = \begin{bmatrix} 1 & 2 & 1 \\ 1 & 1 & 1 \\ 1 & 3 & 3 \\ 1 & 4 & 4 \end{bmatrix}, ~~~~~ \mathrm{\mathbf y}_{3\times 1} = [7, 6, 8]^T \]

\[\mathrm{\mathbf{X}}\mathrm{\mathbf{y}} = \begin{bmatrix} 1 & 2 & 1 \\ 1 & 1 & 1 \\ 1 & 3 & 3 \\ 1 & 4 & 4 \end{bmatrix} \cdot \begin{bmatrix} 7 \\ 6 \\ 8 \end{bmatrix} = \begin{bmatrix} 27 \\ 21 \\ 49 \\ 63 \end{bmatrix} \]

x <- c(1, 1, 1, 1, 2, 1, 3, 4, 1, 1, 3, 4)
y <- c(7, 6, 8)
X <- matrix(x, nrow = 4, ncol = 3)
X %*% y
     [,1]
[1,]   27
[2,]   21
[3,]   49
[4,]   63

행렬의 전치(transpose)

  • 전치 행렬(transpose matrix)는 임의의 행렬의 행과 열을 서로 맞바꾼 행렬임
  • 행렬 \(\mathrm{\mathbf X}\)의 전치 행렬은 \(\mathrm{\mathbf X}^T\) 또는 \(\mathrm{\mathbf X}'\) 으로 나타냄
  • 행렬 \(\mathrm{\mathbf X}\)가 다음과 같이 주어졌을 때 전치 행렬 결과

\[\mathrm{\mathbf{X}} = \begin{bmatrix} 1 & 2 & 3\\ 4 & 5 & 6 \end{bmatrix} ~~~~~ \mathrm{\mathbf{X}}^T = \begin{bmatrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{bmatrix} \]

  • R에서 행렬을 전치시키는 함수는 t()
# t(object_name): 전치행렬 반환
x <- 1:6
X <- matrix(x, nrow = 2, ncol = 3, byrow = T)
t(X)
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6
# 전치행렬과 행렬 간 곱
x <- c(1, 1, 1, 1, 1, 22.3, 23.2, 21.5, 25.3, 28.0)
X <- matrix(x, nrow = 5)
t(X) %*% X
      [,1]    [,2]
[1,]   5.0  120.30
[2,] 120.3 2921.87

  • 벡터-벡터 곱 연산(%*% 사용)

\[ \mathrm{\mathbf x} = [1, 2, 3, 4]^T \]

\[\mathrm{\mathbf x}\mathrm{\mathbf x}^T = \begin{bmatrix} 1 \\ 2 \\ 3 \\ 4 \end{bmatrix} \cdot \begin{bmatrix} 1 & 2 & 3 & 4 \end{bmatrix} = \begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 4 & 6 & 8 \\ 3 & 6 & 9 & 12 \\ 4 & 8 & 12 & 16 \end{bmatrix} \]

\[\mathrm{\mathbf x}^T\mathrm{\mathbf x} = \begin{bmatrix} 1 & 2 & 3 & 4 \end{bmatrix} \cdot \begin{bmatrix} 1 \\ 2 \\ 3 \\ 4 \end{bmatrix} = 1 + 4 + 9 + 16 = 30 \]

x <- 1:4
x %*% t(x) # 행렬 반환
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    4    6    8
[3,]    3    6    9   12
[4,]    4    8   12   16
t(x) %*% x # 스칼라 반환 x %*% x와 동일 결과 출력
     [,1]
[1,]   30

참고: 전치행렬의 성질(통계수학 II 강의내용 참고)

  • \((\mathrm{\mathbf{X}}^T)^T = \mathrm{\mathbf{X}}\)
  • \((\mathrm{\mathbf{X} + \mathbf{Y}})^T = \mathrm{\mathbf{X}}^T + \mathrm{\mathbf{Y}}^T\)
  • \((\mathrm{\mathbf{X}\mathbf{Y}})^T = \mathrm{\mathbf{Y}}^T\mathrm{\mathbf{X}}^T\)
  • \((c\mathrm{\mathbf{X}})^T = c\mathrm{\mathbf{X}}^T\), \(c\)는 임의의 상수

역행렬(inverse matrix)

  • 행렬의 나눗셈 형태
  • 행렬 \(\mathrm{\mathbf{X}}\)\(n \times n\) 정방행렬(square matrix)일 때, 아래를 만족하는 행렬 \(\mathrm{\mathbf{Y}}_{n \times n}\)가 존재하면 \(\mathrm{\mathbf{Y}}\)\(\mathrm{\mathbf{X}}\)의 역행렬(inverse matrix)라고 하고 \(\mathrm{\mathbf{X}}^{-1}\)로 나타냄.

\[ \mathrm{\mathbf{X}\mathbf{X}^{-1}} = \mathrm{\mathbf{X}^{-1}\mathbf{X}} = \mathrm{\mathbf{I}}_{n\times n} \]

  • 여기서 \(\mathrm{\mathbf{I}}_{n\times n}\)은 대각 원소가 1이고 나머지 원소는 0인 항등 행렬임
  • \(2 \times 2\) 행렬의 역행렬은 아래와 같이 구함(\(3\times 3\) 이상 역행렬 구하는 방법은 통계수학 II 강의 참고)

\[\mathrm{\mathbf{X}} = \begin{bmatrix} a & b \\ c & d \end{bmatrix}, ~~~~ \mathrm{\mathbf{X}}^{-1} = \frac{1}{ad - bc} \begin{bmatrix} ~~~d & -b \\ -c &~~~a \end{bmatrix} \]

  • R에서 정방 행렬의 역행렬은 solve() 함수를 사용해 구함
# 2 by 2 행렬의 역행렬
x <- c(1, 2, 3, 4)
X <- matrix(x, 2)
solve(X)
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5
# 항등 행렬이 나오는지 확인
X %*% solve(X)
     [,1] [,2]
[1,]    1    0
[2,]    0    1

참고: 역행렬의 성질(통계수학 II 강의내용 참고)

  • \((\mathrm{\mathbf{X}}^{-1})^{-1} = \mathrm{\mathbf{X}}\)
  • \((\mathrm{\mathbf{X}}^T)^{-1} = (\mathrm{\mathbf{X}}^{-1})^T\)
  • \((\mathrm{\mathbf{XY}})^{-1} = \mathrm{\mathbf{Y}}^{-1}\mathrm{\mathbf{X}}^{-1}\)

행렬식(determinant)

  • 행렬의 성질을 대표할 수 있는 하나의 값으로 \(n \times n\) 정방행렬(square matrix)에서 정의
  • 역행렬을 구할 때 임의의 행렬이 0, 즉 위 \(2\times 2\) 행렬에서 \(ad - bc\)의 값이 0이라면 역행렬이 존재할 수 없는데 여기서 \(ad - bc\)\(2\times 2\) 행렬의 행렬식임
  • 임의의 정방행렬 \(\mathrm{\mathbf X}\)의 행렬식은 \(|\mathrm{\mathbf X}|\) 또는 \(\det(\mathrm{\mathbf{X}})\)로 표시함
  • \(2\times 2\) 행렬의 행렬식은 넓이, \(3\times 3\) 이상인 정방 행렬에서는 부피의 개념으로 이해할 수 있음
  • 정방행렬 \(\mathrm{\mathbf X}_{n\times n}=\{x_{ij}\}\)가 주어졌을 때, \(i\) 번째 행과 \(j\) 번째 열을 제외한 나머지 \((n-1)\times (n-1)\) 정방행렬의 행렬식을 \(|\mathrm{\mathbf{X}}_{ij}|\) 라고 하면 이를 \(x_{ij}\)의 소행렬식(minor)이라 부르고 \(x_{ij}\)의 여인수(co-factor) \(\mathrm{\mathbf{C}}_{ij}\) 는 아래와 같이 정의됨

\[ c_{ij} = (-1)^{i+j}|\mathrm{\mathbf{X}}_{ij}| \]

  • 이때 \(\mathrm{\mathbf X}_{n\times n}\) 행렬식은 임의의 \(i\) 또는 \(j\)에 대해 아래의 식을 통해 구할 수 있음

\[ \det(\mathrm{\mathbf{X}}) = \sum_{i=1}^{n}x_{ij}c_{ij} = \sum_{j=1}^n x_{ij}c_{ij} \]

  • 행렬식 계산 예시

\[\mathrm{\mathbf{X}} = \begin{bmatrix} 1 &~~~5 &~~~0\\ 2 &~~~4 & -1\\ 0 & -2 &~~~0 \end{bmatrix} \]

\[\begin{aligned} \det(\mathrm{\mathbf{X}}) &= x_{11}\det(\mathrm{\mathbf{X}}_{11}) - x_{12}\det(\mathrm{\mathbf{X}}_{12}) + x_{13}\det(\mathrm{\mathbf{X}}_{13}) \\ & \\ & = 1 \begin{vmatrix} ~~~4 & -1 \\ - 2&~~~0 \end{vmatrix} -5 \begin{vmatrix} 2 & -1 \\ 0 &~~~0 \end{vmatrix} + 0 \begin{vmatrix} 2 &~~~4 \\ 0 & -2 \end{vmatrix} = -2 \end{aligned} \]

  • R에서 임의 행렬의 행렬식은 det() 함수를 이용해 구함
X <- matrix(c(1, 2, 0, 5, 4, -2, 0, -1, 0), ncol = 3)
det(X)
[1] -2

참고: 행렬식의 성질(통계수학 II 강의내용 참고)

  • 행렬 \(\mathrm{\mathbf{X}}\), \(\mathrm{\mathbf{Y}}\)가 정방행렬이면 \(\det(\mathrm{\mathbf{XY}}) = \det(\mathrm{\mathbf{X}})\det(\mathrm{\mathbf{Y}})\)
  • \(\det(\mathrm{\mathbf{X}}) = \det(\mathrm{\mathbf{X}}^T)\)
  • \(\det(c\mathrm{\mathbf{X}}) = c^n \det(\mathrm{\mathbf{X}})\) 여기서 \(c\)는 임의의 상수
  • \(\det(\mathrm{\mathbf{X}}^{-1}) = \det(\mathrm{\mathbf{X}})^{-1}\)

그외 정칙(non-singluar), 비정칙(non-singular), 양정치(positive definite) 행렬 모두 행렬식으로 정의할 수 있고 자세한 내용은 통계수학 II를 통해 학습. 추가적으로 여인수 \(c_{ij}\) 를 이용한 역행렬 공식은 아래와 같음

\[\mathrm{\mathbf{X}}^{-1} = \frac{1}{\det(\mathrm{\mathbf{X}})} \begin{bmatrix} c_{11} & c_{12} & \cdots & c_{1n} \\ c_{21} & c_{22} & \cdots & c_{2n} \\ \vdots & \vdots & \cdots & \vdots \\ c_{n1} & c_{n2} & \cdots & c_{nn} \end{bmatrix} \]

예습: \(3\times 3\) 정방행렬 \(\mathrm{\mathbf{X}}\)가 아래와 같이 주어졌을 때, \(\mathrm{\mathbf{X}}\)의 행렬식과 역행렬 \(\mathrm{\mathbf{X}}^{-1}\)을 직접 계산해 보고, R에서 각각을 구하는 함수를 사용하여 계산 결과가 맞는지 확인

\[\mathrm{\mathbf{X}} = \begin{bmatrix} 6 & 1 & 4 \\ 2 & 5 & 3 \\ 1 & 1 & 2 \end{bmatrix} \]

2.5.2 행렬의 색인

  • R의 행렬 객체 내 데이터 접근은 벡터와 유사하게 행과 열에 대응하는 색인 또는 이름으로 접근 가능
  • 행렬의 행과 열은 꺽쇠 `[]’ 안에서 ,(콤마)로 구분
  • X[idx_row, idx_col]: 행렬 Xidx_row 행, idx_col행에 저장된 값 반환(색인번호는 1부터 시작)
  • idx_row, idx_col을 지정하지 않으면 전체 행 또는 열을 선택
x <- 1:12
X <- matrix(x, ncol = 4)
X
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
# 1행만 선택
X[1, ]
[1]  1  4  7 10
# 3열만 선택
X[, 3]
[1] 7 8 9
# 1:3행만 선택
X[1:3, ]
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
# 1-2행, 3-4열 선택
X[1:2, 3:4]
     [,1] [,2]
[1,]    7   10
[2,]    8   11

  • 행렬의 각 행과 열에 이름 부여 가능 \(\rightarrow\) matrix() 함수 인수 중 dimnames 에 속성 부여와 동일
  • dimnames() 함수를 통해 각 행과 열의 이름 확인 및 부여 가능
  • dimnames(object)[[i]], i = 1, 2 를 통해 행(i = 1)과 열(i = 2) 이름 변경 및 부여 가능
  • 위와 유사한 기능을 하는 함수
    • rownames(): 헹 이름 반환 및 부여
    • colnames(): 열 이름 반환 및 부여
# matrix 함수 내에서 행렬 이름 동시 부여
X <- matrix(1:9, ncol = 3, 
            dimnames = list(c("1", "2", "3"), # 행 이름
                            c("A", "B", "C")))# 열 이름
X
  A B C
1 1 4 7
2 2 5 8
3 3 6 9
# dimnames()를 이용한 이름 확인
dimnames(X) # 행렬에 대한 리스트 반환
[[1]]
[1] "1" "2" "3"

[[2]]
[1] "A" "B" "C"
# dimnames() 함수로 행 이름 변경
dimnames(X)[[1]] <- c("r1", "r2", "r3")

# dimnames() 함수로 열 이름 변경
dimnames(X)[[2]] <- c("c1", "c2", "c3")
dimnames(X)
[[1]]
[1] "r1" "r2" "r3"

[[2]]
[1] "c1" "c2" "c3"
X
   c1 c2 c3
r1  1  4  7
r2  2  5  8
r3  3  6  9
# rownames()를 통해 행 이름 확인
rownames(X)
[1] "r1" "r2" "r3"
# colnames()를 통해 열 이름 확인
colnames(X)
[1] "c1" "c2" "c3"
# rownames()를 이용해 행 이름 변경
rownames(X) <- c("apple", "strawberry", "orange")
rownames(X)
[1] "apple"      "strawberry" "orange"    
# colnames()를 이용해 행 이름 변경
colnames(X) <- c("costco", "emart", "homeplus")
colnames(X)
[1] "costco"   "emart"    "homeplus"
X
           costco emart homeplus
apple           1     4        7
strawberry      2     5        8
orange          3     6        9

  • 행과 열에 대한 이름이 존재한다면 벡터와 마찬가지로 이름으로 색인 가능
X[c("apple", "orange"), c("emart")]
 apple orange 
     4      6 
# 2번째 열에 해당(emart)를 제외한 나머지 열 반환
X[, colnames(X)[-2]]
           costco homeplus
apple           1        7
strawberry      2        8
orange          3        9

  • 색인한 행렬 원소에 다른 값 할당
y <- c(1:12); Y <- matrix(y, ncol = 3)
Y
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
# 2, 4 행과 2-3열에 다른 값 할당
Y[c(2, 4), 2:3] <- matrix(c(1, 2, 1, 4), ncol = 2)

# 행렬 값 할당 다른 예시
X <- matrix(nrow = 4, ncol = 3) # NA 값으로 구성된 4 by 3 행렬
X
     [,1] [,2] [,3]
[1,]   NA   NA   NA
[2,]   NA   NA   NA
[3,]   NA   NA   NA
[4,]   NA   NA   NA
y <- c(1, 0, 0, 1); Y <- matrix(y, ncol = 2)
X[3:4, 2:3] <- Y
X
     [,1] [,2] [,3]
[1,]   NA   NA   NA
[2,]   NA   NA   NA
[3,]   NA    1    0
[4,]   NA    0    1

  • 행렬 필터링 \(\rightarrow\) 색인 대신 조건 사용(벡터와 동일)
X = matrix(c(1,2,4,3,2,3,5,6), nrow = 4, ncol = 2)

# X의 1열이 3보다 작거나 같은 행 필터링
X[X[,1] <= 3, ]
     [,1] [,2]
[1,]    1    2
[2,]    2    3
[3,]    3    6
# 논리값을 활용한 필터링
idx <- X[, 1] <= 3; idx
[1]  TRUE  TRUE FALSE  TRUE
X[idx, ]
     [,1] [,2]
[1,]    1    2
[2,]    2    3
[3,]    3    6

2.5.3 행과 열 추가 및 제거

  • 행렬 재할당(re-assignment)를 통해 열이나 행을 직접 추가하거나 삭제 가능
  • cbind() (열 붙이기, column bind), rbind() (행 붙이기, row bind) 함수 사용
j <- rep(1, 4)
Z <- matrix(c(1:4, 1, 1, 0, 0, 1, 0, 1, 0), nrow = 4, ncol = 3)
Z
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    1    0
[3,]    3    0    1
[4,]    4    0    0
cbind(j, Z) # 열 기준으로 붙이기
     j      
[1,] 1 1 1 1
[2,] 1 2 1 0
[3,] 1 3 0 1
[4,] 1 4 0 0
# 길이가 다른 경우 재사용
cbind(1, Z)
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    1    2    1    0
[3,]    1    3    0    1
[4,]    1    4    0    0
# Z 행렬 앞에 j 열 붙혀서 새로운 Z 생성
Z <- cbind(j, Z)

# 행 기준으로 붙이기
Z <- rbind(Z, 2)

  • 행 또는 열의 제거는 벡터에서와 마찬가지로 색인 앞에 - 사용
# 첫 번째 행 제거
Z[-1, ]
     j      
[1,] 1 2 1 0
[2,] 1 3 0 1
[3,] 1 4 0 0
[4,] 2 2 2 2
# 1, 5행 , 3열 제거
Z[-c(1, 5), -3]
     j    
[1,] 1 2 0
[2,] 1 3 1
[3,] 1 4 0

cbind() 또는 rbind() 함수는 다음 주에 배울 데이터 프레임에도 적용 가능하다.

2.5.4 행렬 관련 함수

  • diag(): 대각행렬 생성 또는 대각원소(diagonal elements) 추출
  • 대각행렬: 주 대각선을 제외한 모든 원소가 0인 \(n\times n\) 정방행렬로 다음과 같이 정의

\[ \mathrm{\mathbf{D}} = \{d_{ij}\},~~~~i, j \in \{1, 2, \ldots, n\},~~~~\forall~ i \neq j \rightarrow d_{ij} = 0 \]

D <- diag(c(1:5), 5)
D
     [,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
# 3차원 항등 행렬(모든 대각원소가 1인 행렬)
I3 <- diag(1, 3)

#대각원소 추출
diag(D)
[1] 1 2 3 4 5
# 대각원소 재할당
diag(D) <- rep(1, 5)

객체는 속성(attribute)을 갖고 그 속성에 따라 데이터의 구조가 정해짐. 즉 속성은 데이터에 대한 메타 데이터임. 객체의 속성은 대표적으로 이름(names), 차원(dimension), 클래스(class)로 정의되고 객제에 대한 자세한 정보를 파악하기 위해 제공되는 몇 가지 함수들에 대해 알아봄.

R은 앞서 언급한 바와 같이 객체지향언어(object oriented program, OOP)이고 세 가지 유형의 객체지향 시스템(S3, S4, S5)이 존재함. R의 핵심적인 함수 및 패키지는 S3 객체 시스템을 사용하고 있기 때문에 알아둘 필요가 있으나 본 강의의 범위를 벗어나기 때문에 이번 학기에는 다루지 않을 것임.

  • dim(object_name): 행렬 또는 데이터 프레임의 행과 열의 개수(차원)를 반환
# dim(): 객체의 차원(dimension)을 반환
Z
     j      
[1,] 1 1 1 1
[2,] 1 2 1 0
[3,] 1 3 0 1
[4,] 1 4 0 0
[5,] 2 2 2 2
dim(Z)
[1] 5 4

  • nrow() 또는 NROW(): 행렬의 행 길이 반환
  • ncol() 또는 NCOL(): 행렬의 행 길이 반환
nrow(Z); ncol(Z)
[1] 5
[1] 4

nrow()/ncol()NROW()/NCOL()의 차이점

  • nrow()/ncol()은 행렬 또는 데이터 프레임에 적용되며 벡터가 인수로 사용될 때 NULL 값을 반환하는데 비해 NROW()/NCOL()은 벡터의 길이도 반환 가능
  • attributes(): 객체가 갖는 속성을 반환함
x <- 1:9; X <- matrix(x, ncol = 3)
# 객체의 속성 확인
attributes(x)
NULL
attributes(X)
$dim
[1] 3 3

  • class(): 객체의 클래스 명칭 반환 및 클래스 부여
# 객체의 class 확인
class(x); class(X)
[1] "integer"
[1] "matrix" "array" 
# 객체의 class 부여
class(x) <- "this is a vector"

  • str(): 객체가 갖고 있는 데이터의 구조 확인
# 객체의 구조 파악
str(x); str(X)
 'this is a vector' int [1:9] 1 2 3 4 5 6 7 8 9
 int [1:3, 1:3] 1 2 3 4 5 6 7 8 9
# x와 X에 이름(name) 속성을 추가한 경우
names(x) <- paste0("x", 1:9)
dimnames(X) <- list(paste0("r", 1:3), 
                    paste0("c", 1:3))
attributes(x); attributes(X)
$class
[1] "this is a vector"

$names
[1] "x1" "x2" "x3" "x4" "x5" "x6" "x7" "x8" "x9"
$dim
[1] 3 3

$dimnames
$dimnames[[1]]
[1] "r1" "r2" "r3"

$dimnames[[2]]
[1] "c1" "c2" "c3"
class(x); class(X)
[1] "this is a vector"
[1] "matrix" "array" 
str(x); str(X)
 'this is a vector' Named int [1:9] 1 2 3 4 5 6 7 8 9
 - attr(*, "names")= chr [1:9] "x1" "x2" "x3" "x4" ...
 int [1:3, 1:3] 1 2 3 4 5 6 7 8 9
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:3] "r1" "r2" "r3"
  ..$ : chr [1:3] "c1" "c2" "c3"

  • attr(object, "attribute_name"): 객체가 갖고 있는 속성을 지정해서 확인
# 객체 속성 요소 확인
attr(x, "names")
[1] "x1" "x2" "x3" "x4" "x5" "x6" "x7" "x8" "x9"
attr(X, "dimnames")
[[1]]
[1] "r1" "r2" "r3"

[[2]]
[1] "c1" "c2" "c3"

2.5.5 벡터와 행렬의 차이점

  • 행렬은 개념적으로 \(n \times 1\) 벡터가 2 개 이상 묶어져서 행과 열의 속성을 갖지만 기본적으로는 벡터
z <- 1:8
U <- matrix(z, 4, 2)
length(z) # 입력 벡터 원소의 길이가 8
[1] 8

  • R에서 U가 행렬임을 나타내기 위해 추가적인 속성(attribute)를 부여
class(z) # 벡터
[1] "integer"
attributes(z)
NULL
class(U) # 행렬
[1] "matrix" "array" 
attributes(U)
$dim
[1] 4 2

2.5.6 의도치 않은 차원축소 피하기

  • 다음 행렬에서 한 행을 추출
Z <- matrix(c(1:8), 4, 2)
z <- Z[2, ]

attributes(Z) # 행과 열의 차원 수를 표시
$dim
[1] 4 2
# 객체 z의 속성및 형태는? 
attributes(z) # 차원이 존재하지 않음
NULL

  • 차원축소를 방지하는 방법 \(\rightarrow\) r을 벡터가 아닌 \(1 \times 2\) 행렬로 인식
z <- Z[2, , drop = FALSE]
attributes(z)
$dim
[1] 1 2

  • as.matrix()를 이용한 직접 변환
z <- as.matrix(Z[2, ])
class(z)
[1] "matrix" "array" 
z # 행렬이 변환됨을 유의
     [,1]
[1,]    2
[2,]    6