[DEBUG-WINDOW 처리영역 보기]
즐겨찾기  |  뉴스레터  |  오늘의 정보  |  e브릭몰e브릭몰 회원가입   로그인
BRIC홈 동향
라이카써머캠프
스폰서배너광고 안내  배너1 배너2 배너3 배너4
과학으로 본 코로나19 (COVID-19)
전체보기 Bio통신원 Bio통계 BRIC View BRIC이만난사람들 웹진(BioWave)
목록
조회 1154  인쇄하기 주소복사 트위터 공유 페이스북 공유 
바이오통신원   
[초심자를 위한 생물학+정보학] R의 자료 형태와 구조 2 - 54
생명과학 고주온 (2020-06-26)
_54_
- R의 자료 형태와 구조 2 -

지난 회차까지  R의 기본적인 자료 객체인 벡터1 (수치형, 복소수형, 논리형, 문자형, raw형)에 관하여 알아 보았다. 이번에는 행렬 (matrix), 리스트 (list) 및 데이터프레임 (data frame)에 관한 내용을 알아 보자.

독자들 가운데에서는 행렬에 대하여 중고생 시절 이후에 접할 기회가 없었던 사람도 있으리라 예상되는데, 여기서는 아주 기본적인 사항만 확인하고 R에서 사용할 수 있을 정도로만 살펴보고자 한다. 참고로, 행렬은 전산학 분야, 특히 그래픽 (computer graphics) 영역에서는 위상수학 (topology)과 함께 없어서는 안 되는 중요한 분야이다. 그림이나 형체의 크기 변경이나 렌더링 (rendering) 위치의 수정 등을 위해 행렬 연산이 필수적이다.

행렬은 알다시피  2차원 자료 구조로서, 행 (row)과 열 (column)로 배열된 숫자 집합이다. 행렬은 가로줄의 행 (row)과 세로줄의 열 (column)로 구성되어 있으며, 이를 일반적인 형태로 표현해 보면 다음과 같다.
 

R의 자료 형태와 구조 2 - 54


위 도식에서 각 e는 해당 행렬의 원소 (element)를 표시하며, 붉은 숫자는 행 (row)을 푸른 숫자는 열 (column)을 의미한다. 따라서, 이는 (m x n) 행렬을 나타낸 것이다. 예컨대, 가로 2행, 세로 3열 (2 x 3)의 행렬에 대하여 아래와 같은 예를 들 수 있다.

R의 자료 형태와 구조 2 - 54


R에서 이러한 행렬을 만드는 방법은 여러 가지 있다.

그 전에 우선, R에서 벡터의 특징에 대해 한 가지만 확인하고 다음으로 넘어가자.

지난 회차에서 하나의 벡터를 이루는 원소는 모두 동일한 자료형이어야 한다고 했는데, 사용자가 잘못 입력하는 경우에는 어떤 일이 일어나는지 살펴보자.

------
> var0 <- 3.14  <-- (1)
> print(var0)  <-- (2)
[1] 3.14
> var0  <-- (3)
[1] 3.14
> var1 <- "ABC"  <-- (4)
> var1  <-- (5)
[1] "ABC"
> var2 <- c("A", "97", "b", 70)  <-- (6)
> var2[4]  <-- (7)
[1] "70"
> var2  <-- (8)
[1] "A"  "97" "b"  "70"
> var3 <- c(1, 2, 3)  <-- (9)
> var3  <-- (10)
[1] 1 2 3
> var3 * 3  <-- (11)
[1] 3 6 9
> var4 <- c(1, 3, 5)  <-- (12)
> var3 * var4  <-- (13)
[1]  1  6 15
> var4 - var3  <-- (14)
[1] 0 1 2
>
------

