R좋은게 소문이 났는지? 주위에서 R을 배우는 교수님과 동료 선생님들이 늘어나는 것 같다. 나는 R을 엄청 잘 쓴다고 말은 못하지만, 어쩌다 보니 R에서 통계량 계산만 하고, Excel로 돌아가 다시 데이터를 정리해서 import하는 불필요한 일은 피할 정도가 되었다. 가끔은 사용자 함수를 만들어서 복잡한 text mining도 하고 반복작업을 줄이기도 한다. (매번 잘 되지는 않는다. 하지만 반복작업을 줄이는 코드를 만드는 것이 재미있다.)
논문 작성을 위한 데이터 정리를 노가다 또는 삽질이라고 부르는 친구들도 있지만 나는 그나마 R로 해결되는 것들이라면 코딩하는(?) 재미로 할 만 하다. 오늘부터는 이따금 R 사용법을 안내하는 글을 올려보려고 한다. 가르치는 것은 두 번 배우는 것이라 했으니 배운 것을 꼭꼭 씹어먹고 소화시키기 위함이다. (오늘만 해도 이걸 올리느라 R markdown을 배웠다. ㅎㅎ)
잘못된 정보가 있으면 댓글로 알려주시면 감사하겠습니다.
의학 논문 작성을 위한 R 기초
1. Data frame의 subsetting
1.1. Data frame과 vector
의학 연구자들이 기본적으로 사용하는 데이터는 열과 행으로 이루어진 데이터스프레드시트이다. 엑셀 등으로 작업이 된 경우도 있고 csv파일로 정리된 경우도 있는데 어쨌든 대부분은 csv파일로 변환해서 R에서 불러오게 된다.
example <- read.csv("c:/R/R_document/mtcars.csv", header = TRUE) #파일 경로는 이렇게
example <- read.csv("c:\\R\\R_document\\mtcars.csv", header = TRUE) #또는 이렇게도 가능하다.
#example <- read.csv("c:\\R\\R_document\\mtcars.csv", header = TRUE) 이렇게 쓰면 안 된다.
데이터를 R으로 불러오면 내부에서 data frame 형식으로 존재하게 된다.
class(example)
## [1] "data.frame"
하지만 data frame 형식의 데이터를 다루기 위해서는 다른 형식의 데이터셋(vector, matrix, list)에 대한 기본 지식을 갖추는 것이 좋다. 우선 vector만 이해해도 충분하다.
우선 불러온 데이터를 살펴보자. 데이터의 10행만 출력해보겠다.
head(example, 10) #10이라는 숫자를 입력하지 않으면 기본적으로 6줄을 보여준다.
## mpg cyl disp hp drat wt qsec vs am gear carb
## 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## 9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## 10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
여기서 첫번째 column만 따로 가져와보겠다. 여러가지 방법이 있다.
first_column_1 <- example$mpg #1
first_column_2 <- example["mpg"] #2
first_column_3 <- example[1] #3
세 가지 방법의 결과는 다르다. (1 ≠ 2 = 3) 결과물을 출력해보면
first_column_1
## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0
## [28] 30.4 15.8 19.7 15.0 21.4
class(first_column_1)
## [1] "numeric"
str(first_column_1) #구조를 보여준다.
## num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
첫 번째 방법은 example의 첫 column을 가져와서 (numeric) vector로 만든 것이다. Vector는 같은 형태(e.g. numeric, integer, charactor, factor, logical)의 데이터를 여러개 묶은 형태이다.
class(first_column_2)
## [1] "data.frame"
str(first_column_2)
## 'data.frame': 32 obs. of 1 variable:
## $ mpg: num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
head(first_column_2, 3)
## mpg
## 1 21.0
## 2 21.0
## 3 22.8
두 번째 방법은 data frame의 형태가 유지되어있다. Data frame이라 세로로 긴 여러행이라서 3줄만 출력하였다.
Vector의 특성에서 중요한 것은 logical vector로 부분집합을 가져올 수 있다는 것이다.
vector_1 <- c(15, 16, 17)
#c()는 벡터를 만드는 함수이다. 문자열 벡터는 따옴표 필요 c("a", "b")
vector_1[c(TRUE, FALSE, TRUE)] #1, 3번째 원소만 선택
## [1] 15 17
logical_1 <- c(TRUE, FALSE, TRUE)
vector_1[logical_1] #이번엔 미리 만들어놓은 logical vector를 넣어서 선택해봤다.
## [1] 15 17
반대로 vector에 조건을 걸어 logical vector를 만들어낼 수 있는데 만들어낸 logical vector를 일종의 필터로 이용하여 다시 해당 조건의 원소를 추출할 수 있다.
logical_2 <- vector_1 > 15 #15보다 큰 원소는 TRUE로 그렇지 않으면 FALSE로 반환
logical_2
## [1] FALSE TRUE TRUE
vector_1[logical_2] #logical vector를 이용해서 해당 원소 추출
## [1] 16 17
vector_1[vector_1 > 15] #앞에서 한 것을 한 번에 쓰면
## [1] 16 17
1.2. Data frame의 subsetting - 기본
앞에서 불러온 data frame인 example의 특정 행과 열을 선택해보자.
example[1, 3] #1행 3열
## [1] 160
example[4, "disp"] #4행 disp열
## [1] 258
example[4, ] #4행
## mpg cyl disp hp drat wt qsec vs am gear carb
## 4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
example[, "disp"] #disp열 = example$disp와 같다.
## [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8 275.8 275.8 472.0 460.0 440.0 78.7 75.7 71.1 120.1 318.0 304.0
## [24] 350.0 400.0 79.0 120.3 95.1 351.0 145.0 301.0 121.0
example[5, c("mpg", "disp")] #5행, mpg와 disp열
## mpg disp
## 5 18.7 360
example[5, c(1, 3)] #5행, 1과 3열
## mpg disp
## 5 18.7 360
example[c(1:3), c(1:3)] #1-3행, 1-3열
## mpg cyl disp
## 1 21.0 6 160
## 2 21.0 6 160
## 3 22.8 4 108
example[c(TRUE, FALSE), c(1:3)]
## mpg cyl disp
## 1 21.0 6 160.0
## 3 22.8 4 108.0
## 5 18.7 8 360.0
## 7 14.3 8 360.0
## 9 22.8 4 140.8
## 11 17.8 6 167.6
## 13 17.3 8 275.8
## 15 10.4 8 472.0
## 17 14.7 8 440.0
## 19 30.4 4 75.7
## 21 21.5 4 120.1
## 23 15.2 8 304.0
## 25 19.2 8 400.0
## 27 26.0 4 120.3
## 29 15.8 8 351.0
## 31 15.0 8 301.0
#c(TRUE, FALSE)는 전체 행 개수보다 적어서 이 두 값이 반복해서 대입되며 홀수행만 선택된다.
#행 개수에 맞는 logical vector를 넣어줄 수도 있다. (아래 응용편으로 이어지는 내용임.)
1.3. Data frame의 subsetting - 응용
앞에서 배운 것을 응용해보자. 특정 값을 기준으로 subsetting을 해보자. dataframe[logical vector, ]를 하게 되면 TRUE에 해당하는 행만 출력된다. logical vector를 만드는 법은 위에서 설명하였다.
selected <- example[example$mpg < 20, ] #mpg < 20인 행만 선택
head(selected)
## mpg cyl disp hp drat wt qsec vs am gear carb
## 5 18.7 8 360.0 175 3.15 3.44 17.02 0 0 3 2
## 6 18.1 6 225.0 105 2.76 3.46 20.22 1 0 3 1
## 7 14.3 8 360.0 245 3.21 3.57 15.84 0 0 3 4
## 10 19.2 6 167.6 123 3.92 3.44 18.30 1 0 4 4
## 11 17.8 6 167.6 123 3.92 3.44 18.90 1 0 4 4
## 12 16.4 8 275.8 180 3.07 4.07 17.40 0 0 3 3
selected <- example[example$gear == 3, ] #gear = 3인 행만 선택
head(selected)
## mpg cyl disp hp drat wt qsec vs am gear carb
## 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## 12 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## 13 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
selected <- example[example$gear != 3, ] #gear = 3인 행만 제외
selected[order(selected$carb),] #carb값을 기준으로 오름차순으로 정렬
## mpg cyl disp hp drat wt qsec vs am gear carb
## 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## 18 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## 20 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## 26 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## 9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## 19 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## 27 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## 28 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## 32 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
## 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## 10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## 11 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## 29 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## 30 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## 31 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
selected[order(-selected$carb),] #carb값을 기준으로 내림차순 정렬
## mpg cyl disp hp drat wt qsec vs am gear carb
## 31 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## 30 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## 10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## 11 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## 29 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## 9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## 19 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## 27 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## 28 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## 32 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
## 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## 18 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## 20 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## 26 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
이상의 기능들을 이용하면 기본적인 데이터 subsetting은 가능하다고 본다.
Comments
Post a Comment