data.table fillna
데이터 테이블에서 결측값 채우기
데이터 테이블의 문법은 데이터 프레임의 그것과 조금 달라서 활용하는데 애를 먹을 수 있다.
하지만 데이터 테이블은 데이터 프레임으로 할 수 있는 거의 모든 것을 지원하고 있으며, 거기에 제자리 연산(in-place operation)을 추가한다고 생각하면 쉽다.
제자리 연산(in-place operation)이란 컬럼을 수정할 때 새로운 데이터 테이브을 생성하는 것이 아니라 바로 그 자리에서 수정하는 것을 의미한다. 다음의 예를 보자.
library(data.table)
dt0 = data.table(dt = c(as.Date(c('2021-01-01', NA, '2030-03-01')), Sys.Date()),
name = c('K', NA, 'P', 'J'),
ctr = c(NA, 1,3,2))
dtA <- copy(dt0) # dtA <- dt0 과 결과가 다름을 유의하자.
dtB <- copy(dt0)
dt0
## dt name ctr ## 1: 2021-01-01 K NA ## 2: <NA> <NA> 1 ## 3: 2030-03-01 P 3 ## 4: 2021-02-15 J 2
- 비교 : 제자리 연산
dtA[, name:=ifelse(is.na(name), 'unknown', name)]
dtA
## dt name ctr ## 1: 2021-01-01 K NA ## 2: <NA> unknown 1 ## 3: 2030-03-01 P 3 ## 4: 2021-02-15 J 2
- 비교 : 새로운 데이터테이블 생성
dtB[, .(name=ifelse(is.na(name), 'unknown', name))]
## name ## 1: K ## 2: unknown ## 3: P ## 4: J
dtB[, .(dt, name=ifelse(is.na(name), 'unknown', name), ctr)]
## dt name ctr ## 1: 2021-01-01 K NA ## 2: <NA> unknown 1 ## 3: 2030-03-01 P 3 ## 4: 2021-02-15 J 2
colns = names(dtB)
colns = colns[colns!='name']
dtB[, c(.SD, .(name = ifelse(is.na(name), 'unknown', name))), .SDcols=colns]
## dt ctr name ## 1: 2021-01-01 NA K ## 2: <NA> 1 unknown ## 3: 2030-03-01 3 P ## 4: 2021-02-15 2 J
결측치 제거
우선 결측치를 제거하는 함수를 만들어 두는게 좋겠다.
fillna = function(x) {
if (inherits(x, "Date"))
x[is.na(x)] = as.Date('0000-01-01')
else if (inherits(x, 'character')) {
x[is.na(x)] = ''
} else {
x[is.na(x)] = 0
}
x}
위의 함수 fillna
는 벡터 x
가 Date
클래스일 때는 NA를 0000-01-01
로, 문자열일 때에는 NA를 ''
로, 그 밖에는 0
으로 채운다.
이렇게 NA를 채운 새로운 데이터 테이블은 다음과 같이…
dtA[, lapply(.SD, fillna)]
## dt name ctr ## 1: 2021-01-01 K 0 ## 2: 0000-01-01 unknown 1 ## 3: 2030-03-01 P 3 ## 4: 2021-02-15 J 2
기존의 데이터 테이블에 덮어 씌운다면… (메모리가 부족할 때 유용하다)
coln = names(dtA)
dtA[, `:=`(c(coln), lapply(.SD, fillna)), .SDcols = coln]
만약 결측치를 제거하려는 수치형 컬럼의 이름을 이미 알고 있다면,
coln = 'ctr'
dtB[, lapply(.SD, fillna), .SDcols = coln]
## ctr ## 1: 0 ## 2: 1 ## 3: 3 ## 4: 2
cbind(dtB[, !..coln], dtB[, lapply(.SD, fillna), .SDcols = coln])
## dt name ctr ## 1: 2021-01-01 K 0 ## 2: <NA> <NA> 1 ## 3: 2030-03-01 P 3 ## 4: 2021-02-15 J 2
# coln제외한 데이터 테이블 = dtB[, !..coln]
# coln에만 fillna 함수 적용한 결과 dtB[, lapply(.SD, fillna), .SDcols = coln]
오, 이 괴랄한 문법이여!
결론
R로 하는 빅 데이터 분석(개정판)에는 데이터 프레임으로 할 수 있는 여러 작업을 손쉽게 데이터테이블로 수행할 수 있도록 관련 내용들을 체계적으로 정리해 놓았다.
데이터 테이블의 문법을 배우지 않고 데이터 테이블을 사용하고자 한다면 dtplyr
이란 패키지가 도움이 될 것이다.
하지만 dtplyr은 data.table보다 조금 느리다고 한다.
Leave a comment