변수 var0에 수치 3.14를 할당하고 (1), 함수 print()를 사용하여 이를 출력한다 (2). 이때, 변수명을 그대로 입력해도 그 값이 출력된다 (3). 변수 var1에는 문자열 ABC를 입력한 후 (4), 그 값을 출력한다 (5). 이번에는 변수 var2에 문자 A, 문자열 97, 문자 b, 그리고 숫자 70을 할당한다 (6). 이때 사용하는 함수 c()c는 연결 (concatenate)을 의미하는 것으로서 각각 하나의 값으로 구성된 네 벡터 ("A", "97", "b", 70)를 하나로 연결해 주는 기능을 한다. 이렇게 하나의 변수 (var2)에 저장된 각각의 값을 확인하고자 할 때에는 인덱스2를 이용하여 확인할 수 있다 (7). 그런데, 수치로 입력된 네번째 값을 확인해 보니 (7), 문자열로 나타난다. 변수값 전체를 출력해 보니 역시 4개의 모든 값이 문자열로 되어 있다 (8). 이것은 R에서 이렇게 여러 값이 연결되어 하나의 벡터가 되는 경우, 동일한 자료형을 가져야 하기 때문에 수치와 문자열이 혼재할 경우에는 모두 문자열로 변환된다. 다만, 변수 var3var4처럼 그 안에 들어 있는 여러 값이 전부 수치일 때 (9)는 모두 수치로 저장되며 (10), 그 길이가 동일한 경우에 둘 간의 연산 또한 가능하다 (11-14).

R에서의 행렬은 수학에서의 그것과 개념이 같은데, 다만 기술적으로는 행과 열의 두 가지 속성을 추가로 갖는 수치 벡터라고 볼 수 있다. 따라서 행렬의 각 원소의 값이 존재할 경우에는 모두 숫값이다. 이제 R에서 행렬을 만드는 여러 가지 가운데 먼저 matrix() 함수를 사용하는 방법에 대하여 알아보자.

------
> mat1 <- matrix(c(3, 0, 2, -2, -1, 3), nrow = 2)  <-- (1)
> print(mat1)  <-- (2)
     [,1] [,2] [,3]
[1,]    3    2   -1
[2,]    0   -2    3
> mat1  <-- (3)
     [,1] [,2] [,3]
[1,]    3    2   -1
[2,]    0   -2    3
> mat2 <- matrix(c(3, 0, 2, -2, -1, 3), ncol = 3)  <-- (4)
> mat2  <-- (5)
     [,1] [,2] [,3]
[1,]    3    2   -1
[2,]    0   -2    3
> mat3 <- matrix(c(3, 0, 2, -2, -1, 3), nrow = 2, byrow = T)  <-- (6)
> mat3  <-- (7)
     [,1] [,2] [,3]
[1,]    3    0    2
[2,]   -2   -1    3
> mat3[2, 2]  <-- (8)
[1] -1

------

변수 mat1에 수치 3, 0, 2, -2, -1, 3을 차례대로 연결하여 (함수 c()) 행이 2개인 (nrow = 2) 행렬을 만들어 (matrix() 함수 사용) 할당하고 (1), 함수 print()를 실행하여 그 내용을 확인한다 (2). 이 경우, 변수명 (mat1)을 그냥 입력해도 내용을 확인할 수 있다 (3). 결과를 보면, 변수 mat1은 첫 행에 각 열의 순서대로 3, 2, -1, 두번째 행에 열의 순서대로 0, -2, 3의 수치가 들어 있는 (2 x 3) 행렬임을 알 수 있다. 이번에는 행의 수를 지정 (nrow = 2)하지 말고, 열의 수를 지정하는 방식으로 각 원소의 값이 동일한 행렬을 만들어 보자.

변수 mat1에 할당할 때 사용했던 nrow 대신 ncol을 사용하여 열의 갯수를 3으로 지정하여 mat1과 같은 내용의 행렬을 변수 mat2에 할당하고 (4), 그 내용을 확인한다 (5). 결과를 보면 변수 mat1과 mat2의 내용이 동일한 것으로 알 수 있다. 그런데, 입력 값의 순서와 행렬의 결과를 보면, 입력 값이 행렬에 들어가는 순서는 1행1열 [1, 1] -> 2행1열 [2, 1] -> 1행2열 [1, 2] -> 2행2열 [2, 2]...의 순으로 원소값이 정해지는 것을 볼 수 있다. 기본적으로 각 행의 열을 순서대로 먼저 채우고, 그 다음의 열을 채우는 식으로 진행된다. 이러한 규칙이 불편할 경우에는 행을 먼저 채우도록 (byrow = T) 조건을 지정할 수 있다 (6). 이렇게 하면, 입력값의 순서대로 행부터 먼저 채우는 방식으로 작동한다는 것을 알 수 있다 (7). 행렬의 각 원소에 들어 있는 값은 그 위치를 지정함으로써 알아 볼 수 있다 (8).

