더북(TheBook)

NA의 처리

NA는 값이 기록되지 않았거나 관측되지 않은 경우 데이터에 저장되는 값으로 ‘결측치’라고 부른다. 예를 들어, 인구 조사에서 특정 가구가 소득을 묻는 항목에 답을 하지 않았다면 해당 값은 NA로 기록될 것이다.

데이터에 NA가 포함되어 있을 경우 연산 결과가 다음과 같이 NA로 바뀌어버리므로 주의가 필요하다.

> NA & TRUE
[1] NA
> NA + 1
[1] NA

이러한 문제점을 해결하기 위해 많은 R 함수에서 na.rm을 함수 인자로 받는다. na.rm은 NA 값이 있을 때 해당 값을 연산에서 제외할 것인지를 지정하는 데 사용한다. 다음 예를 살펴보자.

> sum(c(1, 2, 3, NA))
[1] NA
> sum(c(1, 2, 3, NA), na.rm=TRUE)
[1] 6

이처럼 NA 값에 따라 처리를 다르게 하려면 na.fail, na.omit, na.exclude, na.pass 함수를 사용한다. 또 다른 예로, 잘 알려진 기계 학습 패키지 중 하나인 caret(Classification and Regression Training)[1]은 NA 처리 방법을 결정한다. 표 3-5에 이 함수들을 보였다.

표 3-5 NA 처리 함수

함수

의미

na.fail(object, ...)

object에 NA가 포함되어 있으면 실패한다.

na.omit(object, ...)

object에 NA가 포함되어 있으면 이를 제외한다.

na.exclude(object, ...)

object에 NA가 포함되어 있으면 이를 제외한다는 점에서 na.omit과 동일하다. 그러나 naresid, napredict를 사용하는 함수에서 NA로 제외한 행을 결과에 다시 추가한다는 점이 다르다.

na.pass(object, ...)

object에 NA가 포함되어 있더라도 통과시킨다.

다음 예는 이 함수들의 차이를 보여준다.

> (x <- data.frame(a=c(1, 2, 3), b=c("a", NA , "c"), c=c("a", "b", NA)))
  a    b    c
1 1    a    a
2 2 <NA>    b
3 3    c <NA>
> na.fail(x)     # NA가 포함되어 있으므로 실패
Error in na.fail.default(x) : missing values in object
> na.omit(x)     # NA가 포함된 행을 제외
  a b c
1 1 a a
> na.exclude(x)  # NA가 포함된 행을 제외
  a b c
1 1 a a
> na.pass(x)     # NA의 여부에 상관없이 통과
  a    b    c
1 1    a    a
2 2 <NA>    b
3 3    c <NA>

따라서 NA를 어떻게 처리할지를 na.action이라는 함수 인자로 받았다면 ‘na.action(데이터 프레임)’을 실행해 현재 처리 중인 데이터를 사용자가 원하는 대로 정제할 수 있다.

<Note> na.omit과 na.exclude의 차이

다음과 같이 NA가 포함된 데이터 프레임을 가정해보자.

  > df <- data.frame(x=1:5, y=seq(2,10,2))
  > df[3, 2]=NA
  > df
  x y
  1 1 2
  2 2 4
  3 3 NA
  4 4 8
  5 5 10

이 데이터에 y = ax + b 형태의 선형 모델을 가정해보자. 이 모델은 선형 회귀 함수 lm( )으로 만들 수 있다. 만들어진 모델에 resid( ) 함수를 적용하면 선형 모델로 예측한 값과 실제 y 값 간의 차이인 잔차(residual)를 구할 수 있다(선형 회귀 및 lm, resid 함수 등에 대한 내용은 ‘8장. 선형 회귀’에서 다시 다룬다).

lm( ) 함수는 인자로 na.action을 받으며, 이 값에 따라 NA가 포함된 행을 다루는 방법이 달라진다. 예를 들어, na.omit을 지정하면 다음과 같이 NA가 포함된 3행을 제외하고 모델을 작성한다. 따라서 df에 총 5행이 있지만 resid( )의 결과는 총 4개 값이다.

  > resid(lm(y ~ x, data=df, na.action=na.omit))
              1            2            4             5
  -2.982647e-16 3.439354e-16 1.612526e-16 -2.069233e-16

반면 na.action에 na.exclude를 지정하면 NA를 제외하고 모델을 만들지만, 잔차(residual)를 구할 때 NA가 포함된 행은 잔차를 NA로 해서 추가한다. 따라서 resid( )의 결과의 길이와 원래 데이터의 길이가 같다.

  > resid(lm(y ~ x, data=df, na.action=na.exclude))
              1            2            3             4             5
  -2.982647e-16 3.439354e-16            NA 1.612526e-16 –2.069233e-16
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.