R 은 통계 분야에서 (특히 data science 쪽) 대세라고 할 수 있지요. 몇년 전부터 R을 익혀 데이터 분석에 이용하고 있는데, 많은 장점이 있으나 가끔 전혀 직관적이지 않는 결과를 내던지는 경우가 있어 멘붕했던 적이 여러번 있었습니다. 그 직관이란 것이 지극히 인간적인 것이고 사실은 R 이라는 프로그래밍 언어를 제대로 이해 못한 때문에 생기는 일들이지만, SAS나 Stata 와 같은 통계 패키지들을 다루면서는 겪지 않았던 괴상한 오류에 시달리는 것이 썩 기분 좋지는 않은 일이지요. 그 중 대표적인 것 중 하나가 NA 관련입니다. missing data 를 R 이 다루는 방법이 무척 엄격하달까요, 이걸 이해 못하면 정말 괴이한 에러에 머리를 쥐어 뜯게 됩니다.
다음과 같은 예를 보시지요. x2 컬럼에 NA 가 박혀 있습니다.
> df <- data.frame(no = 1:5, x1 = c(1, 0, 0, 1, 1), x2 = c(0, NA, NA, 1, 0)) > df no x1 x2 1 1 1 0 2 2 0 NA 3 3 0 NA 4 4 1 1 5 5 1 0 > df[df$x1 == 1, ] no x1 x2 1 1 1 0 4 4 1 1 5 5 1 0 > df[df$x1 != 1, ] no x1 x2 2 2 0 NA 3 3 0 NA
자, 여기까진 멀쩡하죠. 그런데 x2 에 조건을 줘서 선택을 하는 순간 괴상망칙한 현상이 벌어집니다.
> df[df$x2 == 1, ] no x1 x2 NA NA NA NA NA.1 NA NA NA 4 4 1 1 > df[df$x2 != 1, ] no x1 x2 1 1 1 0 NA NA NA NA NA.1 NA NA NA 5 5 1 0
이건 당연히 바라던 바가 아니었겠지요? 그냥 x2 가 1일 때, 또는 1이 아닐 때를 골라주면 될 걸, 왜 이런 어이없는 일이 벌어질까요?
> df$x2 == 1 [1] false NA NA true false
이걸 보시면 이해가 되겠죠. NA 는 같은 지 다른지 비교가 안됩니다. 비교를 하려고 하면 결과는 그냥 NA. 그래서 행 전체가 NA 가 되버리는 참사가 벌어지죠.
이런 일이 안 벌어지려면? 이런 방법들이 있습니다.
> df[which(df$x2 == 1), ] no x1 x2 4 4 1 1 > df[which(df$x2 != 1), ] no x1 x2 1 1 1 0 5 5 1 0
만약 ‘x2 가 1 이 아닌 경우’에 NA 를 포함시켜 주고 싶다면, 번거롭지만 다음과 같이 해야 합니다.
> df[df$x2 != 1 | is.na(df$x2), ] no x1 x2 1 1 1 0 2 2 0 NA 3 3 0 NA 5 5 1 0
코드가 무척 지저분해 보이는데… 다른 해결 방법은? 물론 있죠. 그것도 아주 많이… R 인데!
## subset 함수 이용 > subset(df, x2 == 1) no x1 x2 4 4 1 1 > subset(df, x2 != 1) no x1 x2 1 1 1 0 5 5 1 0 > subset(df, x2 != 1 | is.na(x2)) no x1 x2 1 1 1 0 2 2 0 NA 3 3 0 NA 5 5 1 0 ## dplyr filter 이용 > library(dplyr) > df %>% filter(x2 == 1) no x1 x2 1 4 1 1 > df %>% filter(x2 != 1) no x1 x2 1 1 1 0 2 5 1 0 > df %>% filter(x2 != 1 | is.na(x2)) no x1 x2 1 1 1 0 2 2 0 NA 3 3 0 NA 4 5 1 0 ## data.table 이용 > library(data.table) > dt <- data.table(df) > dt[x2 == 1] no x1 x2 1: 4 1 1 > dt[x2 != 1] no x1 x2 1: 1 1 0 2: 5 1 0 > dt[x2 != 1 | is.na(x2)] no x1 x2 1: 1 1 0 2: 2 0 NA 3: 3 0 NA 4: 5 1 0
다른 방법들이 그나마 덜 지저분해 보이지만, ‘1 아닌 것에 NA 도 포함되게’할 뭔가 더 깔끔한 방법은 찾지 못했습니다. NA 를 다루는데 is.na() 는 피할 수 없는 함수인가 봅니다. 피할 수 없으면 즐기랬나… ㅠㅠ
2018. 8. 20.