AI & 빅데이터/데이터 주물럭( + feature engineering)

[데이터전처리] Outlier(이상치/이상값/특이값/특이치 등) 탐지 방법(detection method) : 1. IQR 방식 with 파이썬

Clary K 2020. 10. 28. 22:10
728x90

데이터 내에서 이상값을 탐지하는 강력한 방법 중 하나로 탐색적 데이터 분석(EDA)의 선구자인 John Tukey가 개발한 이상치 검출 IQR (사 분위 범위) 방법이 있다. 역사가 오래된 전통적인 방법이다.

이 방법이 고안된 시대는 수작업으로 계산하고 플로팅도 하는 시대였기 때문에 대체적으로 데이터셋은 일반적으로 작았으며 데이터가 말해주고 있는 이야기 자체를 이해하는 데에 중점을 두었다고 한다. John Tukey가 기여한 박스플롯(box-and-whisker 플롯이라고 불리기도 함)을 본 적이 있다면 이 방법이 실제로 작동하는 것을 본 것이나 다름없다 :)

 

 

IQR Method란?

박스플롯 그래프는 사 분위수(데이터를 동일한 사이즈의 4개 그룹으로 나누는 기준 점)를 사용하여 데이터의 모양을 표시한다. 박스는 25번째와 75번째 백분위 수와 같은 1사 분위수와 3사 분위수를 나타낸다. 박스 중간에 있는 선은 중앙값 인 2사 분위수를 나타낸다.

타이타닉 데이터셋의 수치형 변수인 'age'와 'fare' 변수를 예로 박스플롯을 그려보았다.

 

위와 같은 이상치 탐지 방법에 이름을 부여하고 있는 사 분위수 범위는 1사 분위와 3사 분위(박스 모양의 가장자리) 사이의 범위를 말한다. John Tukey가 정의한 이상치는 첫 번째 사 분위수보다 낮은 IQR의 1.5배 또는 세 번째 사 분위수보다 높은 IQR의 1.5배를 벗어나는 데이터 포인트를 "외부(outside)" 또는 "거리가 먼(far out)"것으로 간주하였다. 고전적인 박스플롯에서 검은 선으로 확장되는 '수염(whiskers)'은 박스플롯의 '외부 또는 가장자리'까지가 아닌 마지막 데이터 포인트까지 확장되어 있다.

 

위의 2개의 박스플롯 중 'age' 변수를 예로 들어보면, 박스에서 데이터셋의 중앙값이 29로 떨어지고 1사 분위수와 3사 분위수가 각각 약 20과 39로 떨어지는 것을 볼 수 있다. 수염(검은 선 부분)은 약 63까지 플로팅되었고, 63 이상부터 80까지 범위에 이상값들이 7개 포인트로 나타났다.

 

[파이썬 seaborn 박스플롯 그리기 참고]

 

[데이터시각화] 파이썬 seaborn : 시각화 유형 : 분포(Distribution) - 2) 박스플롯(boxplot) 그래프의 모든

​지난 시간에 이어 분포 유형에 해당하는 그래프인 박스플롯 그래프에 대해서 스터디를 해보자.​​​박스...

blog.naver.com

 

그렇다면!!

박스플롯으로 시각화 된 이상값들을 파이썬을 통해 실제적으로 검출해보는 작업을 해보자.

 

 

파이썬 IQR 방식 이상치 탐지

위에서 IQR 이상치 탐지 개념을 설명해놓았으므로 그것을 반영한 이상치 탐지 함수를 정의해준다.

 

