쭈쌤
쭈쌤 Hello World

[R 데이터분석] 데이터 정제

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[R 데이터분석] 데이터 정제≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

[R 데이터분석] 데이터 정제

데이터 정제란 데이터 분석에 앞서 전처리가 완료된 데이터에 대해 빈값(결측치)이나 정상 범위를 벗어난 값(이상치)들을 제거하거나 다른 값으로 대체하는 처리를 말합니다.

#01.결측치

비어있는 값 (DB에서의 NULL과 비슷한 의미)

현장에서 만들어진 실제 데이터는 수집 과정에서 발생한 오류로 인해 결측치를 포함하고 있는 경우가 많다.

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

1) 결측치를 처리하는 대표적인 방법

  1. 결측치 소거법
    • 결측치가 포함된 행 혹은 열을 제거하는 방법
    • 결측치가 포함된 데이터가 적은 경우는 상관 없지만 결측치가 많을 경우 결과 왜곡이 발생할 수 있다.
  2. 결측치 대체법
    • 결측치에 대표값이나 기술통계값을 적용하는 방법

2) 필요한 기본 패키지와 샘플 데이터 준비

a) 패키지 가져오기

1
2
3
4
5
REPO_URL <- "https://cran.seoul.go.kr/"

# `%>%`가 적용되는 기능을 사용하고자 할 경우
if (!require("dplyr"))     install.packages("dplyr", repos=REPO_URL)
library(dplyr)

b) 샘플 데이터 준비

1
2
성적표 <- read.csv("http://itpaper.co.kr/demo/r/grade.csv", stringsAsFactors=F, fileEncoding="euc-kr")
성적표
▶ 출력결과
A data.frame: 5 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><int><int><int>
철수1남자 98NA8864
영희2여자 88906272
민수1남자 9270NANA
수현3여자 63603170
호영4남자12050NA88

3) 결측치를 확인하는 방법

a) 데이터프레임 전체에 대한 확인

is.na() 함수는 결측치에 대해 TRUE를, 결측치가 아닌 정상 값에 대해 FALSE를 적용한 새로운 DataFrame을 반환한다.

1
2
3
# 결측치 확인 --> 결측치가 맞는 값에 TRUE가 표시된다.
결측치확인 <- is.na(성적표)
결측치확인
▶ 출력결과
A matrix: 5 × 7 of type lgl
이름학년성별국어영어수학과학
FALSEFALSEFALSEFALSE TRUEFALSEFALSE
FALSEFALSEFALSEFALSEFALSEFALSEFALSE
FALSEFALSEFALSEFALSEFALSE TRUE TRUE
FALSEFALSEFALSEFALSEFALSEFALSEFALSE
FALSEFALSEFALSEFALSEFALSE TRUEFALSE

b) 결측치 빈도수 출력

table() 함수는 DataFrame의 각 열에 대해 값의 종류별로 카운트 한 결과를 산정한 결과를 반환한다.

이를 데이터 빈도수라고 한다.

1
2
결측치빈도 <- table(결측치확인)
결측치빈도
▶ 출력결과
1
2
3
결측치확인
FALSE  TRUE
   31     4

c) 각 열별로 결측치 수 확인하기

colSumes() 함수는 DataFrame에서 각 열별로 합산을 수행한다. 이 때 TRUEFALSE는 각각 1, 0으로 계산되어 진다.

1
colSums(결측치확인)
▶ 출력결과
1
2
3
4
5
6
7
이름      0
학년      0
성별      0
국어      0
영어      1
수학      2
과학      1

d) 특정 변수(컬럼)에 대한 결측치 확인

1
2
수학점수_결측치 <- is.na(성적표$수학)
수학점수_결측치
▶ 출력결과
1
2
3
4
5
1. FALSE
2. FALSE
3. TRUE
4. FALSE
5. TRUE

e) 특정 컬럼에 대한 결측치 빈도수 확인

1
2
수학점수_결측치빈도 <- table(수학점수_결측치)
수학점수_결측치빈도
▶ 출력결과
1
2
3
수학점수_결측치
FALSE  TRUE
    3     2

4) 결측치 소거

f) 특정 열에 대해 결측치가 포함된 행만 추출하기

1
성적표 %>% filter(is.na(수학))
▶ 출력결과
A data.frame: 2 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><int><int><int>
민수1남자 9270NANA
호영4남자12050NA88

g) 특정 열에 대해 결측치가 포함되지 않은 행만 추출하기

is.na() 함수를 부정하기 위해 !를 적용한다.

1
성적표 %>% filter(!is.na(수학))
▶ 출력결과
A data.frame: 3 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><int><int><int>
철수1남자98NA8864
영희2여자88906272
수현3여자63603170

