본문 바로가기
  • "You can't manage what you can't measure" Peter Drucker
데이터 분석 (with Rstudio)

[R 기초] 결측값 결측치 처리 (데이터 클린징)

by Vitaminymc 2023. 9. 21.
반응형

데이터 전처리 (Data Preprocessing)

데이터 전처리는 데이터 사이언스, 머신 러닝 및 데이터 분석 프로젝트 필요한 데이터를 준비하고 가공하여 분석, 모델링 또는 머신 러닝 모델에 적합하게 사용할 수 있는 형태로 준비하는 포괄적인 과정 
데이터의 품질을 향상시키고 분석 가능한 형태로 변환하여 모델의 성능을 최적화하고 정확성을 확보하기 위한 사전 단계

데이처 전처리 과정

1. 데이터 수집 : 프로젝트의 목적에 따라 적합한 데이터를 수집하고 데이터의 정확성과 완전성을 확인

  • 시스템에서 데이터를 추출하더라도 엑셀 파일 등으로 변환하는 과정에서 누락이나 중복되는 경우 발생
  • 데이터에 사용되는 여러 날짜 (예. 주문일, 물류센터 출고일, 고객 배송일 등)와 분석 대상 기간의 기준 확인 필요 

2. 결측치 처리 : 데이터에 결측치(누락된 값)가 있는 경우, 이를 적절하게 처리

  • 결측치 삭제 또는 대체 

3. 이상치 처리 : 이상치(예외적인 값)를 탐지하고 이를 조치

4. 범주형 데이터 인코딩 : 범주형 변수를 수치형 변수로 변환

5. 데이터 분할 : 데이터를 학습용, 검증용 및 테스트용으로 구분 

6. 데이터 정제 : 노이즈를 제거하거나 데이터에 오류를 수정

7. 데이터 표준화 : 데이터를 표준화하여 일관된 형식으로 변환

  • 예) 날짜 형식을 통일하거나 단위를 표준화

데이터 분석의 80~90%는 전처리 작업, 나머지 10~20%는 전처리 작업 불평등하는데 쓴다는 말이 있을 정도로 분석 전에 하는 사전 작업에 많은 시간이 할애
궁극적으로 기계 학습 모델의 성능을 향상시켜 예측을 더 정확하게 수행하도록 하고, 모델 학습 및 평가에서 발생할 수 있는 문제를 사전에 식별하고 해결하므로 실질적인 시간과 자원을 절약하기 위함
 

데이터 클린징 (Data Cleansing) 프로세스

데이터 클린징은 데이터를 정확하고 유효하게 만드는 과정 (데이터 품질을 향상시켜 분석 결과의 신뢰성을 증대하는 과정)으로, 데이터 분석 전에 필수적인 과정
데이터에서 오류, 이상치 및 불필요한 정보(예: 잘못된 값, 중복 레코드)를 식별하고 수정 또는 제거하여 데이터의 정확성과 일관성을 향상

데이처 클린징 과정

1. 데이터 수집 : 데이터 클린징은 데이터 수집 단계에서 시작, 데이터 수집에 오류가 발생하지 않도록 주의

2. 결측치 처리
: 결측치(누락된 값)를 확인하고 대체하거나 제거

3. 이상치 처리
: 이상치(예외적인 값)를 탐지하고 수정하거나 제거

 
4. 중복 제거 : 중복된 레코드를 식별하고 제거

5. 데이터 형식 표준화
: 데이터 형식을 표준화하여 일관성을 유지
 
6. 데이터 유형 검사 : 데이터 유형(예: 숫자, 문자열)을 확인하고 잘못된 유형을 수정

 
7. 불필요한 열 제거 : 분석에 필요하지 않은 열을 제거

 
데이터 클린징(Data Cleansing)과 데이터 전처리(Data Preprocessing)는 유사한 작업을 포함하지만 중요한 차이점이 있음
-  데이터 전처리(Data Preprocessing) : 모델링에 적합한 형식으로 데이터 가공에 중점
- 데이터 클린징(Data Cleansing) : 데이터 품질을 개선하는 데 중점
 

결측치 (결측값, Missing Values) 처리 방법

해당 데이터를 삭제 또는 분석에서 제외

다른 값으로 대체

데이터 유형(성격)과 분석 목적에 따라 선택

1. 평균 또는 중앙값 대체 : 연속형 변수에 대한 일반적인 방법으로, 결측치를 해당 변수의 평균값 또는 중앙값으로 대체 (변수의 분포가 정규 분포와 유사한 경우에 효과적)

2. 최빈값 대체 : 범주형 변수에 대한 대체 방법으로, 결측치를 해당 변수의 최빈값으로 대체

3. 회귀 분석 기반 대체 : 다른 변수와의 관계를 고려하여 결측치를 예측하는 회귀 모델을 사용하여 대체
    (다른 변수들과의 관계가 있는 경우 유용)

4. K-최근접 이웃(K-Nearest Neighbors) 대체 : 유사한 샘플을 찾아 해당 샘플들의 값으로 결측치를 대체 
   (데이터가 밀집된 경우에 유용)

