[R] 연습

[R] 데이터 정제하기 (이상값편)

Simon Yoon 2021. 12. 10. 20:09

지난 포스팅에서는 결측치에 대해서 다루었다.

결측치 편에서 다루었던 내용을 요약하자면,

1) 데이터셋에 결측치가 있는지 확인하기 위해서는, summary(), is.na(), complete.cases() 함수를 사용하자.

2) 좀 더 보기 좋게 칼럼별 결측치의 개수를 알고 싶다면, apply(is.na(), 2, sum)이나 colSums(is.na()) 함수를 사용하자.

3) 결측값이 존재하는 행의 수를 확인하기 위해서는, sum(complete.cases()) 함수를 사용한다.

4) 결측치가 너무 많은 열 혹은 행을 삭제하고 싶다면, 열 직접 삭제를 하거나,

    행을 삭제하고 싶다면, !is.na() / complete.cases() / filter() / na.omit() 함수를 사용할 수 있다.

5) 결측치를 평균으로 대치하고 싶다면, ifelse()를 사용하거나 직접 평균 대치를 통해서 할 수 있다.

 

이번 포스팅에서는 데이터셋에 존재할 수 있는 이상값을 판별하고 이상값을 처리하는 연습을 할 것이다.

여기서는 mtcars 데이터를 사용할 것이다.

cars.df <- mtcars

mtcars 데이터의 일부


첫 번째로, 이상값을 판별하는 방법 중에 ESD, 사분위수를 활용하는 방식을 연습할 것이다.

Q. ESD: 평균에서 3 표준편차 떨어진 값을 이상치로 판단하는 방식은?

A. 평균(mean())과 표준편차(sd())를 이용해서 간단히 계산이 가능하다.

 

hp변수에는 ±3표준편차 범위를 넘는 값이 없어서, 연습을 위해서 잠시 ±1.5표준편차로 하자.

먼저, 평균과 표준편차를 구해서 구간을 정해서 이상값을 추출하는 방식은 다음과 같다.

# 이상치를 구하기 위한 평균과 표준편차 저장
hp.mean <- mean(cars.df$hp)
hp.sd <- sd(cars.df$hp)

# 이상치를 판단하기 위한 값 설정
out.min <- hp.mean - 1.5 * hp.sd
out.max <- hp.mean + 1.5 * hp.sd

# 이상치 값을 출력하기
cars.df$hp[cars.df$hp < out.min | cars.df$hp > out.max]

# 결과 [1] 264 335

 

어느 구간을 이상값으로 설정하느냐에 따라서 숫자만 약간 수정하면 될 것이다.

 

더 나아가, 아예 판별식을 함수로 만들어서 원하는 아무 변수에 적용할 수 있도록 하기 위해서, 다음과 같이 작성할 수 있다.

esd.fun <- function(x){return(abs(x - mean(x)) / sd(x) > 1.5)}

library(dplyr)
cars.df %>% filter(esd.fun(hp))

#                 mpg cyl disp  hp drat   wt qsec vs am gear carb
# Ford Pantera L 15.8   8  351 264 4.22 3.17 14.5  0  1    5    4
# Maserati Bora  15.0   8  301 335 3.54 3.57 14.6  0  1    5    8

 

이렇게 함수를 지정하게 되면 원하는 변수를 다 확인해볼 수 있다는 장점이 있다.

또한 앞서서 연습한 dplyr 패키지를 이용해서 결과를 추출할 수 도 있을 것이다.

 


두 번째로, 사분위수를 이용해서 이상값을 판별하는 방식을 알아보자.

Q. 사분위수 범위(IQR)의 1.5배 범위를 벗어나는 값을 이상값으로 판단하려면?

A. boxplot(), fivenum(), IQR() 함수를 이용해보자.

 

boxplot()을 활용하면 먼저 박스플롯으로 시각적으로 먼저 판단해볼 수 있다는 점이 좋다고 할 수 있다.

hp 컬럼 boxplot

# 박스플롯 그리기
hp.box <- boxplot(cars.df$hp)

# 이상값 확인하기
hp.box$out
# 결과 [1] 335

# 각 수치 결과 확인하기
hp.box$stats
#     [,1]
#[1,]   52  # 하위 경계 최소값
#[2,]   96  # 제 1사분위
#[3,]  123  # 제 2사분위
#[4,]  180  # 제 3사분위
#[5,]  264  # 상위 경계 최대값

hp.box$stats를 사용하면 각 경계 최소값과 최대값을 쉽게 알 수 있다.

 

