블로그

데이터 정제하기 - 결측치 본문

Computer engineering/R

데이터 정제하기 - 결측치

JuNM0418 2019. 4. 11. 14:41

결측치

결측치(Missing Value)는 누락된 값, 비어 있는 값을 의미합니다.

결측치가 있으면 함수가 적용되지 않거나 분석 결과가 왜곡되는 문제가 발생합니다.

따라서 결측치가 있는지 확인하고 제거하는 정제과정이 필요합니다.

결측치 찾기

R에서는 결측치를 대문자 NA로 표시합니다.

결측치는 따옴표가 없다는 것에 유의합니다.

따라서 따옴표가 있으면 결측치가 아니라 영문자 "NA"를 의미합니다.

df <- data.frame(sex = c("M", "F", NA , "M", "F"),
                  score = c(5,4,3,4, NA))
df

   sex score
1    M     5
2    F     4
3 <NA>     3
4    M     4
5    F    NA

결측치 확인하기

is.na()함수를 사용해서 결측치가 들어있는지 확인합니다.

출력된 표에서 결측치는TRUE, 결측치가 아닌 값은 FALSE로 표시합니다.

is.na(df)    # 결측치 확인

       sex score
[1,] FALSE FALSE
[2,] FALSE FALSE
[3,]  TRUE FALSE
[4,] FALSE FALSE
[5,] FALSE  TRUE

따라서 sex의 3행과 score의 5행에 결측치가 있는 것을 알 수 있습니다.

결측치의 빈도를 출력하면 다음과 같이 정상적인 값이 몇개인지 그리고 결측치가 몇개 있는지 알 수 있습니다.

table(is.na(df))

FALSE  TRUE 
    8     2 

결측치 제거하기

is.na()filter()에 적용하면 결측치가 있는 행을 제거할 수 있습니다.

먼저 결측치가 있는 행을 출력합니다

아래 코드는 score의 값이 NA가 아닌 행들을 출력해줍니다.

library(dplyr)
df %>% filter(!is.na(score))

sex score
1   M   5
2    F    4
3 <NA>    3
4    M    4

이렇게 추출한 데이터로 데이터 프레임을 만들면 결측치가 없는 데이터가 됩니다.

df_nomiss <- df %>%filter(!is.na(score))    # score 결측치 제거
mean(df_nomiss$score)    # score 평균 산출

[1] 4

sum(df_nomiss$score)    # score 합계 산출

[1] 16

여러 변수 동시에 결측치 없는 데이터 추출하기

filter()&기호를 사용해 조건을 나열하면 여러 변수에 모두 결측치가 없는 행을 추출할 수 있습니다.

df_nomiss <- df %>% filter(!is.na(score) & !is.na(sex))    # score, sex 결측치 제거
df_nomiss    #출력

  sex score
1   M     5
2   F     4
3   M     4

다른 방법으로 결측치 없는 데이터 출력하기

na.omit()를 이용하면 변수를 지정하지 않고 결측치가 있는 행을 한 번에 제거할 수 있습니다.

df_nomiss2 <- na.omit(df)    # 모든 변수에 결측치 없는 데이터 추출
df_nomiss2

1   M     5
2   F     4
4   M     4

na.omit()는 결측치가 하나라도 있으면 모두 제거하기 때문에 쉽고 간편하게 쓸 수 있습니다. 하지만 분석에 필요한 데이터가 일부 손실된다는 단점이 있습니다.

따라서 filter()를 이용해 분석에 사용할 변수의 결측치만 제거하는 방식을 권합니다.

함수의 결측치 제외 기능 이용하기

mean()과 같은 수치 연산 함수들은 결측치를 제외하고 연산하도록 설정하는 na.rm파라미터를 지원 합니다. na.rmTRUE로 설정하고 결측치를 제외하고 함수를 적용하기 때문에 일일이 결측치를 제거하지 않아도 됩니다.

하지만 모든 함수가 na.rm을 지원하는 것이 아니기 때문에 filter()로 결측치를 제거한 후 함수를 적용하는 순으로 작업해야 합니다.

mean(df$score, na.rm = T)    # 결측치를 제외하고 평균 산출

[1] 4

sum(df$score, na.rm = T)    # 결측치 제외하고 합계 산출

[1] 16

summarise()를 이용해보기 전에 결측치를 일부로 넣어보겠습니다.

exam <- read.csv("csv_exam.csv")    # 데이터 불러오기
exam[c(3, 8, 15), "math"] <- NA    #3, 8, 15행의 math에 NA 할당
exam

   id class math english science
1   1     1   50      98      50
2   2     1   60      97      60
3   3     1   NA      86      78
4   4     1   30      98      58

이제 summarise()mean()sum(),median()함수를 불러온다음 na.rm을 사용해서 결측치를 제외하고 값을 구해보겠습니다.

exam %>% summarise(mean_math = mean(math, na.rm = T),
                    sum_math = sum(math, na.rm = T),
                    median_math = median(math, na.rm = T))

  mean_math sum_math median_math
1  55.23529      939          50

결측치 대체하기

데이터가 크고 결측치가 얼마 없는 경우에는 결측치를 제거하고 분석하더라도 무리가 없습니다. 하지만 데이터가 작고 결측치가 많은 경우 결측치를 제거하면 많은 데이터가 손실돼 결과가 왜곡되는 문제가 발생합니다.

따라서 결측치 대신 다른 값을 집어넣는 것이 있는데 그것을 '결측치 대체하기(Imputation)'이라고 합니다.

결측치를 대체하는 방법에는 평균이나 최빈값 같은 대표값을 구해 모든 결측치를 데채하는 방법과 통계 분석 기법으로 각 결측치의 예측값을 추정해 대체하는 방법이 있는데 여기서는 평균을 구해 일괄 대체하는 방법을 알아보겠습니다.

평균값으로 결측치 제거하기

앞에서 만든 exam 데이터에서 3, 8, 15행의 math는 결측치 입니다.

이 값들을 평균값으로 대체하겠습니다.

먼저 math의 평균값을 구하겠습니다.

mean(exam$math, na.rm = T)    # 결측치 제외하고 math 평균 산출

[1] 55.23529

평균값을 구했으니 ifelse()를 이용해 NA값을 평균값으로 대체하겠습니다.

mathNA55를 입력하고 그렇지 않으면 원래의 값을 그대로 두겠습니다.

exam$math <- ifelse(is.na(exam$math), 55, exam$math)    # math가 NA면 55로 대체
table(is.na(exam$math))    # 결측치 빈도표 생성

FALSE 
   20

exam    #출력

   id class math english science
1   1     1   50      98      50
2   2     1   60      97      60
3   3     1   55      86      78
4   4     1   30      98      58

출력 결과를 보면 math의 결측치가 55로 수정된 것을 볼 수 있습니다.

이 결과를 가지고 연산함수를 적용하며 정상적인 값이 출력되는 것을 확인할 수 있습니다.

mean(exam$math)

[1] 55.2

출처

김영우, 쉽게 배우는 R 데이터 분석, 이지퍼블리싱, 2019

Comments