Lovetoken

저는 개발 취향을 가진 데이터 분석가 Jr. 입니다.

Navigation
 » Home
 » About Me
 » Github

R에서 data.frame 과 data.table 에 대해 join 작업을 이용한 벤치마킹

27 Jun 2016 » R



R에서 최근에 많이 하는 작업이 있다.
바로 data.frame 기반으로 데이터를 인아웃풋 한 코드들을 모두 data.table 로 코드 스위칭하는 작업이다.
data.table 의 빠른처리속도는 이전부터 명성이 자자했지만 게으름으로 인해 고집스럽게 쓰지 않았었다.
하지만 인내심의 한계에 다다르고 빠른 속도를 직접 체감하고 나서 뒤늦게 도입하기 시작한 것 같다.

구글링을 통해서도 다양한 data.table 의 showcase 들이 있고, 퍼포먼스를 확인할 수 있는 예제코드를 구하기 쉽다.
나도 그러한 예제코드를 만들어 보았고 공유해 보고자 한다.
나는 data.frame 과 data.table 에 대해서 병합작업을 이용해 벤치마킹 하는 코드 프로그램을 아래와 같이 작성해 보았다.

library(data.table)
library(dplyr)
library(rbenchmark)

N=10^6

df <- data.frame(
    ID = seq(N),
    group = LETTERS %>% sample(N, T),
    Var1 = rnorm(N, 10, 2^2),
    Var2 = rpois(N, 5)
    ) %>% tbl_df
df2 <- data.frame(
    ID = seq(N) %>% rev,
    Var3 = rnorm(N, -10, 2^2)
    ) %>% sample_n(N*.9) %>% tbl_df

dt <- data.table(df); setkey(dt, ID)
dt2 <- data.table(df2); setkey(dt2, ID)

benchmark(
    join_res_df <- left_join(df, df2),
    join_res_dt <- left_join(dt, dt2), replications = 20
)

위의 코드를 간략히 설명해 보면



예제로 사용할 data.frame, data.table 객체 만들기

library(data.table)
library(dplyr)
library(rbenchmark)

N=10^6

df <- data.frame(
    ID = seq(N),
    group = LETTERS %>% sample(N, T),
    Var1 = rnorm(N, 10, 2^2),
    Var2 = rpois(N, 5)
    ) %>% tbl_df
df2 <- data.frame(
    ID = seq(N) %>% rev,
    Var3 = rnorm(N, -10, 2^2)
    ) %>% sample_n(N*.9) %>% tbl_df

dt <- data.table(df); setkey(dt, ID)
dt2 <- data.table(df2); setkey(dt2, ID)

1,000,000 개의 데이터셋과 이중에서 90% 인 900,000 개의 새로운 변수를 가진 데이터셋을 서로 join 하기 위해 (의미가 별로 없는) 데이터프레임 df, df2 객체를 만드는 코드이다.
join 으로 붙여져야 하는 대상은 “Var3” 으로 명칭된 변수  − 10 을 평균으로 하는 정규분포 난수이다.

이후 class 만 data.table 로 바꾼 dt, dt2 동일내용의 객체를 준비했다.
data.table 에선 key variable 를 사전에 지정할 수 있는데 바로 data.table 의 setkey() 함수를 통해 가능하다.
key 변수는 공통의 “ID” 변수를 선택하였다.
setkey() 함수를 이용한 이와같은 key 변수 지정은 추후 join 작업의 편의성을 증대시켜주고 처리속도의 작은 개선을 기대할 수 있게 해준다.
무엇보다 현업시 key variable 에 대한 상기를 지속적으로 해야하는 상황에서 이렇게 명시해 줄 수 있는 도구가 있는것은 긍정적이라고 할 수 있다.
key variable 세팅이 제대로 되었는지가 궁금하다면 tables() 함수를 통해 눈으로 확인 할 수 있다.

tables()
##      NAME      NROW NCOL MB COLS               KEY
## [1,] dt   1,000,000    4 20 ID,group,Var1,Var2 ID 
## [2,] dt2    900,000    2 11 ID,Var3            ID 
## Total: 31MB

출력결과의 맨 우측 Key 항목에 “ID” 가 있는것을 보아 제대로 세팅이 된 것을 볼 수 있다.1



Join

본격적으로 병합(Join)을 시작한다.
join 방법은 무난한 left join 을 실시하기 위해 dplyr package 에 있는 left_join() 함수를 이용 했다.

data.frame 에 대한 join 과
data.table 에 대한 join 수행시간을 간편하게 측정하기위해 rbenchmark package 의 benchmark() 함수를 이용했다.

benchmark(
    join_res_df <- left_join(df, df2, by="ID"),
    join_res_dt <- left_join(dt, dt2, by="ID"), replications = 20
)
##                                           test replications elapsed
## 1 join_res_df <- left_join(df, df2, by = "ID")           20  19.608
## 2 join_res_dt <- left_join(dt, dt2, by = "ID")           20   7.667
##   relative user.self sys.self user.child sys.child
## 1    2.557    18.395    1.114          0         0
## 2    1.000     6.782    0.848          0         0

위의 코드는 join_res_df <- left_join(df, df2, by="ID")join_res_dt <- left_join(dt, dt2, by="ID") 코드를 의도적으로 20번 반복 수행해 걸린 시간을 측정해주게 된다.
현 예제에 대한 시간측정결과 elapsed 항목을 볼 때 data.table 에 대한 join 작업의 수행속도가 data.frame 보다 약 10배 빠른 것을 볼 수 있다!


  1. setkey() 함수를 통해 key variable 를 세팅하지 않았던 단계에 tables() 를 실행시키면 Key 항목은 빈칸이었을 것 이다.↩︎