R) 행렬 - 조작

R) 행렬 - 조작

행렬은 1차원 부터 n차원 까지 고차원의 데이터 표현이 가능하다. 그래서 보통 3차원 이상의 정보를 담고 있는 이미지 데이터 조작에도 많이 활용되기도 하고 각종 머신러닝 알고리즘 구현에 근간이 되는 행렬 연산을 지원하는 matrix 객체를 다뤄보자.

기본 행렬의 조작

행이름(rowname)이나 열이름(columnname)을 지정하지 않고 원소 배치만 활용하여 만드는 기본 행렬을 다뤄보도록 한다. 다음의 코드를 참고하여 mat1 객체를 생성해보자.

1
2
3
4
5
6
mat1 = matrix(letters[1:12], nrow = 3, byrow = TRUE)
mat1
## [,1] [,2] [,3] [,4]
## [1,] "a" "b" "c" "d"
## [2,] "e" "f" "g" "h"
## [3,] "i" "j" "k" "l"

matrix 객체는 특이하게도 2차원 벡터이지만 1차원 벡터처럼 원소를 추출할 수 있다. 단, 각 원소의 index는 column방향을 기준으로 하기 때문에 다음의 코드의 입력과 출력을 잘 확인하기 바란다.

1
2
3
4
5
6
7
8
mat1[1]
## [1] "a"

mat1[4]
## [1] "b"

mat1[9]
## [1] "k"

2차원 객체의 벡터연산(객체의 내부 원소를 추출하기 위해 객체명 직후에 대괄호를 사용하는 연산)은 대괄호 안에 쉼표를 추가하여 쉼표 앞은 row, 쉼표 뒤는 column에 관여한다. 다음의 코드는 첫번째 row와 첫번째 column의 원소를 출력하는 코드이다.

1
2
3
4
5
mat1[1, ]
## [1] "a" "b" "c" "d"

mat1[, 1]
## [1] "a" "e" "i"

앞의 코드는 각각 뒤와 앞을 생략했는데 벡터연산에서는 특정 위치에 아무것도 입력하지 않으면 전체를(여기서는 row 또는 column) 지정하는 것과 같다. 다음의 코드는 쉼표 앞뒤로 모두 값을 지정하였고 직전 코드 실행결과와 같은 것을 알 수 있다.

1
2
3
4
5
mat1[1, 1:4]
## [1] "a" "b" "c" "d"

mat1[1:3, 1]
## [1] "a" "e" "i"

앞의 코드 실행결과는 모두 matrix가 아닌 1차원 벡터로 출력되었다. matrix는 출력결과가 2차원이 아닌 경우는 matrix객체 구조가 아닌 1차원 벡터로 출력한다. 혹시나 이를 방지하기 위해서는 drop 인자에 FALSE를 입력하여 원소 하나만 출력하더라도 matrix객체 구조를 유지할 수 있도록 해준다.

1
2
3
4
5
6
mat1[1, 2]
## [1] "b"

mat1[1, 2, drop = FALSE]
## [,1]
## [1,] "b"

다음과 같이 출력 결과가 2차원인 경우 matrix객체 구조를 유지하는 것을 볼 수 있다.

1
2
3
4
5
6
7
8
mat1[1:2, 2:3]
## [,1] [,2]
## [1,] "b" "c"
## [2,] "f" "g"
mat1[c(1, 3), c(2, 4)]
## [,1] [,2]
## [1,] "b" "d"
## [2,] "j" "l"

이름이 있는 행렬의 조작

행이름(rowname)과 열이름(columnname)이 지정된 matrix객체를 다뤄보자.

1
2
3
4
5
6
7
8
mat2 = matrix(11:19, nrow = 3, byrow = TRUE,
dimnames = list(c("r1", "r2", "r3"),
c("c1", "c2", "c3")))
mat2
## c1 c2 c3
## r1 11 12 13
## r2 14 15 16
## r3 17 18 19

이전에는 특정 열 또는 행의 index를 숫자로 지정했지만 행이름과 열이름이 있는 경우는 이렇게 각 이름을 명시하여 원소를 추출할 수 있다.

1
2
3
4
5
6
mat2[, "c1"]
## r1 r2 r3
## 11 14 17
mat2["r1", ]
## c1 c2 c3
## 11 12 13

두 개 이상의 열이름과 행이름을 지정하여 원소를 추출할 수 있고 행 또는 열의 원소를 추출할 때 다음의 2번 코드처럼 열 추출은 숫자, 행 추출은 문자를 활용해도 된다.

1
2
3
4
5
6
7
8
mat2[c("r1", "r3"), c("c1", "c3")] # 1
## c1 c3
## r1 11 13
## r3 17 19
mat2[1:2, c("c2", "c3")] # 2
## c2 c3
## r1 12 13
## r2 15 16

단, 첫번째 변수와 “c3” 변수를 추출하기 위해 c(1, "c3")처럼 적으면 안된다.

행렬 정보 확인

matrix 객체를 살펴보고 원하는 원소를 추출하기 위해 mat3 객체를 준비한다.

1
2
3
4
5
6
7
mat3 = matrix(1:9, nrow = 3,
dimnames = list(c("a", "b", "c"), c("d", "e", "f")))
mat3
## d e f
## a 1 4 7
## b 2 5 8
## c 3 6 9

