지난 포스팅에서는 R data.table 이 키(Key)와 빠른 이진 탐색(fast binary search) 기반의 부분집합 선택을 하는 원리, 함수 사용방법에 대하여 소개하였습니다.
지난 포스팅이 R data.table에 Key 를 활용하여 행(row, i)에 대해서만 subset 하는 방법에 대해 한정해서 소개했습니다. 반면, 이번 포스팅은 지난 포스팅을 이어받아 더 확장하여, DT[i, j, by][order()] 기본 구문에서 행뿐만 아니라 칼럼(column, j), 그룹(group, by) 별 연산, 정렬, 키 재설정 하는 방법까지 소개하겠습니다.
1. 키 설정 후, 특정 키(Key) 값에 행을 한정해 칼럼 j 가져오기 (select in j)
2. 체인연산으로 정렬하기 (chaining)
3. 특정 키(Key) 값에 행을 한정해 칼럼 j 에 연산 수행하기 (compute or do in j)
4. 칼럼 j에 := 를 사용하여 키의 부분집합에 할당하기(sub-assign by reference)
5. by 를 사용하여 그룹별 집계하기 (aggregation using by)
1. 키 설정 후, 특정 키(Key) 값에 행을 한정해 칼럼 j 가져오기 (select in j) |
먼저 Cars93 data.frame에서 칼럼 몇 개만 가져와서 예제로 사용할 간단할 data.table DT 를 만들어보겠습니다. 그리고 DT의 Type, DriveTrain 칼럼에 대해 키를 설정(setkey) 하겠습니다.
이렇게 키를 설정하면 data.table DT는 키인 Type, DriveTrain을 참조으로 오름차순으로 재정렬됩니다.
library(data.table) > key(DT) > > # reordered by Keys > head(DT, 10) |
이제 위에서 설정한 (a) Type, DriveTrain 키(Key) 값이 Type == "Compact" & DriveTrain == "Front" 인 행을 선별하고 (subset row i), (b) 이들 부분집합에 대해서 칼럼(column j) Model, MPG.highway 를 선택해서 가져오겠습니다.
이렇게 data.table의 특정 키 값의 행만 가져오기(subset) 할 때 Key를 설정하면서 재정렬 된 상태이고 빠른 이진 탐색(fast binary search)로 키 값 데이터를 선별하므로 매우 빠르게 수행됩니다. 그리고 이렇게 선별한 subset에 한정해서 칼럼 j를 선택해서 가져오므로 메모리 효율적이고 빠릅니다.
> # Select in j Model MPG.highway |
data.table |
dplyr |
library(data.table) setkey(DT, Type, DriveTrain) DT[.("Compact", "Front"), .(Model, MPG.highway)] |
library(dplyr) DT %>% |
위의 코드에서 뒤의 칼럼 j 를 선택할 때 c("Model", "MPG.highway") 처럼 큰 따옴표(" ")를 대신 사용할 수도 있으며, 프로그래밍을 할 때 유용하게 쓸 수 있습니다.
# or alternatively
|
2. 체인연산으로 결과 정렬하기 (chaining) |
위의 (1) 번 결과를 MPG.highway 를 기준으로 오름차순 정렬하려면 Chaining 으로 [order(MPG.highway)] 를 뒤에 이어서 써주면 됩니다.
> # Chaining |
위의 (1)번 결과를 MPG.highway를 기준으로 내림차순(in decreasing order)으로 정렬을 하고 싶으면 마이너스 부호('-') 를 같이 써주어서 Chaining으로 [order(-MPG.highway)] 을 이어서 써주면 됩니다.
> # in descending order |
3. 특정 키(Key) 값에 행을 한정해 칼럼 j 에 연산 수행하기 (compute or do in j) |
(1)에서 설정한 키의 특정값인 Type == "Compact" & DriveTrain == "Front" 인 행을 선별하여, 이들 subset에 대해서만 MPG.highway 칼럼 j의 최대값(max), 평균(mean), 중앙값(median), 최소값(min), 1/4분위수(Q1), 3/4분위수(Q3)를 구해보겠습니다.
이때 요약통계량 연산을 하는데 사용하는 함수는 base R 함수의 max(), mean(), median(), min(), quantile() 과 동일하되, 속도는 base R 보다 data.table이 훨씬 빠릅니다!
> # Compute or do in j
|
4. 칼럼 j에 := 를 사용하여 키의 부분집합에 할당하기(sub-assign by reference) |
이번에는 Type을 키로 설정하고, 키의 값이 Type == "Large" 이면 ':=' 특수부호를 사용하여 Type == "Big" 의 다른 값으로 재할당(sub-assign by reference)해보겠습니다.
이러한 부분집합 재할당 때도 data.frame 대비 data.table이 훨씬 더 빠르게 수행이 됩니다.
> # sub-assign by reference using := in j > > DT[.("Large"), Type := "Big"] > > DT[, .N, by=Type] |
다만, 키의 특정 값을 재할당하고 나면 애초 키를 설정할 때 재정렬(reorder) 되었던 것이 이제 더이상 유효하지 않으므로 키가 해제됩니다.(Key 가 NULL로 설정됨)
> key(DT) # the key is removed by setting to NULL
|
5. by 를 사용하여 그룹별 집계하기 (aggregation using by) |
다시 data.table DT에 차종(Type)을 키로 설정한 후에, 동력전달장치(DriveTrain) 그룹별로 고속도로연비(MPG.highway) 의 최대값(max)을 집계해보겠습니다. 집계된 칼럼은 mpg_max 라는 이름을 부여하겠습니다.
이때 그룹별 집계의 결과값은 keyby 의 기준인 동력전달장치(DriveTrain)을 기준으로 정렬됩니다.
> # Aggregation using by |
그리고, 그룹별 집계의 결과는 keyby 칼럼인 동력전달장치(DriveTrain)을 키로 설정됩니다.
> key(agg) # key is changed to DriveTrain.
|
만약 그룹별 집계를 할 때 그룹 연산 부호에 'keyby' 대신에 'by'를 사용하면 나중에 setkey(agg_2, DriveTrain) 처럼 별도의 키를 설정하는 코드를 추가해주어야 키가 설정이 되고 키를 기준으로 재정렬이 됩니다. (조금 번거롭습니다.)
> agg_2 <- DT["Compact", > # set the column 'DriveTrain' as a Key using setkey() explicitely
|
[Reference]
* data.table vignette: https://cran.r-project.org/web/packages/data.table/vignettes/datatable-keys-fast-subset.html
다음번 포스팅에서는 R data.table에서 mult, nomatch 매개변수를 사용하여 Key값에 매칭되는 행 중에서 모든 행, 첫번째 행, 마지막 행, 값이 존재하는 행만 가져오는 방법을 소개하겠습니다.
이번 포스팅이 많은 도움이 되었기를 바랍니다.
행복한 데이터 과학자 되세요!