R 행렬 값 바꾸기 - R haenglyeol gabs bakkugi

05. 행렬과 배열 Matrix & Array

* 본 블로그의 모든 게시물은 전문적인 내용이 아님을 알려드립니다.

 * 내용에 오류가 있거나 불친절한 설명이 있는 경우 언제든지 댓글로 의견을 남겨주세요!

목차

0. 행렬과 배열

1. 행렬과 배열의 생성

2. 행렬과 배열의 인덱싱

3. 행렬과 배열의 필터링

4. 행렬간 연산 및 함수

5. 행렬의 결합

* 사용함수 정리

#colnames(), rownames()

0. 행렬과 배열

행렬과 배열은 앞장 04. 벡터 Vector의 첫번째 R의 자료구조에서 다뤘듯이 동일한 타입만 받는 구조입니다.

행렬은 행과 열로 이루어진 우리가 수학적으로 알고 있는 행렬과 동일한 형태이고 배열은 이러한 행렬을 여러장을 쌓아 올린 형태입니다.

행렬과 배열을 생성하고 인덱싱 및 필터링 하는 과정을 알아보도록 하겠습니다.

1. 행렬과 배열의 생성

1-1) 행렬 생성

matrix(값, nrow = 행의 개수, ncol = 열의 개수,

byrow = FALSE(디폴트 값),

# 값의 입력 방향, TRUE설정시 행 우선 입력, FALSE시 열 우선 입력             

# 디폴트란 아무 설정을 하지 않을 시 자동으로 적용되는 값을 말함

dimnames = NULL)

# 행과 열의 이름, 반드시 list로 기입

> matrix(1:9, nrow = 3)

    [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

# 이 경우엔 nrow나 ncol 하나의 값만 지정해주어도 된다.

# 9개 요소를 3개의 행으로 둔다는 말은 3x3 행렬을 뜻하기 때문

# byrow= , 파라매터를 사용하지 않을 시 1열부터 채워 나가는 것을 확인할 수 있다.

> matrix(1:9, nrow = 3, byrow=TRUE)

     [,1] [,2] [,3]

[1,]    1    2    3

[2,]    4    5    6

[3,]    7    8    9

> matrix(1:9, nrow = 3, byrow=TRUE, dimnames = list(c("행1","행2","행3"), c("열1","열2","열3")))

    열1 열2 열3

행1   1   2   3

행2   4   5   6

행3   7   8   9

# dimnames 는 list로 감싸주어야 한다. list는 다음 게시글에서 자세히 다룰 예정

# 위 예시에서 볼 수 있듯이 list의 첫번째 요소 c("행~",...)는 행의 이름을, 두번째 요소는 열의 이름을 뜻한다.

# 행렬 생성시 dimnames를 이용해 행,열 이름을 지정하기 보단

*colnames(), *rownames()를 통해 행렬의 이름을 지정하는 방법을 자주 사용한다.

1-2) 배열 생성

array(값,

dim = c(행의 개수,열의 개수,페이지(=차원)의 개수),

dimnames = NULL)

# 행,열,페이지의 이름, 반드시 list로 기입

> array(1:27, dim = c(3,3,3))

# 배열을 만들겠다, 값은 1~27이고 3개의 행 3개의 열로 구성된 행렬 3개로 이루어진 배열.

, , 1

# 1번째 행렬을 말한다. 편의상 페이지라고 하겠다.

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

, , 2

     [,1] [,2] [,3]

[1,]   10   13   16

[2,]   11   14   17

[3,]   12   15   18

, , 3

     [,1] [,2] [,3]

[1,]   19   22   25

[2,]   20   23   26

[3,]   21   24   27

> array(1:27, dim = c(3,3,3),

dimnames = list(c("행1","행2","행3"), c("열1","열2","열3"), c("페이지1","페이지2","페이지3")))

# 행렬과 동일하게 list로 묶어주며 1번째는 행, 2번째는 열, 3번째는 페이지의 이름을 뜻한다.

