Chapter 3 Data 전처리-결측치 처리

  • 데이터 전처리는 크게 (1) 결측치 처리(2) 이상값 처리 로 나눌 수 있습니다.
    이번 chapter에서는 결측치를 파악하고, 처리 하는 법을 공유 드리겠습니다.

  • 이번에는 R에 기본 내장되어 있는 naniar 패키지의 riskfactors 데이터를 활용하겠습니다.

  • 먼저, 필요한 라이브러리를 호출합니다.

#데이터 구조를 시각적으로 확인할 수 있는 visdat 패키지도 호출합니다. 
pacman::p_load('tidyverse', 'naniar', 'visdat')
  • 이제 오늘 활용할 riskfactors 데이터를 파악해 보겠습니다.

  • str함수를 통해 riskfactors 데이터가 어떤 자료형과 어떤 구조로 되어 있는지 확인하실 수 있습니다.

str(riskfactors)
## tibble [245 × 34] (S3: tbl_df/tbl/data.frame)
##  $ state           : Factor w/ 52 levels "1","2","5","6",..: 22 36 52 38 28 15 40 50 14 5 ...
##  $ sex             : Factor w/ 2 levels "Male","Female": 2 2 2 1 2 1 1 2 1 2 ...
##  $ age             : int [1:245] 49 48 55 42 66 66 37 62 38 42 ...
##  $ weight_lbs      : int [1:245] 190 170 163 230 135 165 150 170 146 260 ...
##  $ height_inch     : int [1:245] 64 68 64 74 62 70 68 70 70 73 ...
##  $ bmi             : num [1:245] 32.7 25.9 28 29.6 24.7 ...
##  $ marital         : Factor w/ 6 levels "Married","Divorced",..: 1 2 1 1 3 1 1 5 1 4 ...
##  $ pregnant        : Factor w/ 2 levels "Yes","No": NA NA NA NA NA NA NA NA NA 2 ...
##  $ children        : int [1:245] 0 0 0 1 0 0 3 0 2 3 ...
##  $ education       : Factor w/ 6 levels "1","2","3","4",..: 6 5 4 6 5 5 6 6 4 5 ...
##  $ employment      : Factor w/ 7 levels "1","2","3","4",..: 2 1 5 1 1 6 2 6 1 3 ...
##  $ income          : Factor w/ 10 levels "<10k","10-15k",..: 6 6 1 8 7 6 8 1 7 3 ...
##  $ veteran         : Factor w/ 5 levels "1","2","3","4",..: 5 5 5 5 5 3 5 5 5 5 ...
##  $ hispanic        : Factor w/ 2 levels "Yes","No": 2 2 1 2 2 2 2 2 2 2 ...
##  $ health_general  : Factor w/ 6 levels "Excellent","VeryGood",..: 3 4 4 1 1 1 2 5 5 3 ...
##  $ health_physical : int [1:245] 3 4 0 0 0 0 0 30 30 0 ...
##  $ health_mental   : int [1:245] 15 30 0 0 0 0 0 30 30 20 ...
##  $ health_poor     : int [1:245] 2 3 NA NA NA NA NA 30 14 4 ...
##  $ health_cover    : Factor w/ 2 levels "Yes","No": 1 1 1 1 1 1 1 2 1 1 ...
##  $ provide_care    : Factor w/ 2 levels "Yes","No": 2 2 2 2 2 2 1 2 2 2 ...
##  $ activity_limited: Factor w/ 2 levels "Yes","No": 1 2 2 2 2 2 2 2 1 NA ...
##  $ drink_any       : Factor w/ 2 levels "Yes","No": 2 2 2 1 2 2 1 2 2 NA ...
##  $ drink_days      : int [1:245] NA NA NA 15 NA NA 2 NA NA NA ...
##  $ drink_average   : int [1:245] NA NA NA NA NA NA 2 NA NA NA ...
##  $ smoke_100       : Factor w/ 2 levels "Yes","No": 2 2 2 2 1 2 2 1 1 1 ...
##  $ smoke_days      : Factor w/ 3 levels "Everyday","Somedays",..: NA NA NA NA 1 NA NA 3 1 3 ...
##  $ smoke_stop      : Factor w/ 2 levels "Yes","No": NA NA NA NA 1 NA NA NA 1 NA ...
##  $ smoke_last      : Factor w/ 6 levels "3","4","5","6",..: NA NA NA NA NA NA NA 5 NA 3 ...
##  $ diet_fruit      : int [1:245] 1095 52 36 NA -7 24 52 156 24 NA ...
##  $ diet_salad      : int [1:245] 261 209 156 NA 261 52 156 24 84 NA ...
##  $ diet_potato     : int [1:245] 104 52 52 NA 209 104 24 52 144 NA ...
##  $ diet_carrot     : int [1:245] 156 0 24 NA 261 52 24 104 24 NA ...
##  $ diet_vegetable  : int [1:245] 521 52 24 NA 365 365 730 365 0 NA ...
##  $ diet_juice      : int [1:245] 12 0 24 NA 104 365 104 0 0 NA ...
  • riskfactors 데이터는 34개의 변수(열)와 245개의 관측치(행)로 구성되어 있으며,
    tibble 데이터 구조를 갖고 있음을 알 수 있습니다.