fivenum()을 이용해도 사분위수를 알아낼 수 있고 이를 바탕으로 직접 계산해줄 수 있다.

활용방법은 다음과 같다.

hp.q1 <- fivenum(cars.df$hp)[2]
hp.q3 <- fivenum(cars.df$hp)[4]
hp.iqr <- hp.q3 - hp.q1

out.min <- hp.q1 - 1.5*hp.iqr
out.max <- hp.q3 + 1.5*hp.iqr

# 이상값 구하기
out.df <- cars.df[out.min > cars.df$hp | out.max < cars.df$hp, ]

 

IQR의 경우에는 사분위수 범위를 알 수 있는데, 이는 위의 두 함수 boxplot()과 fivenum()을 통해 구했던 사분위수 범위 결과와는 다르다는 점을 꼭 알아두길 바란다.

fivenum(cars.df$hp)[4] - fivenum(cars.df$hp)[2]
# 결과 [1] 84

IQR(cars.df$hp)
# 결과 [1] 83.5

위와 같이 결과가 다른 결과가 나온다. boxplot()이나 fivenum()을 활용하면 실제 데이터상에서 25%위치, 75%위치에 대응되는 값으로 출력되기 때문에 원하는 결과에 맞게 사용하면 될 것 같다.

 


이상값은 앞에서 연습한 것처럼 어떤 범위로도 나올 수 있지만, 입력 오류나 데이터 처리 오류로 인해 존재할 수 없는 값이 입력되어 있을 경우로도 판단할 수 있다.

 

Q. 이상치가 포함된 데이터를 대체하거나 제외해서 분석하고 싶다면?

A. ifelse()로 다른 값으로 대체하거나 dplyr 패키지의 함수들을 활용해보자.

 

mtcars 데이터의 am(변속기 - 0: 자동, 1: 수동) 열에 이상치를 임의로 만들어 주도록 하겠다. 이 변수에는 0과 1로 분류되므로 2가 들어있을 수는 없으니까 2가 들어간 데이터를 이상값으로 판단할 것이다.

cars.df$am[c(5, 10, 15, 20)] <- 2

# 이상값 확인하기
table(cars.df$am)
#  0  1  2 
# 16 12  4

 

위의 입력 코드처럼 table 함수를 이용해서 이상값을 확인할 수 있다. 잘못 입력된 데이터가 4개 존재함을 확인했다.

 

이제 이 4개의 값을 ifelse() 함수를 사용하여 NA(결측값)으로 대체해보겠다. NA가 아닌 다른 값으로 대체하는 것도 같은 방식을 이용하면 된다.

cars.df$am <- ifelse(cars.df$am == 2, NA, cars.df$am)
# 이상값에 NA가 할당되었다

이제 여기에서 dplyr의 여러 함수를 이용하면 자유롭게 데이터를 다룰 수 있을 것이다.

 

 

★ 예시문제1)

mtcars 데이터셋에서 'vs' 변수(0 = V-shaped, 1 = straight)에 임의로 5개의 이상값을 만들고, 이 이상값 데이터를 NA로 대체한 후, NA 값이 포함된 행 제외하여 wt(무게)의 평균을 구하시오.

 

예시답안)

cars.df$vs[c(1,5,10,15,20)] <- 2

# NA로 대체하기
cars.df$vs <- ifelse(cars.df$vs == 2, NA, cars.df$vs)

# dplyr을 활용하여 평균값 계산
cars.df %>%
  filter(!is.na(vs)) %>%
  summarise(wt.mean = mean(wt))

#   wt.mean
#1 3.198778

 

이상값을 다루는 방식에도 전체적인 데이터프레임을 다루는 함수가 항상 포함되어 있기 때문에 전반적으로 다 익혀두는 것은 필수적이라고 할 수 있을 것이다. 또한 여러 방식을 연습한다면 더 좋을 것이다.

 

※ 참고: 코드 예시는 해당 함수를 활용하기 위한 방법으로 제시한 것입니다. 따라서 다른 방법이 존재할 수 있습니다.

'[R] 연습' 카테고리의 다른 글

[R] 정규화(Normalization)편  (0) 2021.12.12
[R] 차원축소 (PCA편)  (2) 2021.12.11
[R] 데이터 정제하기 (결측치편)  (0) 2021.12.01
[R] dplyr 패키지 활용하기 (4편)  (0) 2021.11.30
[R] dplyr 패키지 활용하기 (3편)  (0) 2021.11.29