, , 페이지1

    열1 열2 열3

행1   1   4   7

행2   2   5   8

행3   3   6   9

, , 페이지2

    열1 열2 열3

행1  10  13  16

행2  11  14  17

행3  12  15  18

, , 페이지3

    열1 열2 열3

행1  19  22  25

행2  20  23  26

행3  21  24  27

2. 행렬과 배열의 인덱싱

2-1) 행렬의 인덱싱

행렬의 인덱싱에선 콤마를 기준으로 콤마 앞은 행, 콤마 뒤는 열 이라고 생각하셔야 됩니다.

인덱싱을 통해 원하는 요소 출력, 행의 출력, 열의 출력을 할 수 있으며 방법은 다음과 같습니다.

행렬[의 index, 의 index]

여기서 해당 인덱스 자리를 공백으로 두게되면 해당 인덱스는 전부 출력시켜라와 동일한 의미입니다.

쉽게 생각하면 기본 타입은 행렬[x,y]이나 둘 중 하나를 빈칸으로 두게 되면 특별하게 지정한 행이나 열이 없으니 해당 행or열은 전부 출력시킨다와 같습니다.

예를 들어 행렬[x, ] 와 같이 열의 index를 빈칸으로 두게되면 특별히 지정한 열의 값이 없으니 x행에 속한 모든 열의 값을 출력시키라는 의미입니다.

# 행의 자리를 비워두면 원하는 열의 모든 값을 출력

# 열의 자리를 비워두면 원하는 행의 모든 값을 출력

> a <- matrix(1:9, nrow = 3)

> a

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

# a의 1행 1열의 요소, 행렬의 인덱싱을 통해 나오는 것은 벡터 형태이다.

> a[1,1]

[1] 1

# a의 1행 3열의 요소를 뽑아라

> a[1,3]

[1] 7

# a의 1행을 출력, [원하는 행, ]으로 열자리를 비움으로써 해당 행의 모든 값을 출력한다.

> a[1, ]

[1] 1 4 7

# a의 2행~3행을 출력

> a[2:3,]

    [,1] [,2] [,3]

[1,]    2    5    8

[2,]    3    6    9

# a의 1열을 출력,

# 행의 자리를 비우고[ , 원하는 열]을 통해 해당 열의 모든 행의 값을 출력할 수 있다.

> a[ ,1]

[1] 1 2 3

# a의 2열을 출력,

> a[ ,2]

[1] 4 5 6

# 행과 열을 출력할 때 행렬의 형태를 보존해서 출력하고 싶은 경우 drop=FALSE를 해준다.

> a[,2, drop=F]

     [,1]

[1,]    4

[2,]    5

[3,]    6

# a의 2열~3열을 출력,

> a[ , 2:3]

     [,1] [,2]

[1,]    4    7

[2,]    5    8

[3,]    6    9

2-2) 배열의 인덱싱

배열의 인덱싱은 행렬과 동일하고 페이지(=차원)의 인덱스만 추가됩니다.

배열[의 index, 의 index, 페이지의 index]

> z <- array(1:27, dim = c(3,3,3),

dimnames = list(c("행1","행2","행3"), c("열1","열2","열3"), c("p1","p2","p3")))

> z

, , p1

    열1 열2 열3

행1   1   4   7

행2   2   5   8

행3   3   6   9

, , p2

    열1 열2 열3

행1  10  13  16

행2  11  14  17

행3  12  15  18

, , p3

    열1 열2 열3

행1  19  22  25

행2  20  23  26

행3  21  24  27

# 1페이지의 3행 3열의 요소

> z[3,3,1]

[1] 9

# 2페이지의 1행 3열의 요소

> z[1,2,2]

[1] 13

# 2페이지의 모든 행, 모든 열의 값, 즉 2페이지 행렬 출력

> z[ , ,2]

    열1 열2 열3

행1  10  13  16

행2  11  14  17

행3  12  15  18

# 1페이지, 3페이지 출력

> z[ , , c(1,3)]

, , p1

    열1 열2 열3

행1   1   4   7

행2   2   5   8

행3   3   6   9

, , p3

    열1 열2 열3

행1  19  22  25

행2  20  23  26

행3  21  24  27

# z배열에서 1행들만 뽑아라, 밑의 값을 보자면 p1의 1행 값들은 1 4 7 p2에서 1행의 요소는 10 13 16임을 알 수 있다.

> z[1, , ]

    p1 p2 p3

열1  1 10 19

열2  4 13 22

열3  7 16 25

z배열에서 2열들만 뽑아라

> z[ , 2, ]

    p1 p2 p3

행1  4 13 22

행2  5 14 23

행3  6 15 24

3. 행렬과 배열의 필터링

원하는 조건에 맞는 값을 뽑아내는 것을 필터링이라고 했습니다. 필터링을 하기위해선 반드시 인덱싱에 대한 이해가 필요합니다.

예시를 통해 알아보도록 하겠습니다.

> a <- matrix(1:9, nrow =3);a

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

> a[a[ ,2] > 4, ]

무엇을 뽑고싶은 걸까요? 하나하나 살펴 보도록 합시다. 앞에서 ','콤마를 기준으로 앞에 있는 것은 행이라고 했습니다.

그렇다면 위의 식은 어느 특정한 조건에 맞는 행을 뽑기 위한 것임을 알 수 있습니다.

> a[조건a[,2]>4, ]            #조건에 맞는 행을 출력시킨다.

조건을 알아보니 여기에도 인덱스가 들어가있네요.

a[ ,2] > 4

해석을 해보면 a의 2열이 4보다 큰 값입니다. 우선 a[ ,2]를 실행시켜보면

> a[ ,2]

[1] 4 5 6

이 나오며 비교 연산자를 통해 논리 값을 구해보면 다음과 같이 나옵니다.

> a[,2] > 4

[1] FALSE TRUE TRUE

인덱싱의 기본은 논리형 값에서 TRUE만 출력시키는 것이라고 했었죠?

즉 처음에 복잡해 보였던 a[a,2]>4,] 는 결국 a에서 조건에 맞는 행을 추출하는데 조건의 결과가 두번째와 세번째요소를 나타내는 것이여서

결국엔 다음과 같은 결과가 나옵니다.

> a[a[,2] > 4, ]

     [,1] [,2] [,3]

[1,]    2    5    8

[2,]    3    6    9

앞에서 했던 것과 동일한 것을 알 수 있습니다

> a[2:3,]

     [,1] [,2] [,3]

[1,]    2    5    8

[2,]    3    6    9

> x <- 1:3

> a[x %% 2 == 1, ]

이것은 무엇을 뽑고 싶은 것일까요?

위의 예시와 마찬가지로 ','콤마 앞에 조건이 들어가있기 때문에 원하는 행을 추출하려는 것을 알 수 있습니다.

조건을 살펴 봅니다.

x %% 2 == 1

x는 1,2,3으로 주어졌고 각각을 2로 나눈 나머지가 1인 경우를 추출하려고 하나보네요.

2로 나눈 나머지가 1이다? 이는 홀수를 의미하며 a에서 홀수 행만 뽑으라는 것이구나! 라는 것을 알 수 있습니다.

따라서 a의 홀수행만 추출한 결과는 다음과 같습니다.

> a[x%%2==1,]

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    3    6    9

나머지 연산을 통해 짝수와 홀수를 구별하는 문제는 자주 사용되니 알아두면 좋습니다.

위에서 보았듯이 필터링의 기본은 인덱싱입니다. 원하는 행을 추출하고 싶어? 그러면 행렬의 인덱싱에서 ',' 콤마 앞쪽에 조건을 줘야 겠구나!