3.1 결측치 처리하기

3.1.1 결측치 제거

na.omit(데이터) : 데이터의 결측치를 제거하라

  • 데이터에 값이 들어 있지 않은 경우, NA로 표시가 됩니다.

  • 저는 처음 데이터 분석을 진행할 때는 NA를 처리하지 않고 진행하시는 것을 추천 드립니다.

  • NA가 한 개만 들어있어도 해당 줄을 다 날리기 때문에
    아까운 다른 데이터까지 다 날려버릴 수도 있습니다.

  • 아래의 예제를 보시면, na.omit으로 결측치를 날렸을 때
    riskfactors의 관측치가 0으로, 모든 값 (행)이 없어진 것을 확인하실 수 있습니다.

glimpse(na.omit(riskfactors))
## Rows: 0
## Columns: 34
## $ state            <fct> 
## $ sex              <fct> 
## $ age              <int> 
## $ weight_lbs       <int> 
## $ height_inch      <int> 
## $ bmi              <dbl> 
## $ marital          <fct> 
## $ pregnant         <fct> 
## $ children         <int> 
## $ education        <fct> 
## $ employment       <fct> 
## $ income           <fct> 
## $ veteran          <fct> 
## $ hispanic         <fct> 
## $ health_general   <fct> 
## $ health_physical  <int> 
## $ health_mental    <int> 
## $ health_poor      <int> 
## $ health_cover     <fct> 
## $ provide_care     <fct> 
## $ activity_limited <fct> 
## $ drink_any        <fct> 
## $ drink_days       <int> 
## $ drink_average    <int> 
## $ smoke_100        <fct> 
## $ smoke_days       <fct> 
## $ smoke_stop       <fct> 
## $ smoke_last       <fct> 
## $ diet_fruit       <int> 
## $ diet_salad       <int> 
## $ diet_potato      <int> 
## $ diet_carrot      <int> 
## $ diet_vegetable   <int> 
## $ diet_juice       <int>
  • na.omit 함수 안에 데이터를 넣으시면 해당 데이터의 NA값이 포함된 관측치(행)을 제거합니다.

3.1.2 각 함수의 결측치 제거 옵션 활용

  • 저는 결측지는 우선 그대로 두고, 분석을 진행해 보시는 것을 추천드립니다.

  • 회귀, 상관 등 대부분의 분석 함수들이 na값을 제외하고 분석을 진행하는 옵션을 갖추고 있습니다.

  • NA를 처리 하지 않은 상태에서 함수의 NA처리 옵션을 활용하여 돌려 보시고, 이후 NA를 처리하시고 돌려보시는 것을 추천 드립니다.

  • 대부분의 함수에 na값을 제외하고 돌릴 수 있는 인자가 있습니다.

  • sum 함수의 경우, na.rm 옵션으로 na값을 제외하고 구할 수 있습니다.

  • 아래의 예를 보시면, na.rm 옵션이 없을 때는 결과가 NA가 나오지만,

  • na.rm 옵션이 있을 때는 NA 값을 제외한 값들의 sum 결과가 표시됨을 보실 수 있습니다.

# NA값이 포함되어 있는 데이터의 sum을 구하면, 결과값이 NA로 나옵니다. 
sum(riskfactors$diet_fruit)
## [1] NA
# sum 함수에서 NA값을 제거하고 sum하는 옵션인 na.rm=T 를 넣으면 값이 나옵니다. 
sum(riskfactors$diet_fruit,na.rm=T)
## [1] 76956
  • 회귀분석의 경우에는 na.action 옵션이 있습니다.
  • na.action 옵션에 따라 잔차에 차이가 발생합니다.
lm(bmi~pregnant,riskfactors,na.action = na.omit) 
  • na.action 조건을 na.omit으로 주었을 경우, NA값을 제외 시키며,
    이에 따라 결측치가 제거된 후 위와 같이 회귀분석이 실행됩니다.

3.2 결측치 대체하기

  • 저희가 보유하고 있는 데이터는 그 수가 많기에, 결측치를 대체하지 않고,
    제거한 후 사용하여도 원하는 분석결과를 얻으실 수도 있습니다.

  • 결측치를 대체하여 분석하기 원하신다면 아래의 포스팅 참고 부탁 드립니다.

  • mice, rpart, DMwR 등의 패키지를 활용하여 결측치를 대체하실 수 있습니다.

  • 자세한 내용은 아래 링크 참조 부탁 드립니다.

    결측치 처리 기본개념
    결측치 처리(the book)