12.3 결측치의 처리

R에서 누락된 값은 NA (not available) 기호로 표시됩니다. 불가능한 값(예 : 0으로 나누기)은 기호 NaN (Not a Number)로 표시됩니다. R은 문자 및 숫자 데이터에 동일한 기호를 사용합니다.

결측치의 처리는 여러 가지 방법이 있습니다. 여기서는 결측치를 다른 값으로 대체하는 방법과 결측치를 제외시키는 방법에 대하여 살펴보겠습니다.

결측치를 처리하기 전에 데이터 세트에 결측치가 있는지 확인하는 방법 먼저 학습하겠습니다.

12.3.1 결측치 확인

is.na() 함수를 이용하여 결측치를 확인할 수 있습니다. 또한 which() 함수와 결합하여 NA가 있는 위치를 확인할 수 있으며, sum() 함수와 mean() 함수와 결합하여 NA의 갯수와 NA의 비율을 구할 수도 있습니다.

## 결측치가 있는 데이터 프레임에서 NA값을 확인합니다.
is.na(df)                             # df의 데이터 요소별로 NA이면 TRUE를 반환합니다. 
##       name gender myvar1 myvar2
## [1,] FALSE  FALSE  FALSE  FALSE
## [2,] FALSE  FALSE   TRUE  FALSE
## [3,] FALSE  FALSE  FALSE  FALSE
                                      # 데이터 프레임은 사작형 모양으로 is.na() 함수는 
                                      # "논리형 행렬/배열형"으로 반환합니다.

## 데이터 프레임의 특정 컬럼(벡터)에 NA가 있는지 확인합니다.
is.na(df$myvar1)                      # 논리형 벡터를 반환합니다.
## [1] FALSE  TRUE FALSE
## 결측치가 있는 벡터에서 NA값을 확인합니다.
y <- c(1,2,3,NA)
is.na(y)                              # 논리형 벡터 (F F F T)를 반환합니다.
## [1] FALSE FALSE FALSE  TRUE
## which(is.na()) 함수를 이용하여 NA가 있는 색인 번호를 확인할 수 있습니다.
which(is.na(df))                      # 열 우선에 의한 요소의 위치인 8을 출력됩니다. 
## [1] 8
which(is.na(y))                       # 4를 출력합니다.
## [1] 4
## sum(is.na()) 함수를 이용하여 NA의 갯수를 확인할 수 있습니다.
sum(is.na(df))                        # 1을 출력합니다.
## [1] 1
sum(is.na(y))                         # 1을 출력합니다.
## [1] 1
## mean(is.na()) 함수를 이용하여 NA의 비율을 구할 수 있습니다.
mean(is.na(df))                        # 1/12인 0.0833을 출력합니다.
## [1] 0.08333333
mean(is.na(y))                         # 1/4인 0.25를 출력합니다.
## [1] 0.25

12.3.1.1 일반 데이터를 결측치 NA로 변경하기

데이터 프레임에 NA로 입력이 되어 있지 않은 데이터를 NA로도 변경할 수 있습니다. 예를 들어, my.df 데이터 프레임의 myvar1 열에 있는99의 값을 NA로 변경하고, myvar2열에 있는7의 값을 NA로 변경해 보겠습니다.

# my.df 데이터 프레임을 생성합니다.
my.df <- data.frame(name = c("Kim", "Lee", "Park", "Choi", "Suh"),
                 gender = c("Female", "Male", "Female", "Male", "Female"),
                 myvar1 = c(1, NA, 3, 2, 99),
                 myvar2 = c(1, 3, 5, 7, 7))
str(my.df)
## 'data.frame':    5 obs. of  4 variables:
##  $ name  : chr  "Kim" "Lee" "Park" "Choi" ...
##  $ gender: chr  "Female" "Male" "Female" "Male" ...
##  $ myvar1: num  1 NA 3 2 99
##  $ myvar2: num  1 3 5 7 7
# myvar1 컬럼의 99값은 실제로 결측치로 입력한 값입니다. 이를 NA로 변경합니다. 
# my.df$myvar1 의 값이 99인 요소를 선택한 다음, 그 값을 NA로 변경합니다.
my.df$myvar1[my.df$myvar1 == 99] <- NA

# myvar2 컬럼의 7값은 실제로 결측치로 입력한 값입니다. 이를 NA로 변경합니다. 
# my.df$myvar2 의 값이 7인 요소를 선택한 다음, 그 값을 NA로 변경합니다.
my.df$myvar2[my.df$myvar2 == 7] <- NA

12.3.1.2 NA를 제거한 연산