원하는 열을 추출하고 싶어? 그러면 행렬의 인덱싱에서 ','콤마 뒤쪽에 조건을 줘야겠구나!라는 생각이 자유자재로 드셔야 합니다.

배열은 행렬의 필터링과 동일하니 따로 예시는 들지 않겠습니다.

4. 행렬간 연산 및 함수

행렬과 행렬간의 곱은 %*% (행렬곱) 연산자를 통해 사용합니다. 

벡터와 행렬간의 곱도 가능하며 행렬곱은 항상 수학적으로 곱이 가능한 형태를 갖는 행렬 or 벡터만이 가능합니다.

예로 1x3벡터와 3x3행렬을 곱해보겠습니다.

> x <- 1:3

> y <- matrix(1:9, nrow =3)

> x %*% y

     [,1] [,2] [,3]

[1,]   14   32   50

> y %*% x

     [,1]

[1,]   30

[2,]   36

[3,]   42

행렬 곱이 불가한 형태를 곱하면 다음과 같이 에러가 나옵니다.

> x <- 1:2

> y <- matrix(1:9, nrow =3)

> x %*% y

Error in x %*% y : non-conformable arguments

다음은 행렬내의 요소들을 여러 함수를 통해 요약해보겠습니다.

> m <- matrix(1:9, nrow =3);m

     [,1] [,2] [,3]

[1,]    1    4    7

[2,]    2    5    8

[3,]    3    6    9

# rowMeans() : 행별로 평균을 내라

> rowMeans(m)

[1] 4 5 6

# rowSums() : 행별로 합을 내라

> rowSums(m)

[1] 12 15 18

# colMeans() : 열별로 평균을 내라

> colMeans(m)

[1] 2 5 8

# colSums() : 열별로 합을 내라

> colSums(m)

[1]  6 15 24

다음은 행렬의 형태를 확인할 수 있는 함수입니다.

> m2 <- matrix(1:12, nrow =4);m2

     [,1] [,2] [,3]

[1,]    1    5    9

[2,]    2    6   10

[3,]    3    7   11

[4,]    4    8   12

# attributes() : 행렬 구조를 리스트 형태로 반환

> attributes(m2)

$dim

[1] 4 3

dim() : 행렬 구조를 벡터 형태로 반환

> dim(m2)

[1] 4 3

# ncol() : 열의 개수

> ncol(m2)

[1] 3

nrow() : 행의 개수

> nrow(m2)

[1] 4

이러한 행렬을 전치시킬 수 있다. 전치란 행과 열을 바꾼다는 것을 의미한다.

t() : 행렬의 전치

> t(m2)

     [,1] [,2] [,3] [,4]

[1,]    1    2    3    4

[2,]    5    6    7    8

[3,]    9   10   11   12

5. 행렬의 결합

이미 만들어진 행렬에 새로운 값을 행결합, 열결합을 통해 추가할 수 있습니다.

열을 결합할 땐 cbind(), 행을 결합할 땐 rbind()를 사용합니다. 

다음과 같이 만들어진 m3에 행과 열을 추가하고 기존에 만들었던 m2와도 합쳐보겠습니다.

> m3 <- matrix(1:4, nrow=2);m3

     [,1] [,2]

[1,]    1    3

[2,]    2    4

rbind() : 행결합, 왼쪽 인자값에 우측값을 결합한다.

> rbind(m3, c(3,5))

     [,1] [,2]

[1,]    1    3

[2,]    2    4

[3,]    3    5

순서를 바꿔서 rbind를 진행할 경우 3,5가 먼저 들어가게 됩니다.

> x <- c(3,5)

> rbind(x,m3)

     [,1] [,2]

[1,]    3    5

[2,]    1    3

[3,]    2    4

주의할 점은 이렇게 나온 결과값은 m3에 저장이 되지 않습니다.

즉 함수를 통해 나온 결과는 단순히 실행을 할 경우 이렇게 나옵니다~를 말해주는 것이지 변수안의 값을 변화시키진 않습니다.

