'data.table 그룹별 요약통계량'에 해당되는 글 1건

  1. 2020.10.02 [R data.table] data.table의 기본 구문 DT[i, j, by][order] 과 Base R, dplyr, SQL 구문의 비교

지난번 포스팅에서는 R data.table이 무엇이고 또 왜 좋은지, 그리고 data.table을 생성하는 4가지 방법을 소개하였습니다. 


이번 포스팅에서는 R data.table 의 일반 구문(general syntax of data.table)을 Base R, dplyr, SQL 구문과 비교해가면서 설명해보겠습니다. 그러면 상대적으로 data.table 이 매우 간결하고 일관성있으며, 또 SQL 구문과도 비슷한 면이 있어서 익히기 쉽겠구나 하는 인상을 받으실 겁니다. 




R data.table 은 DT[i, j, by][order] 의 기본 구문 형태를 따릅니다. 여기서 DT 는 data.table을 말하여, i, j, by, order 는 

  • i : 데이터 조작/집계의 대상이 되는 행(rows)이 무엇인지를 지정합니다. Base R의 subset() 또는 which() 함수dplyr의 filter() 함수, SQL의 where 구문과 같은 역할을 합니다. 

  • j : 일반적으로 조작/집계의 실행이 일어나는 열(columns)과 실행(action, function)을 말합니다. 기존 열을 수정할 수도 있고, 새로운 조작/집계를 통해 새로운 열을 만들 수도 있습니다. 어떤 R 패키지의 어떤 함수 표현도 모두 사용할 수 있습니다. Base R, dplyr 의 function(column_name), 또는 SQL의 select 구문과 같은 역할을 합니다. 

  • by : j에서 지정한 열(columns)과 실행(action, function)을 그룹 별로(by group) 수행하라고 지정해줍니다. Base R의 tapply()나 by() 함수, dplyr의 group_by() 함수, SQL 의 group by 구문과 같은 역할을 합니다. 

  • order : 결과 테이블을 기준 변수에 따라 오름차순(ascending) 또는 내림차순(descending)으로 정렬할 때 사용합니다. Base R의 sort() 또는 order() 함수, dplyr의 arrange() 함수, SQL의 order by 구문과 같은 역할을 합니다. 


아래에는 소속 그룹을 나타내는 'g' 변수와 정수 값을 가지는 'x' 변수로 구성된 'data'라는 이름의 data.frame, data.table에서, 'x' 가 8 이하인 관측치를 대상으로, 그룹 'g' 별로 'x'의 합을 구한 후에 그룹 'g'를 기준으로 내림차순으로 그 결과를 제시하라는 예제입니다. 


Base R, dplyr, data.table, 그리고 SQL 을 각각 비교해보겠습니다. 


먼저, 예제로 사용할 간단한 data.frame 과 data.table 을 만들어보겠습니다. 변수 'g'는 (그룹 "a" 5개, 그룹 "b" 5개)의 관측치로 이루어져있으며, 변수 'x'는 1~10 까지 순차적인 정수로 이루어져 있습니다.  



# loading packages

library(data.table)

library(dplyr)


# creating data.frame with 2 variables, 10 observations

> data <- data.frame(g = c(rep('a', 5), rep('b', 5)), x = 1:10)

> data

   g  x

1  a  1

2  a  2

3  a  3

4  a  4

5  a  5

6  b  6

7  b  7

8  b  8

9  b  9

10 b 10

>

>

>

# converting data.frame to data.table

> data_dt <- as.data.table(data)

> str(data_dt)

Classes 'data.table' and 'data.frame': 10 obs. of  2 variables:

 $ g: Factor w/ 2 levels "a","b": 1 1 1 1 1 2 2 2 2 2

 $ x: int  1 2 3 4 5 6 7 8 9 10

 - attr(*, ".internal.selfref")=<externalptr> 




이제 아래 과업(task)을 Base R, dplyr, data.table, SQL 로 각각 수행해보겠습니다. 


# ===== 과업 (Task) =====

'data' 라는 데이터셋에서 

'x'가 8 이하인 관측치를 대상으로 

'x'의 합을 구하되

그룹 변수 g 별로 (그룹 'a', 그룹 'b') 구분하여 구하여 

결과를 그룹 변수 g의 내림차순으로 정렬(그룹 'b' 먼저, 그룹 'a' 나중에) 하시오. 


 Base R

dplyr 

data.table 

data2 <- subset(data, 

                subset = (x <= 8))


sort(tapply(data2$x, 

            data2$g, 

            sum), 

     decreasing=TRUE)

data %>% 

  filter(x <= 8) %>% 

  group_by(g) %>% 

  summarise(sum(x)) %>% 

  arrange(desc(g))

data_dt[x<=8, sum(x), by=g][

  order(-g)]

# Out

 b  a 

21 15

# Out

# A tibble: 2 x 2

  g     `sum(x)`

  <fct>    <int>

1 b           21

2 a           15 

# Out

   g V1

1: b 21

2: a 15 



Base R 은 data2$x, data2$g 처럼 각 칼럼 앞에 접두사로 'data2$' 가 필요했는데요, data.table은 각 칼럼별로 접두사 'DT$' 가 필요없습니다. DT[ ] 안에 각 변수 이름을 그냥 써주면 DT의 변수라고 인식을 합니다. 


Base R의 경우 x 가 8 이하인 관측치만 먼저 subset()을 하고 나서, 이후 tapply()로 그룹별로 x에 대해서 sum을 하고, sort()로 내림차순 정렬하는 식으로 하다보니 코드가 길고 복잡합니다. 반면에 data.table의 경우 DT[i, j, by][order] 구문 형식에 따라 i 부분에서 x<=8 로 조건을 만족하는 관측치만 가져온 후, j 부분에서 sum(x) 로 합계를 구하되, by 부분에서 by=g 로 그룹별로 수행하라고 설정하고, [order(-g)] 를 뒤에 설정해주어서 내림차순으로 제시하라고 하였습니다. Base R 대비 무척 간결하고 직관적입니다! 


dplyr 도 Base R 보다는 간결하기는 합니다만, data.table이 조금 더 간결합니다. 


만약 SQL 구문에 이미 익숙한 분이라면 data.table 의 구문이 좀더 수월하게 다가올 수도 있겠습니다. 아래 표의 왼쪽 칸에 SQL 구문으로 똑같은 과업을 수행했을 때의 query 인데요, 오른쪽의 data.table 구문과 비교해보면 어떠신가요? 좀 비슷하지요?!


 SQL

data.table 

SELECT 

g, 

SUM(x) AS x_sum

FROM data_dt

WHERE x <= 8

GROUP BY g 

ORDER BY g DESC;

data_dt[x<=8, 

        sum(x), 

        by=g][

          order(-g)]



이번 포스팅에서는 data.table을 Base R, dplyr, SQL과 비교해보면서 data.table의 구문이 얼마나 간결하고 깜끔한지에 대한 이해를 도모했다면, 다음 포스팅에서는 data.table에 대해서만 DT[i, j, by][order] 기본 구문의 i, j, by, order 별로 좀더 다양한 사용방법에 대해서 한번 더 소개하겠습니다. 


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. 



728x90
반응형
Posted by Rfriend
,