이상치(Outlier)
이상치(Outlier)란 보통 관측된 데이터 범위에서 많이 벗어난 아주 작은 값 혹은 큰 값을 말하며 크게 2가지 기준이 있음
1. Extreme Studentized Deviation(ESD) 이용한 이상치 발견
- 데이터가 정규분포를 따른다고 가정할 때, 평균에서 표준편차의 3배 이상 떨어진 값
- 모든 데이터가 정규 분포를 따르지 않을 수 있기 때문에 다음 상황에서는 제한됨
- 데이터가 크게 비대칭일 때( → Log변환 등을 노려볼 수 있음)
- 샘플 크기가 작을 경우

1. IQR(Inter Quantile Range)를 이용한 이상치 발견
- ESD와 동일하게 데이터가 비대칭적이거나 샘플사이즈가 작은 경우 제한됨

코드를 통한 이상치 발견 방법
ESD를 이용한 처리
import numpy as np
mean = np.mean(data)
std = np.std(data)
upper_limit = mean + 3*std
lower_limit = mean - 3*std
IQR을 이용한 처리(box plot)
Q1 = df['column'].quantile(0.25)
Q3 = df['column'].qunatile(0.75)
IQR = Q3 - Q1
upper_limit = Q3 + 1.5*IQR
lower_limit = Q1 - 1.5*IQR
※이상치는 주관적인 값이므로 데이터의 삭제 여부는 분석가가 해야 할 일이다. 다만 도메인과 비즈니스 맥락에 따라 기준이 달라지며 삭제할 경우 데이터의 품질이 좋아질수 있으나 그와 동시에 정보 손실이 동반되므로 이상치 처리에 주의해야 한다.
실습(Seaborn 라이브러리에서 tips 데이터 활용)
ESD 이상치 처리
import numpy as np
mean = np.mean(tips_df['total_bill'])
std = np.std(tips_df['total_bill'])
upper_limit = mean + 3*std
lower_limit = mean - 3*std
print(upper_limit, lower_limit)
최대값 46.43839435626422 최소값 -6.866509110362578
#boleen을 통한 조건 필터링
cond = (tips_df['total_bill'] > 46.4)
cond
0 False
1 False
2 False
3 False
4 False
...
239 False
240 False
241 False
242 False
243 False
Name: total_bill, Length: 244, dtype: bool
※True 값(이상치) 확인
#total_bill이 46보다 큰 값(이상치) 확인
tips_df[cond]
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
| 156 | 48.17 | 5.00 | Male | No | Sun | Dinner | 6 |
| 170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
| 212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |
IQR을 이용한 이상치 확인
#boxplot으로 그래프 확인
import seaborn as sns
sns.boxplot(tips_df['total_bill'])

Q1 = tips_df['total_bill'].quantile(0.25)
Q3 = tips_df['total_bill'].quantile(0.75)
IQR = Q3 - Q1
upper_limit2 = Q3 + 1.5*IQR
lower_limit2 = Q1 - 1.5*IQR
print(Q1, Q3, IQR, upper_limit2, lower_limit2)
Q1 = 13.3475 (박스 윗변 값)
Q3 = 24.127499999999998(박스 아랫변 값)
IQR = 10.779999999999998(박스 높이)
upper_limit2 = 40.29749999999999(최대값)
lower_limit2 = -2.8224999999999945(최소값)
#이상치 찾기
cond2 = (tips_df['total_bill'] > upper_limit2)
cond2
0 False
1 False
2 False
3 False
4 False
...
239 False
240 False
241 False
242 False
243 False
Name: total_bill, Length: 244, dtype: bool
※True 값(이상치) 확인
##total_bill이 40보다 큰 값(이상치) 확인
tips_df[cond2]
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
| 102 | 44.30 | 2.50 | Female | Yes | Sat | Dinner | 3 |
| 142 | 41.19 | 5.00 | Male | No | Thur | Lunch | 5 |
| 156 | 48.17 | 5.00 | Male | No | Sun | Dinner | 6 |
| 170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
| 182 | 45.35 | 3.50 | Male | Yes | Sun | Dinner | 3 |
| 184 | 40.55 | 3.00 | Male | Yes | Sun | Dinner | 2 |
| 197 | 43.11 | 5.00 | Female | Yes | Thur | Lunch | 4 |
| 212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |