< 데이터 이상치/이상값 >
이상치는 특정 범위를 벗어난 튀는 데이터이며 데이터 분석에 영향을 줄 수 있어 보통 제거하는 편이다.
하지만 경우에 따라 보류하고 별도 분석을 진행할 수도 있다.
데이터 전처리를 어떻게 할 것이냐는 분석 목적, 상황 등에 따라 다르다.
이상치는 데이터 입력 오류, 측정 오류, 실험 오류, 고의적인 이상값, 표본추출 에러 등에서 발생할 수 있으며, 소비자 조사 같은 경우 간혹 정말 특이한 특성을 가진 고객이라 일반적 범위에서 많이 벗어난 경우도 있다.
예를 들어, 대부분이 연봉 4000 - 6000만원인데 2억 이상인 경우 등.
이상치를 알아내기 가장 쉬운 방법은 시각화를 통해서 한 눈에 보는 방법인 것 같다.
개인적으로 그 중 제일 편한 방법은 박스플롯 (상자수염그림) 사용인 것 같다.
박스플롯은 최솟값, 3개의 사분위수 (25%, 50%, 75%), 최댓값으로 데이터를 요약하는 그래프로, 데이터가 어떤 방향으로 더 많이 늘어져 있는지 한 눈에 파악 가능하며 이상치 또한 함께 표현이 된다.
파이썬을 사용하여 박스플롯을 만들려면 우선 시각화 모듈을 불러와야한다.
Matplotlib, Seaborn 등을 불러와야 하는데, 가장 기본이 되는 Matplotlib 을 사용하여 박스플롯을 만들어보겠다.
사용할 데이터는 지난번 데이터 전처리에서 결측값 처리하는 방법을 다룬 글에서 사용한 Kaggle 타이타닉 데이터 세트를 사용하겠다.
< 파이썬 describe 메서드로 데이터 분포 확인 >
Matplotlib을 그리기 전에 우선 describe() 메서드로 데이터 분포부터 확인해보자
data3['Fare'].describe() # data3 데이터프레임의 Fare 열에 대한 데이터 정보 확인
결과값으로 Fare 열에는 총 418개의 데이터 인풋이 있다.
그리고 통계량은 아래와 같다:
- 평균: 35.57
- 표준편차: 55.85
- 최솟값: 0
- 25% 구간: 7.90
- 50% 구간: 14.45
- 75% 구간: 31.57
- 최댓값: 512.33
평균, 표준편차, 50% 구간 (중간값), 75% 구간과 최댓값을 보면 알 수 있듯이 범위에서 심각하게 벗어난 이상치가 있다는 것을 머리속에 그릴 수 있다.
이제 머리속으로 그리고 있는 데이터 분포를 Matplotlib 의 박스플롯을 사용하여 그려보자
< 파이썬 Matplotlib 으로 박스플롯 그리기 >
Maplotlib 으로 박스플롯을 그리는 방법은 아주 간단하다.
1. Matplotlib 임포트하기
2. Matplotlib 코드 넣고 돌리기
import matplotlib.pyplot as plt # maplotlib의 pyplot 모듈을 plt 라는 별칭으로 불러오고
plt.boxplot(data3['Fare') # data3의 'Fare' 열을 기준으로 boxplot 그리기
plt.title('Boxplot - Fare') # 그래프 제목 (불필요하면 스킵해도 됨)
plt.xlabel('') # x 축 라벨
plt.ylabel('USD') # y 축 라벨
plt.show() # 그래프 제시
위에서 확인한 최댓값이 512.33 이었는데 박스플롯에서도 이 값은 혼자 멀찍이 떨어져 찍혀 있는 게 보인다.
앞단에서 설명했듯 박스플롯에서 이상치는 IQR(25%~75% 구간) 에서 위, 아래로 1.5배씩 떨어진 곳에 있는 데이터다.
즉, 이상치는 제1사분위수 - (IQR*1.5) 과 제3사분위수 + (IQR*1.5) 이다.
이렇게 '일반적 범위'를 벗어난 이상치는 박스플롯의 수염(위스커) 밖에 o 표기로 표현된다.
박스플롯을 가로로 보고 싶다면 vert=False 라는 조건을 추가해주면 된다.
plt.boxplot(data3['Fare'], vert=False) # 박스플롯 가로로 그리기기
plt.title('Boxplot - Fare')
plt.xlabel('USD') # vert=False 할 경우 x,y 축이 전환되기 때문에 이전 라벨과 반대로 넣어줘야함
plt.ylabel('')
plt.show()
보통 지정값으로 박스플롯의 수염의 길이는 IQR의 1.5배이다.
하지만 수염 길이를 조절하여 이상치의 기준을 다르게 볼 수도 있다.
whis=수염길이 조건을 코드에 추가해주면 된다.
# 수염길이=5.0 으로 변경하여 박스플롯 그리기
plt.boxplot(data3['Fare'], vert=False, whis=5.0) # 박스플롯 가로로 그리기기
plt.title('Boxplot - Fare')
plt.xlabel('USD')
plt.ylabel('')
plt.show()
whis 지정값이 1.5일 때와 5.0으로 변경된 후의 수염길이와 이상치 분포가 다른 것을 확인할 수 있다.
한 번에 여러 박스플롯을 그릴 수도 있다.
이 때, 동일한 단위를 기준으로 여러 그래프를 그릴 수도, 각 그래프 별로 적절한 단위에 맞춰 그려지도록 할 수도 있다.
전자의 경우 위에서 한 것과 비슷한 방식으로 추가하고자 하는 열만 코드에 넣어주면 된다.
후자의 경우 subplot 을 사용하여 그릴 수 있다.
< 동일한 단위에서 여러개의 박스플롯 그리기 >
같은 단위를 가진 데이터의 분포를 조건에 따라 비교해보기 위해 성별에 따른 Age 분포를 박스플롯으로 보도록 하겠다.
스텝은 아래와 같다.
1. 조건에 맞춰 데이터 필터링
성별에 맞춰 Age 데이터를 분리해야해서 male_age 와 female_age 로 변수를 만들고 조건에 맞게 필터링 해준다.
2. 필터링된 데이터를 박스플롯으로 그리기
male_age, female_age를 박스플롯에 데이터로 넣어주고, 각 그래프에 맞게 xticks 를 사용하여 그래프 라벨을 넣어준다
# 동일한 단위로 여러개의 박스플롯 그리기
# 성별에 따른 티켓 값 구분
# 셩별에 따라 데이터 필터링
male_age=data3[data3['Sex']=='male']['Age']
female_age=data3[data3['Sex']=='female']['Age']
# 박스 플롯 그리기기
plt.boxplot([male_age, female_age]) # 필터링한 성별에 따른 age 로 박스플롯 만들기
plt.xticks([1,2],['Male', 'Female']) # 각 그래프의 라벨을 Male, Female 로 넣기
plt.title('Age Distribution by Sex') # 제목
plt.ylabel('Age') # y 축 라벨
plt.show()
< 단위가 다른 여러개의 박스플롯 그리기 - subplots 사용>
한 번에 여러개의 그래프를 그리기 위해 subplots 함수를 사용할 수 있다.
subplots는 matplotlib의 axes 클래스의 객체를 말하며, 두 개 이상의 축을 포함한다.
figure 객체와 각 subplot을 나타내는 axes 객체의 배열을 반환하기 때문에
1. 사용 전에 figure, axes 에 대한 정보를 전달하고
2. 만들 각 그래프에 대한 내용을 순차적으로 넣어준다.
# 개별 스케일로 여러개의 박스플롯 그리기
# Fare, Age
fig, axes=plt.subplots(1,2, figsize=(16,8)) # (1,2) 형태의 그래프를 만들며, 사이즈는 16x8
# (1,2) ==> 1개의 행에 2개의 그래프가 들어가는 모습
# 첫 번째 그래프 그리기 - Fare
axes[0].boxplot(data3['Fare']) # 박스플롯을 그릴 기준 데이터
axes[0].set_title('Fare Distribution') # 제목
axes[0].set_ylabel('USD') # y축 라벨
# 두 번째 그래프 그리기 - Age
axes[1].boxplot(data3['Age']) # 박스플롯으로 그릴 기준 데이터
axes[1].set_title('Age Distribution') # 제목
axes[1].set_ylabel('Age') # y 축 라벨
참고로, subplots 으로는 그래프 종류도 모두 다르게 그릴 수 있다.
오늘 주제는 박스플롯이었기 때문에 박스플롯만 그려보았다.
'파이썬 - 분석 라이브러리' 카테고리의 다른 글
[파이썬] 데이터 전처리 | 데이터 정제, 결측값 처리 - isna().sum(), replace(), fillna() (0) | 2025.02.12 |
---|---|
[파이썬] Open() 함수, UnicodeDecodeError, chardet, chardet.detect() (0) | 2024.08.21 |
[파이썬] 시리즈/데이터프레임 인덱싱 - iloc, loc (0) | 2024.06.12 |
[파이썬] 데이터프레임 인덱스 수정 - set_index, reset_index, reindex, drop, index.name (0) | 2024.06.11 |
[파이썬] 데이터프레임 정보 확인 - info, describe, columns, count, unique, dtype, head (0) | 2024.06.10 |