다음은 여러 열을 결합해 주는 함수인 cbind()와 행들을 결합해 주는 함수인 rbind()를 사용하는 예이다.

------
> mat4 <- rbind(c(3.1, 2.3, -1.2), c(1.0, -2.7, 3.3))  <-- (9)
> mat4  <-- (10)
     [,1] [,2] [,3]
[1,]  3.1  2.3 -1.2
[2,]  1.0 -2.7  3.3
> mat5 <- cbind(c(3.1, 1.0), c(2.3, -2.7), c(-1.2, 3.3))  <-- (11)
> mat5  <-- (12)
     [,1] [,2] [,3]
[1,]  3.1  2.3 -1.2
[2,]  1.0 -2.7  3.3
> print(mat4); mat5  <-- (13)
     [,1] [,2] [,3]
[1,]  3.1  2.3 -1.2
[2,]  1.0 -2.7  3.3
     [,1] [,2] [,3]
[1,]  3.1  2.3 -1.2
[2,]  1.0 -2.7  3.3
>
------

먼저, 행들을 결합하는 rbind()를 사용해 보자. 각 행별로 들어갈 수치 자료를 연결한 후, 함수 rbind()를 사용하여 변수 mat4에 할당하고 (9), 그 내용을 확인한다 (10). 유사한 방식으로 이번에는 열 결합 함수 cbind()를 사용, 각 열에 들어갈 수치 자료를 연결하여 변수 mat5에 할당하고 (11) 결과를 확인한다 (12). 각기 다른 방식으로 생성한 변수 mat4mat5의 내용이 동일한지 이들을 출력하여 살펴본다 (13). R에서도 두 개 이상의 명령을 이어서 실행하기 위해서는 ;를 사용하면 된다 (13).

이외에도, 함수 dim()을 사용하여 수치 벡터의 행과 열의 수를 결정하는 방법도 있다. 함수 dim()은 객체의 차원을 표시하거나 지정하는 역할을 한다.

------
> mat6 <- c(3, 0, 2, -2, -1, 3)  <-- (14)
> mat6  <-- (15)
[1]  3  0  2 -2 -1  3
> dim(mat6) <- c(2, 3)  <-- (16)
> mat6  <-- (17)
     [,1] [,2] [,3]
[1,]    3    2   -1
[2,]    0   -2    3
> dim(mat6)  <-- (18)
[1] 2 3
> mat6[1, 2]  <-- (19)
[1] 2
> mat7 <- c(1, 2, 3, 4)  <-- (20)
> dim(mat7)  <-- (21)
NULL
> mat7  <-- (22)
[1] 1 2 3 4
> dim(mat7) <- c(2, 2)  <-- (23)
> mat7  <-- (24)
     [,1] [,2]
[1,]    1    3
[2,]    2    4
> dim(mat7)  <-- (25)
[1] 2 2
> mat7 / -2  <-- (26)
     [,1] [,2]
[1,] -0.5 -1.5
[2,] -1.0 -2.0
> mat6 - 3  <-- (27)
     [,1] [,2] [,3]
[1,]    0   -1   -4
[2,]   -3   -5    0
>
------

이번에는 앞서 사용했던 6개의 수치 자료를 그냥 연결하여 변수 mat6에 할당하고 (14) 그 내용을 확인해 보면, 6개의 수치가 순서대로 들어 있음을 알 수 있다 (15). 이제 변수 mat6의 차원을 지정하기 위하여 함수 dim()mat6에 적용하고, 이에 대한 값으로 2행 3열 (c(2, 3))을 입력한다 (16). 그 결과, 변수 mat6은 (2 x 3) 행렬로 변경되었음을 알 수 있고 (17), 이 변수의 차원을 함수 dim()으로 확인해 보면 2(행) 3(열)의 구조임을 알 수 있다 (18). 그리고, 변수 mat6의 1행 2열에는 숫자 2가 들어 있음도 확인해 보자 (19).