def outlier_iqr(data, column): 

    # lower, upper 글로벌 변수 선언하기     
    global lower, upper    
    
    # 4분위수 기준 지정하기     
    q25, q75 = np.quantile(data[column], 0.25), np.quantile(data[column], 0.75)          
    
    # IQR 계산하기     
    iqr = q75 - q25    
    
    # outlier cutoff 계산하기     
    cut_off = iqr * 1.5          
    
    # lower와 upper bound 값 구하기     
    lower, upper = q25 - cut_off, q75 + cut_off     
    
    print('IQR은',iqr, '이다.')     
    print('lower bound 값은', lower, '이다.')     
    print('upper bound 값은', upper, '이다.')    
    
    # 1사 분위와 4사 분위에 속해있는 데이터 각각 저장하기     
    data1 = data[data[column] > upper]     
    data2 = data[data[column] < lower]    
    
    # 이상치 총 개수 구하기
    return print('총 이상치 개수는', data1.shape[0] + data2.shape[0], '이다.')
    

 

이렇게 이상치 탐지 함수를 생성해준다.

 

 

그럼 타이타닉 데이터셋을 불러와서 이상치 탐지하고 싶은 변수에 적용을 해보자.

 

titanic = sns.load_dataset('titanic') 

titanic.head(10)

 

 

 

위에서 박스플롯 이상치 예는 'age'를 기준으로 설명을 하였지만, 실제적인 적용은 'fare' 변수로 해보려고 한다.

 

outlier_iqr(titanic,'fare')

out :

IQR은 23.0896 이다.

lower bound 값은 -26.724 이다.

upper bound 값은 65.6344 이다.

총 이상치 개수는 116 이다.

 

>> IQR 방식을 사용하여 타이타닛 데이터셋의 'fare' 변수의 이상치를 탐지한 결과 총 891 관측치 중에서 이상값으로 탐지된 데이터는 116개로 계산되었다.

 

이상치 탐지 후 어떤 방식으로 처리할지는 다음에 다룰 예정이긴 하지만 만약 삭제하는 경우라고 가정하겠다.

이상값이 아닌 데이터들을 저장한다면 다음과 같이 작업해주면 된다.

 

data = data[(data['fare'] < upper) & (data['fare'] > lower)]

len(data)

>> 이상값들을 제외한 데이터 개수는 총 775이 되었다.

 

 

IQR 이상치 범위 displot 시각화

이상치로 탐지된 영역을 박스플롯이 아닌 displot으로 시각화해보자.

해당 범위에 관한 데이터 분포를 더 상세하게 살펴볼 수 있다.

plt.figure(figsize=(10,5))

sns.distplot(titanic.fare, kde=False)


# 이상치 영역 박스 그리기

plt.axvspan(xmin=lower, xmax=titanic.fare.min(), alpha=0.2, color='red')

plt.axvspan(xmin=upper, xmax=titanic.fare.max(), alpha=0.2, color='red')

 

 

displot 그래프로 시각화해서 확인해보니 확실히 'fare' 변수의 4사 분위에 속하는 이상값의 영역이 굉장히 넓게 퍼져있음을 알 수 있다. 

seaborn의 displot 그래프 위에 이상값에 해당하는 영역은 matplotlib의 axvspan로 범위를 지정하여 투명도를 적용하여 레이어링 후 시각화해주었다.

 

[파이썬 seaborn distplot 그리기 참고]

 

[데이터시각화] 파이썬 seaborn : 시각화 유형 : 분포(Distribution) - 1) 히스토그램(histogram) 그래프의

​데이터시각화 카테고리에 본격적으로 처음 올려보는 포스팅은 시각화 유형 중 분포에 해당하는 히스토그...

blog.naver.com

 

 

저 빨간 영역의 이상치들을 전부 삭제할 것인지 다른 처리를 해줄 것인지는 데이터 분석 상황에 따라 달라질 것이다.

오늘은 이상치들을 핸들링하는 것을 포함하는 것이 아니므로 그것에 관련하여는 다음번에 포스팅을 하도록 하겠다.

당분간 파이썬 이상치 탐지 방법 시리즈로만 포스팅하려고 한다 :)

 

 

참고문헌

  • Chris Albon - Machine Learning with Python Cookbook_ Practical Solutions from Preprocessing to Deep Learning-O’Reilly Media (2018) : 4.6 Detecting Outliers
  • colingorrie.github.io/outlier-detection.html#fn:1
728x90