이번 포스팅에서는 여러개의 데이터 프레임을 한꺼번에 하나의 데이터프레임으로 묶는 몇가지 방법을 알아보고, 성능 측면을 비교해보겠습니다.

 

이번 포스팅은 andrew 님이 r-bloggers.com 에 썼던을 그대로 가져다가 번역을 한 내용입니다. 

 

[ Source ] Concatenating a list of data frames , June 6, 2014, By andrew

 

결론 먼저 말씀드리면, data.table package의 rbindlist(data) 함수가 속도 면에서 월등히 빠르네요.

 

 

 

[ R로 여러개의 데이터프레임을 한꺼번에 하나의 데이터프레임으로 묶기 ]

 

 

 

 

0) 문제 (The problem)

 

아래처럼 3개의 칼럼으로 구성된 100,000 개의 자잘한 데이터 프레임을 한개의 커다란 데이터 프레임으로 합치는 것이 풀어야 할 문제, 미션입니다.

 

data = list() 로 해서 전체 데이터 프레임들을 data라는 리스트로 만들어서 아래 각 방법별 예제에 사용하였습니다.

 

> ###########################################
> ## Concatenating a list of data frames
> ## do.call(rbind, data)
> ## ldply(data, rbind)
> ## rbind.fill(data)
> ## rbindlist(data) ** winner! **
> ###########################################
> 
> ## The Problem
> 
> data = list()
> 
> N = 100000
> 
> for (n in 1:N) {
+   data[[n]] = data.frame(index = n, 
+                          char = sample(letters, 1), 
+                          z = runif(1))
+ }
> 
> data[[1]]
  index char         z
1     1    j 0.2300154

 

 

 

 

1) The navie solution : do.call(rbind, data)

 

가장 쉽게 생각할 수 있는 방법으로 base package에 포함되어 있는 rbind() 함수를 do.call 함수로 계속 호출해서 여러개의 데이터 프레임을 위/아래로 합치는 방법입니다. 

 

이거 한번 돌리니 정말 시간 오래 걸리네요.  @@~  낮잠 잠깐 자고 와도 될 정도로요.

 

 

> ## (1) The Naive Solution
> head(do.call(rbind, data))
  index char          z
1     1    j 0.23001541
2     2    f 0.63555284
3     3    d 0.65774397
4     4    y 0.46550511
5     5    b 0.02688307
6     6    u 0.19057217

 

 

 

 

2-1) plyr package : ldply(data, rbind)

 

두번째 방법은 plyr package의 ldply(data, rbind) 함수를 사용하는 방법입니다.

 

> ## (2) Alternative Solutions #1 and #2
> ## (2-1) plyr package : ldply(data, rbind)
> install.packages("plyr")
> library(plyr)
> head(ldply(data, rbind))
  index char          z
1     1    j 0.23001541
2     2    f 0.63555284
3     3    d 0.65774397
4     4    y 0.46550511
5     5    b 0.02688307
6     6    u 0.19057217

 

 

 

 

 

2-2) plyr package : rbind.fill(data)

 

세번째 방법은 plyr package의 rbind.fill(data) 함수를 사용하는 방법입니다.  결과는 앞의 두 방법과 동일함을 알 수 있습니다.

 

> ## (2-2) plyr package : rbind.fill(data)
> library(plyr)
> head(rbind.fill(data))
  index char          z
1     1    j 0.23001541
2     2    f 0.63555284
3     3    d 0.65774397
4     4    y 0.46550511
5     5    b 0.02688307
6     6    u 0.19057217

 

 

 

 

 

3) data.table package : rbindlist(data)

 

마지막 방법은 data.table package의 rbindlist(data) 함수를 사용하는 방법입니다.

 

> ## (3) Alternative Solution 
> ## data.table package : rbindlist(data)
> install.packages("data.table")
> library(data.table)
> head(rbindlist(data))
   index char          z
1:     1    j 0.23001541
2:     2    f 0.63555284
3:     3    d 0.65774397
4:     4    y 0.46550511
5:     5    b 0.02688307
6:     6    u 0.19057217

 

 

 

 

4) 벤치마킹 테스트 (bechmarking test)

 

 

> ## Benchmarking (performance comparison)
> install.packages("rbenchmark")
> library(rbenchmark)
> benchmark(do.call(rbind, data),
+           ldply(data, rbind), 
+           rbind.fill(data), 
+           rbindlist(data))

                  test replications  elapsed relative user.self sys.self user.child sys.child

1 do.call(rbind, data)          100 11387.82  668.692  11384.15     1.54         NA        NA
2   ldply(data, rbind)          100  4983.72  292.644   4982.90     0.52         NA        NA
3     rbind.fill(data)          100  1480.46   86.932   1480.23     0.17         NA        NA
4      rbindlist(data)          100    17.03    1.000     16.86     0.17         NA        NA

 

 

패키지/함수별 성능 비교를 해본 결과 data.table 패키지의 rbindlist(data) 함수가 월등히 빠르다는 것을 알 수 있습니다.  위의 벤치마킹 결과를 보면, 속도가 가장 빨랐던 rbindlist(data)를 1로 놨을 때, 상대적인 속도(relative 칼럼)를 보면 rbind.fill(data)가 86.932로서 rbindlist(data)보다 86배 더 오래걸리고, ldply(data, rbind)가 292.644로서 rbindlist(data)보다 292배 더 오래걸린다는 뜻입니다.  do.call(rbind, data)는 rbindlist(data) 보다 상대적으로 668.692배 더 시간이 걸리는 것으로 나오네요.

 

rbindlist(data)가 훨등히 속도가 빠른 이유는 두가지인데요,

 

(1) rbind() 함수가 각 데이터 프레임의 칼럼 이름을 확인하고, 칼럼 이름이 다를 경우 재정렬해서 합치는데 반해, data.table 패키지의 rbindlist() 함수는 각 데이터 프레임의 칼럼 이름을 확인하지 않고 단지 위치(position)를 기준으로 그냥 합쳐버리기 때문이며,

(따라서, rbindlist() 함수를 사용하려면 각 데이터 프레임의 칼럼 위치가 서로 동일해야 함)

 

(2) rbind() 함수는 R code로 작성된 반면에, data.table 패키지의 rbindlist() 는 C 언어로 코딩이 되어있기 때문입니다.

 

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

 

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

 

 

Posted by R Friend R_Friend