rbind를 한 결과를 m3에 할당을 해주는 작업을 통해서 m3에 c(3,5)를 행결합한 결과를 저장할 수 있습니다.

> m3 <- rbind(m3, c(3,5));m3

     [,1] [,2]

[1,]    1    3

[2,]    2    4

[3,]    3    5

# cbind() : 열결합, 마찬가지로 왼쪽 인자값에 우측 인자값을 결합한다.

> cbind(m3, c(6,7,8))

     [,1] [,2] [,3]

[1,]    1    3    6

[2,]    2    4    7

[3,]    3    5    8

주의할 점은 행,열결합을 실행할 때 값의 개수를 맞춰주어야 합니다. 

개수를 맞추지 않으면 실행이 되는 경우라도 값을 삭제하고 결합하기 때문에 원하는 결과값이 나오기 힘들고, 아예실행이 되지 않는 경우도 있습니다.

rbind와 cbind를 이용해 행렬끼리 결합 또한 가능합니다. 전에 만들어 두었던 m2와 결합을 해보겠습니다.

> rbind(m2,m3)

     [,1] [,2] [,3]

[1,]    1    5    9

[2,]    2    6   10

[3,]    3    7   11

[4,]    4    8   12

[5,]    1    3    6

[6,]    2    4    7

[7,]    3    5    8

# 행의 개수를 맞추어 주기위해 m2를 전치시켰다. 3x4행렬과 3x3행렬의 열결합

> cbind(t(m2),m3)

     [,1] [,2] [,3] [,4] [,5] [,6] [,7]

[1,]    1    2    3    4    1    3    6

[2,]    5    6    7    8    2    4    7

[3,]    9   10   11   12    3    5    8

* 사용 함수 정리

*01. colnames(), rownames()

- colnames()는 열의 이름을, rownames()는 행의 이름을 확인하여 주며 해당 함수 실행시 결과값은 벡터이다.

- 앞선 예시를 통해 알아보자.

> a <- matrix(1:9, nrow = 3, byrow=TRUE, dimnames = list(c("행1","행2","행3"), c("열1","열2","열3")))

> a

    열1 열2 열3

행1   1   2   3

행2   4   5   6

행3   7   8   9

> colnames(a)

[1] "열1" "열2" "열3"

> rownames(a)

[1] "행1" "행2" "행3"

- 이렇게 출력된 결과값은 벡터라고 했다. 따라서 변수 할당, 인덱싱 등 벡터연산의 모든것이 가능하다.

# colnames(a)의 첫번째 요소

> colnames(a)[1]

[1] "열1"

# rownames(a)의 두번째~세번째 요소

> rownames(a)[2:3]

[1] "행2" "행3"

# 세미콜론';'을 통해 변수의 생성과 출력을 한줄에 할 수 있다.

# 세미콜론은 한줄을 띄운것과 같은 의미를 갖는다.

> b <- matrix(1:9, nrow = 3, byrow=TRUE);b

[,1] [,2] [,3]

[1,]    1    2    3

[2,]    4    5    6

[3,]    7    8    9

> colnames(b)

[1] NULL

> rownames(b)

[1] NULL

# 이름을 설정하지 않았을 땐 값이 없음을 뜻하는 NULL이 출력됨을 알 수 있다.

# 이름이 없는 행렬에 col,rownames()를 활용하여 이름을 만들어 주자.

> colnames(b) <- c("열_1", "열_2", "열_3")

> rownames(b) <- c("행_1", "행_2", "행_"3")

> b

     열_1 열_2 열_3

행_1    1    2    3

행_2    4    5    6

행_3    7    8    9

# row,colnames()를 통해 특정 행,열의 이름만 바꿀 수 있다. 왜? 벡터이기 때문에

> rownames(b)[2] <- "row2"

> b

     열_1 열_2 열_3

행_1    1    2    3

row2    4    5    6

행_3    7    8    9

2