벡터의 연산을 위한 다양한 함수들에 대하여 제2부 제2장에서 살펴보았습니다. 이러한 함수들은 벡터에 NA값이 있으면 그 결과로 NA를 반환합니다. 이때 함수에 na.rm = TRUE 인수를 설정해 주면 벡터 요소에서 NA를 제거하고 연산을 하게 됩니다.

# my.df의 myvar1 컬럼의 합계와 평균을 구해 보겠습니다. sum() 함수와 mean() 함수 이용
sum(my.df$myvar1)                           # 결과로 NA를 반환합니다.
## [1] NA
mean(my.df$myvar2)                          # 결과로 NA를 반환합니다.
## [1] NA
# sum() 함수와 mean() 함수에 na.rm = TRUE 인수를 지정해 줍니다.
sum(my.df$myvar1, na.rm = TRUE)             # 결과로 6을 반환합니다.
## [1] 6
mean(my.df$myvar2, na.rm = TRUE)            # 결과로 3을 반환합니다.
## [1] 3

complete.cases() 함수를 이용하여 데이터 세트의 각 행 별로 NA가 존재하는지 확인할 수 있습니다. 이 complete.cases() 함수는 논리형 벡터를 반환합니다.

na.omit() 함수는 결측치가 있는 행들을 제거한 개체를 반환합니다.

예를 들어, 앞에서 my.df 데이터 프레임에 대하여 각 행 단위로 NA가 있는 행은 제거하여 새로운 데이터 세트를 생성해 보겠습니다.

# my.df 파일의 내용을 확인합니다.
my.df                           # 2, 4, 5번째 행에 NA가 잆습니다.
##   name gender myvar1 myvar2
## 1  Kim Female      1      1
## 2  Lee   Male     NA      3
## 3 Park Female      3      5
## 4 Choi   Male      2     NA
## 5  Suh Female     NA     NA
# complete.case() 함수를 이용해 보겠습니다.
comp.index <- complete.cases(my.df)     # my.df의 행별로 NA가 있는지 확인합니다. 
comp.index                              # T, F, T, F, F가 반환됩니다.
## [1]  TRUE FALSE  TRUE FALSE FALSE
my.comp.df <- my.df[comp.index,  ]      # comp.index가 T인 행만 선택해서 my.comp.df 개체에 복사합니다.
my.comp.df
##   name gender myvar1 myvar2
## 1  Kim Female      1      1
## 3 Park Female      3      5
# na.omit() 함수를 이용해 보겠습니다.
my.new.df <- na.omit(my.df)             # my.df의 각 행에서 NA가 없는 행만 my.new.df 개체에 복사합니다.
my.new.df
##   name gender myvar1 myvar2
## 1  Kim Female      1      1
## 3 Park Female      3      5
# my.comp.df와 my.new.df는 동일한 데이터 세트 입니다. : setequal() 함수로 확인합니다.
setequal(my.comp.df, my.new.df)         # TRUE를 반환합니다.
## [1] TRUE

12.3.1.3 NA값을 다른 값으로 대체하기

데이터 프레임의 특정 컬럼에 NA가 있는 경우 앞에서 살펴본 것처럼 NA를 제거하고 연산을 하는 방법도 있지만, 이 NA 값을 컬럼의 대표값 예를 들면 평균값이나 중앙값 등으로 변경하여 처리하기도 합니다.

앞의 예에서 my.df 데이터 프레임의 myvar1 컬럼의 NA 값을 평균값으로 대체해 보겠습니다.

# my.df$myvar1의 NA 요소 값을 my.df$myvar1의 평균값을 대체합니다.
# my.df$myvar1 컬럼의 요소 값을 확인합니다.
my.df$myvar1
## [1]  1 NA  3  2 NA
# 먼저 my.df$myvar1의 평균을 구합니다. 
mean.myvar1 <- mean(my.df$myvar1, na.rm = TRUE)    # NA를 제거한 평균을 구합니다.
mean.myvar1                                        # NA를 제거한 평균은 2입니다.
## [1] 2
# my.df$myvar1의 요소 값이 NA인 것들을 찾아서 mean.myvar1으로 대체합니다.
my.df$myvar1[is.na(my.df$myvar1)] <- mean.myvar1   
my.df$myvar1                                       # NA가 모두 평균값 2로 대체되었습니다.
## [1] 1 2 3 2 2

R의 대부분의 모델링 함수는 결측값을 처리하기위한 옵션을 제공합니다. 다중 대체와 같은 방법을 통해 결측값을 리스트 요소별로(행별로) 삭제하는 것 이상으로 진행할 수 있습니다. R을 통해 액세스할 수 있는 좋은 구현에는 Amelia II, Mice 그리고 mitools 등이 있습니다.13