이제 함수 dim()의 기능에 대해 좀더 알아 보기 위하여, 새로운 변수 mat7에 숫자 1, 2, 3, 4를 차례대로 연결하여 할당하고 (20) 그 차원을 확인하기 위해 함수 dim()을 적용하면, 변수 mat7에는 아직 차원이 설정되지 않은 상태이므로 결과로 NULL이 출력된다 (24). 여기서 mat7에 차원을 부여하는 함수 dim()을 사용하여 (2 x 2) 행렬로 만들고 확인할 수 있다 (23-24). 다시 dim()으로 mat7의 차원을 확인할 수도 있다 (25). 즉, 함수 dim()은 차원이 없는 수치 자료에 대해서는 차원을 지정하는 기능을 하지만, 이미 차원이 부여된 자료에 대해서는 그 내용을 확인하는 역할도 수행한다. 행렬에 대해서는 단일 수치 (벡터)에 대해서 나눗셈과 뺄셈 등의 사칙연산도 가능하다 (26-27).

다음 회차에는 리스트 (list) 및 데이터프레임 (data frame)에 관한 내용 알아 보면서 마무리하자.

 

----------------------------------------------------  
1. atomic vector
2. R에서 벡터의 인덱스는 1부터 시작한다.

 

 

- 고주온박사(필명)의 "초심자를 위한 생물학+정보학"은 아래 PDF 다운 받으셔서 읽는 것도 가능합니다. -
 
파일첨부 1: 54_RnG2_r.pdf (706 KB)
  추천 1
  
인쇄하기 주소복사 트위터 공유 페이스북 공유 
  
고주온(필명)
(http://bioprofiler.tistory.com)
IBM-XT시절부터 개인용 컴퓨터를 사용하였으나, 강산이 변한 지금도 어제 코딩한...
다른 연재기사 보기 전체보기 >
[초심자를 위한 생물학+정보학] R의 자료 형태와 구조 1 - 53
지난 번에 통계학 도구인 R의 기동과 간단한 작동의 예를 보았다. 앞으로 다양한 도표에 관한 내용을 풀어 가면서 R을 주로 사용하게 될 것이므로 이 도구에 대하여 기초적인 사항을...
[초심자를 위한 생물학+정보학] R과 도표 - 52
과학의 어느 분야든 연구 활동의 결과물은 그것을 보는 사람의 이해를 돕기 위하여 도표의 형태로 표현하게 된다. 많은 경우에 있어서 수치 계산과 각 실체의 연관 관계 등 통계 분석이...
[초심자를 위한 생물학+정보학] 리눅스에서 사용할 수 있는 논문 작성 도구 2 (LaTeX과 Mendeley 등) - 51
잘 아는 바와 같이 문서나 논문의 작성을 위해 사용하는 도구로 워드 프로세서 (word processor)로 불리는 문서 작성기를 사용한다. 최근에 많은 부분이 자동화되기는 했어도...
본 기사는 네티즌에 의해 작성되었거나 기관에서 작성된 보도자료로, BRIC의 입장이 아님을 밝힙니다. 또한 내용 중 개인에게 중요하다고 생각되는 부분은 사실확인을 꼭 하시기 바랍니다. [기사 오류 신고하기]
 
  댓글 1
회원작성글 tmzkdlffor  (2020-07-01 06:06)
잘 읽고 있습니다 박사님.
혹시나 언젠가 기회가 된다면 S4 object 에 대해서도 알려 주실 수 있으실지요?
시각적으로 와닿는 개념이 아니다 보니 Seurat 등을 사용할 때 이해가 힘들더군요 ^^;

감사합니다!
등록
위로가기
동향 홈  |  동향FAQ  |  동향 문의 및 제안
 |  BRIC소개  |  이용안내  |  이용약관  |  개인정보처리방침  |  이메일무단수집거부
Copyright © BRIC. All rights reserved.  |  문의 member@ibric.org
트위터 트위터    페이스북 페이스북   유튜브 유튜브    RSS서비스 RSS
머크