5. 시계열 데이터의 경우 전방 또는 후방 채움 : 시간에 따라 변하는 데이터의 경우, 결측치를 해당 시점의 이전 값이나 이후 값으로 대체

6. 도메인 지식 기반 대체 : 해당 데이터와 관련된 도메인 지식을 활용하여 결측치를 대체

7. 다중 대체 방법 : 여러 대체 방법을 결합하여 사용하거나, 대체 후 성능을 비교하여 가장 적합한 대체 방법 선택

 

300x250

R 결측치 (결측값, Missing Values, NA) 처리

데이터에 NA가 포함되어 있으면, 결과값도 NA가 출력된다.

na.rm = TRUE 옵션을 사용하여 NA 값을 제외하고 요약 통계량을 계산할 수 있다.

특정 변수의 결측값을 확인하고 제거하기 위해서는 complete.cases함수 is.na 함수를 사용한다. 

install.packages('palmerpenguins')  #팔머 펭귄 Dataset이 포함된 패키지

library(palmerpenguins)

data("penguins")  #Dataset 불러오기

summary(penguins)
   
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie   :152 Biscoe   :168 Min.   :32.10 Min.   :13.10 Min.   :172.0 Min.   :2700 female:165    Min.   :2007
Chinstrap: 68 Dream    :124 1st Qu.:39.23 1st Qu.:15.60 1st Qu.:190.0 1st Qu.:3550 male  :168    1st Qu.:2007
Gentoo   :124 Torgersen: 52 Median :44.45 Median :17.30 Median :197.0 Median :4050 NA's  : 11    Median :2008
    Mean   :43.92 Mean   :17.15 Mean   :200.9 Mean   :4202   Mean   :2008
    3rd Qu.:48.50 3rd Qu.:18.70 3rd Qu.:213.0 3rd Qu.:4750   3rd Qu.:2009
    Max.   :59.60 Max.   :21.50 Max.   :231.0 Max.   :6300   Max.   :2009
    NA's   :2 NA's   :2 NA's   :2 NA's   :2  

penguins 데이터는 총 344 Row로 구성되어 있으나, 일부 변수는 결측치가 포함됨

penguins_df <- penguins

no_col <- ncol(penguins_df)

#변수별 결측값 수 확인
for(i in 1: no_col) {
  name_col <- names(penguins_df)[i]
  no_na <- sum ( is.na (penguins_df[,i]) )
  cat ( name_col, ":", no_na, "\n")
}
species : 0 
island : 0 
bill_length_mm : 2 
bill_depth_mm : 2 
flipper_length_mm : 2 
body_mass_g : 2 
sex : 11 
year : 0 

complete.cases(penguins_df)

총 11개 행 (4, 9, 10, 11, 12, 48, 179, 219, 257, 269, 272 행)에 결측치 포함

 

결측치 제거 (complete.cases)

penguins_df [!complete.cases(penguins_df),]
# A tibble: 11 × 8
  species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
  <fct> <fct> <dbl> <dbl> <int> <int> <fct> <int>
1 Adelie Torgersen NA NA NA NA NA 2007
2 Adelie Torgersen 34.1 18.1 193 3475 NA 2007
3 Adelie Torgersen 42 20.2 190 4250 NA 2007
4 Adelie Torgersen 37.8 17.1 186 3300 NA 2007
5 Adelie Torgersen 37.8 17.3 180 3700 NA 2007
6 Adelie Dream 37.5 18.9 179 2975 NA 2007
7 Gentoo Biscoe 44.5 14.3 216 4100 NA 2007
8 Gentoo Biscoe 46.2 14.4 214 4650 NA 2008
9 Gentoo Biscoe 47.3 13.8 216 4725 NA 2009
10 Gentoo Biscoe 44.5 15.7 217 4875 NA 2009
11 Gentoo Biscoe NA NA NA NA NA 2009
penguins_df2 <- penguins_df[complete.cases(penguins_df),]

summary(penguins_df2)
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie   :146 Biscoe   :163 Min.   :32.10 Min.   :13.10 Min.   :172 Min.   :2700 female:165 Min.   :2007
Chinstrap: 68 Dream    :123 1st Qu.:39.50 1st Qu.:15.60 1st Qu.:190 1st Qu.:3550 male  :168 1st Qu.:2007
Gentoo   :119 Torgersen: 47 Median :44.50 Median :17.30 Median :197 Median :4050   Median :2008
    Mean   :43.99 Mean   :17.16 Mean   :201 Mean   :4207   Mean   :2008
    3rd Qu.:48.60 3rd Qu.:18.70 3rd Qu.:213 3rd Qu.:4775   3rd Qu.:2009
    Max.   :59.60 Max.   :21.50 Max.   :231 Max.   :6300   Max.   :2009
str(penguins_df)

str(penguins_df2)
tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
 $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
 $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
 $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
 $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