h) 두 개 이상의 열에 대한 결측치 소거

filter 함수에 &로 구분하여 결측치 상태를 지정한다.

결측치가 포함된 행들이 제거된다.

1
2
결측치제거 <- 성적표 %>% filter(!is.na(영어) & !is.na(수학) & !is.na(과학))
결측치제거
▶ 출력결과
A data.frame: 2 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><int><int><int>
영희2여자88906272
수현3여자63603170

i) 결측치를 전체 데이터프레임에 대해 한번에 제거하기

모든 변수에 결측치 일괄제거

na.omit()은 간단한 장점이 있지만 자칫 분석에 필요한 행까지 손실될 우려가 있다.

예를 들어 분석 목적이 성별에 따른 수학점수 차이를 알아보는 것이라면 na.omit()을 사용했을 때, 국어점수에 결측치가 포함된 철수의 데이터도 삭제된다.

철수는 수학에 대해 결측치가 아니므로 분석이 가능함에도 불구하고 일괄 삭제 기능으로 제거되는 것이다.

따라서 filter()를 이용해 분석에 사용할 수 있는 변수의 결측치만 제거하는 것이 좋다.

1
2
일괄제거 <- na.omit(성적표)
일괄제거
▶ 출력결과
A data.frame: 2 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><int><int><int>
2영희2여자88906272
4수현3여자63603170

5) 결측치 대체

  • 연속형 변수 : 평균이나 중앙값으로 대체
    • 수량적 특성에 의한 구분
  • 이산형 변수 : 최빈값으로 대체
    • 범주를 갖는 데이터.
    • 범주형 데이터에는 논리적 순서가 없을 수도 있다.
    • 성별, 재료 유형, 결제 방법 등

a) 결측치를 대체할 때 고려되어야 하는 사항들

  • 결측치의 비율
  • 데이터의 분포
  • 다른 변수와의 관계가 있는지

b) 각 컬럼별로 결측치 데이터 확인

1
colSums(is.na(성적표))
▶ 출력결과
1
2
3
4
5
6
7
이름      0
학년      0
성별      0
국어      0
영어      1
수학      2
과학      1

c) 결측치가 존재하는 컬럼에 대한 평균값 얻기

mean() 함수를 사용하면 특정 컬럼에 대한 평균값을 얻을 수 있다. 이 때, na.rm=TRUE 파라미터를 추가하면 결측치를 제외한 평균을 얻을 수 있다.

na.rm 파라미터 미적용시 결측치가 포함된 열은 계산되지 않고 <NA>로 반환됨.

1
2
영어평균 <- mean(성적표$영어, na.rm=TRUE)
영어평균
▶ 출력결과
1
67.5
1
2
수학평균 <- mean(성적표$수학, na.rm=TRUE)
수학평균
▶ 출력결과
1
60.3333333333333
1
2
과학평균 <- mean(성적표$과학, na.rm=TRUE)
과학평균
▶ 출력결과
1
73.5

d) 결측치가 포함된 컬럼에서 결측치 값을 평균값으로 대체

컬럼의 값이 결측치라면 영어평균을 적용, 그렇지 않다면 원래의 영어점수 적용.

1
2
3
4
성적표$영어 <- ifelse(is.na(성적표$영어), 영어평균, 성적표$영어)
성적표$수학 <- ifelse(is.na(성적표$수학), 수학평균, 성적표$수학)
성적표$과학 <- ifelse(is.na(성적표$과학), 과학평균, 성적표$과학)
성적표
▶ 출력결과
A data.frame: 5 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><dbl><int><int>
철수1남자 9867.588.0000064.0
영희2여자 8890.062.0000072.0
민수1남자 9270.060.3333373.5
수현3여자 6360.031.0000070.0
호영4남자12050.060.3333388.0

e) 좀 더 간략한 표현

같은 기능을 하는 구문을 좀 더 간략하게 표현하면 아래와 같다.

1
2
3
성적표$수학[is.na(성적표$수학)] <- 수학평균
성적표$과학[is.na(성적표$과학)] <- 과학평균
성적표
▶ 출력결과
A data.frame: 5 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><dbl><dbl><dbl>
철수1남자 9867.588.0000064.0
영희2여자 8890.062.0000072.0
민수1남자 9270.060.3333373.5
수현3여자 6360.031.0000070.0
호영4남자12050.060.3333388.0

#02.이상치(Outlier) = 이상한 값

정상 범주에서 크게 벗어난 값.

데이터 수집 과정에서 오류가 발생할 수 있기 때문에, 현장에서 만들어진 실제 데이터에는 이상치가 포함될 수 있다. 이상치가 포함되어 있으면 분석 결과가 왜곡되기 때문에 분석에 앞서 이상치를 제거하는 작업을 해야 한다.