객체 구조, 행렬 크기, 열이름, 행이름을 확인하기 위하여 차례대로 str(), dim(), colnames(), rownames() 함수를 사용해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
str(mat3)
## int [1:3, 1:3] 1 2 3 4 5 6 7 8 9
## - attr(*, "dimnames")=List of 2
## ..$ : chr [1:3] "a" "b" "c"
## ..$ : chr [1:3] "d" "e" "f"

dim(mat3)
## [1] 3 3

colnames(mat3)
## [1] "d" "e" "f"

rownames(mat3)
## [1] "a" "b" "c"

여기서 dim() 함수는 2차원 matrix객체가 입력될 경우 두 숫자를 출력하는데 첫 번째 숫자는 row 개수이고, 두 번째 숫자는 column 개수이다. mat3 객체는 3x3 행렬이라 dim() 함수의 결과에서 3이 2개인 것을 확인할 수 있다.

행이름 또는 열이름을 초기화 하거나 바꾸기 위해서 다음과 같이 코드를 작성할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rownames(mat3) = NULL
mat3
## d e f
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
colnames(mat3)[1] = "var1"
mat3
## var1 e f
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
colnames(mat3) = c("col1", "col2", "col3")
mat3
## col1 col2 col3
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9

head()tail() 함수를 사용하여 처음 또는 마지막 행 부터 원하는 개수의 행을 추출할 수 있다.

1
2
3
4
5
6
7
8
9
head(mat3, 2)
## col1 col2 col3
## [1,] 1 4 7
## [2,] 2 5 8

tail(mat3, 2)
## col1 col2 col3
## [2,] 2 5 8
## [3,] 3 6 9

여기서는 mat3 객체의 row개수가 3개 밖에 되지 않기에 head(), tail() 함수 전부 2개 행만 출력하도록 했지만 각 함수의 기본값은 6으로 별도의 숫자를 지정하지 않으면 6개 행을 추출할 수 있다.

전치(transpose)행렬을 확인하려면 t() 함수를 사용할 수 있다.

1
2
3
4
5
t(mat3)
## [,1] [,2] [,3]
## col1 1 2 3
## col2 4 5 6
## col3 7 8 9

행렬의 대각 원소(diagonal elements)만 추출하려면 diag() 함수를 사용할 수 있다.

1
2
diag(mat3)
## [1] 1 5 9

하삼각행렬과 상삼각행렬과 관련된 함수는 lower.tri()upper.tri() 함수이다. 다음 예제를 확인해보자.

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
lower.tri(mat3)
## [,1] [,2] [,3]
## [1,] FALSE FALSE FALSE
## [2,] TRUE FALSE FALSE
## [3,] TRUE TRUE FALSE

lower.tri(mat3, diag = TRUE)
## [,1] [,2] [,3]
## [1,] TRUE FALSE FALSE
## [2,] TRUE TRUE FALSE
## [3,] TRUE TRUE TRUE

mat3[lower.tri(mat3)]
## [1] 2 3 6

mat3[lower.tri(mat3, diag = TRUE)]
## [1] 1 2 3 5 6 9

upper.tri(mat3, )
## [,1] [,2] [,3]
## [1,] FALSE TRUE TRUE
## [2,] FALSE FALSE TRUE
## [3,] FALSE FALSE FALSE

upper.tri(mat3, diag = TRUE)
## [,1] [,2] [,3]
## [1,] TRUE TRUE TRUE
## [2,] FALSE TRUE TRUE
## [3,] FALSE FALSE TRUE

mat3[upper.tri(mat3)]
## [1] 4 7 8

mat3[upper.tri(mat3, diag = TRUE)]
## [1] 1 4 5 7 8 9

lower.tri()upper.tri() 함수만 사용할 경우 각 행렬에 해당하는 위치의 원소가 TRUE 또는 FALSE로 표기된다. 이를 활용하여 원소를 추출하려면 대괄호를 사용한 벡터연산이 필요하다. 그리고 diag 인자에 TRUE를 할당하면 대각원소 까지 포함된다.

원소를 추출하는 것이 아니라 상삼각행렬 또는 하삼각행렬만 남기고자 한다면 다음과 같이 응용코드를 작성할 수 있다.

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
mat3_l1 = mat3
mat3_l1[upper.tri(mat3_l1)] = NA
mat3_l1
## col1 col2 col3
## [1,] 1 NA NA
## [2,] 2 5 NA
## [3,] 3 6 9

mat3_l2 = mat3
mat3_l2[upper.tri(mat3_l2, diag = TRUE)] = NA
mat3_l2
## col1 col2 col3
## [1,] NA NA NA
## [2,] 2 NA NA
## [3,] 3 6 NA

mat3_u1 = mat3
mat3_u1[lower.tri(mat3_u1)] = NA
mat3_u1
## col1 col2 col3
## [1,] 1 4 7
## [2,] NA 5 8
## [3,] NA NA 9

mat3_u2 = mat3
mat3_u2[lower.tri(mat3_u2, diag = TRUE)] = NA
mat3_u2
## col1 col2 col3
## [1,] NA 4 7
## [2,] NA NA 8
## [3,] NA NA NA

<객체 시리즈 - 행렬>
R) 행렬 - 생성
R) 행렬 - 조작
R) 행렬 - 연산

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×