tibble [333 × 8] (S3: tbl_df/tbl/data.frame)
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num [1:333] 39.1 39.5 40.3 36.7 39.3 38.9 39.2 41.1 38.6 34.6 ...
 $ bill_depth_mm    : num [1:333] 18.7 17.4 18 19.3 20.6 17.8 19.6 17.6 21.2 21.1 ...
 $ flipper_length_mm: int [1:333] 181 186 195 193 190 181 195 182 191 198 ...
 $ body_mass_g      : int [1:333] 3750 3800 3250 3450 3650 3625 4675 3200 3800 4400 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 1 2 1 2 1 2 2 ...
 $ year             : int [1:333] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...

344 Row에서 333 Row로 감소
 

결측치 대체 (is.na, na.rm)

평균으로 대체

penguins_df$bill_length_mm[is.na(penguins_df$bill_length_mm)] <- mean(penguins_df$bill_length_mm, na.rm = TRUE)

penguins_df$bill_depth_mm[
is.na(penguins_df$bill_depth_mm)] <- mean(penguins_df$bill_depth_mm, na.rm = TRUE)

penguins_df$flipper_length_mm[
is.na(penguins_df$flipper_length_mm)] <- mean(penguins_df$flipper_length_mm, na.rm = TRUE)
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie   :152 Biscoe   :168 Min.   :32.10 Min.   :13.10 Min.   :172.0 Min.   :2700 female:165 Min.   :2007
Chinstrap: 68 Dream    :124 1st Qu.:39.27 1st Qu.:15.60 1st Qu.:190.0 1st Qu.:3550 male  :168 1st Qu.:2007
Gentoo   :124 Torgersen: 52 Median :44.25 Median :17.30 Median :197.0 Median :4050 NA's  : 11 Median :2008
    Mean   :43.92 Mean   :17.15 Mean   :200.9 Mean   :4202   Mean   :2008
    3rd Qu.:48.50 3rd Qu.:18.70 3rd Qu.:213.0 3rd Qu.:4750   3rd Qu.:2009
    Max.   :59.60 Max.   :21.50 Max.   :231.0 Max.   :6300   Max.   :2009
          NA's   :2    

상위 행 값으로 대체

for (i in 2:length(penguins_df$sex)) {
  
if (is.na(penguins_df$sex[i])) {
    penguins_df$sex[i] <- penguins_df$sex[i - 1]
  }
}
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie   :152 Biscoe   :168 Min.   :32.10 Min.   :13.10 Min.   :172.0 Min.   :2700 female:167 Min.   :2007
Chinstrap: 68 Dream    :124 1st Qu.:39.27 1st Qu.:15.60 1st Qu.:190.0 1st Qu.:3550 male  :177 1st Qu.:2007
Gentoo   :124 Torgersen: 52 Median :44.25 Median :17.30 Median :197.0 Median :4050   Median :2008
    Mean   :43.92 Mean   :17.15 Mean   :200.9 Mean   :4202   Mean   :2008
    3rd Qu.:48.50 3rd Qu.:18.70 3rd Qu.:213.0 3rd Qu.:4750   3rd Qu.:2009
    Max.   :59.60 Max.   :21.50 Max.   :231.0 Max.   :6300   Max.   :2009
          NA's   :2    

다중 대체 방법 (sex에 따라, 평균값으로 대체)

#암,수 평균 body_mass_g
penguins_df %>% group_by (sex ) %>%
  summarise( 
  mean_mass = mean(body_mass_g, na.rm = TRUE)    
  ) -> penguins_df_mean

# 결측치 대체
for (i in 1:nrow(penguins_df)) {
 
 if (is.na(penguins_df$body_mass_g[i])) {
    gender <- penguins_df$sex[i]
    if (gender == "male") {
      penguins_df$body_mass_g[i]<- penguins_df_mean$mean_mass[2]
    } else if (gender == "female") {
      penguins_df$body_mass_g[i] <- penguins_df_mean$mean_mass[1]
    }
  }
}
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie   :152 Biscoe   :168 Min.   :32.10 Min.   :13.10 Min.   :172.0 Min.   :2700 female:167 Min.   :2007
Chinstrap: 68 Dream    :124 1st Qu.:39.27 1st Qu.:15.60 1st Qu.:190.0 1st Qu.:3550 male  :177 1st Qu.:2007
Gentoo   :124 Torgersen: 52 Median :44.25 Median :17.30 Median :197.0 Median :4025   Median :2008
    Mean   :43.92 Mean   :17.15 Mean   :200.9 Mean   :4200   Mean   :2008
    3rd Qu.:48.50 3rd Qu.:18.70 3rd Qu.:213.0 3rd Qu.:4750   3rd Qu.:2009
    Max.   :59.60 Max.   :21.50 Max.   :231.0 Max.   :6300   Max.   :2009
> penguins_df_mean
# A tibble: 2 × 2
  sex    mean_mass
  <fct>      <dbl>
1 female     3862.
2 male       4518.
> penguins_df_mean$mean_mass[1]
[1] 3862.273
> penguins_df_mean$mean_mass[2]
[1] 4518.22

Missing Values NA

728x90