1) 극단치

이상치의 한 종류. 오류는 아니지만 굉장히 드물게 발생하는 극단적인 값.

ex) 몸무게 변수에 200kg 이상의 값이 있다면, 존재할 가능성은 있지만 굉장히 드문 경우이므로 극단치라 볼 수 있다.

a) 극단치 제거 방법

극단치 제거를 위해 먼저 어디까지를 정상 범위로 볼 것인가를 정해야 한다.

  1. 논리적으로 판단하여 정하기
    • 성인의 몸무게가 40~150kg를 벗어나는 경우는 상당히 드물 것으로 판단하고, 이 범위를 벗어나면 극단치로 간주하는 것이다.
  2. 통계적인 기준을 이용하기
    • 상하위 0.3% 또는 +-3 표준 편차에 해당할 만큼 극단적으로 크거나 작으면 극단치로 간주하는 방법
  3. 상자그림
    • 중심에서 크게 벗어난 값을 극단치로 간주.
    • 극단치가 원으로 표시된다.

극단치에 대한 기준이 정해지면 해당 값들을 찾아 결측치로 변경하고 결측치 소거/대체 법을 적용한다.

b) 극단치가 존재하는지 확인하기

데이터 빈도표를 통한 확인

값의 종류를 알 수 있기 때문에 이상치나 극단치를 확인할 수 있다.

아래 빈도표들을 보면 국어점수에서 120점에 대한 수치가 1건 표시됨을 알 수 있다.

1
table(성적표$이름)
▶ 출력결과
1
2
민수 수현 영희 철수 호영
   1    1    1    1    1
1
table(성적표$성별)
▶ 출력결과
1
2
남자 여자
   3    2
1
table(성적표$국어)
▶ 출력결과
1
2
 63  88  92  98 120
  1   1   1   1   1
1
table(성적표$영어)
▶ 출력결과
1
2
  50   60 67.5   70   90
   1    1    1    1    1
1
table(성적표$수학)
▶ 출력결과
1
2
  31    60.3333333333333               62               88
   1                   2                1                1
1
table(성적표$과학)
▶ 출력결과
1
2
  64   70   72 73.5   88
   1    1    1    1    1

c) 상자그림을 통한 확인

극단치가 원으로 표시된다.

1
2
options(repr.plot.width=10, repr.plot.height=7)
boxplot(성적표$국어, 성적표$영어, 성적표$수학, 성적표$과학, names=c('국어','영어', '수학', '과학'))
▶ 출력결과

png

d) 국어점수에 대한 상자그림 상태 확인

boxplot()$stats는 상자그림에 대한 각 위치의 수치값을 표시한다.

극단치 자체를 표시하지는 않는다.

표시 순서대로 아래쪽 극단치 경계, 1사분위 수, 중앙값, 3사분위 수, 위쪽 극단치 경계

1
boxplot(성적표$국어)$stats
▶ 출력결과
1
2
3
4
5
1. 88
2. 88
3. 92
4. 98
5. 98

png

e) 상자그림을 통해 극단치의 위치와 범위를 파악하고 결측치로 대체

국어점수의 위쪽 극단치 경계가 98점으로 표시되었으므로 98점보다 큰 데이터는 모두 극단치로 간주하고 결측치(NA)로 대체한다.

1
2
3
4
5
# 원본을 유지하기 위해 복사본을 하나 만들고 진행
결측치제거 <- 성적표

결측치제거$국어 <- ifelse(결측치제거$국어 > 98, NA, 결측치제거$국어)
결측치제거
▶ 출력결과
A data.frame: 5 × 7
이름학년성별국어영어수학과학
<chr><int><chr><int><dbl><dbl><dbl>
철수1남자9867.588.0000064.0
영희2여자8890.062.0000072.0
민수1남자9270.060.3333373.5
수현3여자6360.031.0000070.0
호영4남자NA50.060.3333388.0

f) 결측치로 처리된 이상치를 다른 통계적 산출 값으로 대체

여기서는 중앙값으로 대체한다.

1
2
결측치제거$국어[is.na(결측치제거$국어)] <- median(결측치제거$국어, na.rm=TRUE)
결측치제거
▶ 출력결과
A data.frame: 5 × 7
이름학년성별국어영어수학과학
<chr><int><chr><dbl><dbl><dbl><dbl>
철수1남자9867.588.0000064.0
영희2여자8890.062.0000072.0
민수1남자9270.060.3333373.5
수현3여자9160.031.0000070.0
호영4남자9050.060.3333388.0
Rating:

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[R 데이터분석] 데이터 정제≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

comments powered by Disqus