HOWTO · Seaborn
이상치가 없는 Seaborn Boxplot
showfliers=False를 사용해 이상치 마커 없이 Seaborn 상자 그림을 만들고, Seaborn이 이상치를 표시하는 1.5 x IQR 규칙을 이해하며, 대신 이상치 값을 제거하거나 상한 처리하는 것이 정당화되는 경우를 확인하세요.
이 페이지의 내용
이 기사는 상자 그림과 이상치가 무엇인지, 그리고 이상치 마커 없이 Seaborn 상자 그림을 만드는 방법을 보여주는 것을 목표로 합니다. 대부분의 경우 올바른 답은 데이터를 삭제하는 것이 아니라 마커를 숨기는 것입니다 — 아래 섹션에서는 두 가지를 모두 보여주고, 실제로 값을 제거하거나 상한 처리하는 것이 정당화되는 경우를 설명합니다.
이상치 마커 없이 Seaborn 상자 그림 만들기
상자 그림은 사분위수를 이용해 분포를 요약합니다. 상자는 제1사분위수(Q1)부터 제3사분위수(Q3)까지에 걸쳐 있고 그 안에 중앙값이 있으며, 수염은 이상치로 간주되지 않는 가장 극단적인 값까지 확장됩니다. 수염 너머의 점들은 이상치 마커(flier)로 개별적으로 그려집니다.
Seaborn 라이브러리에 이미 미리 로드되어 있는 tips 데이터 세트로 작업하겠습니다. 필요한 패키지를 가져오고 데이터를 살펴보겠습니다. 이 데이터 세트는 여러 열이 있는 레스토랑에 관한 것입니다.
import seaborn as sb
import matplotlib.pyplot as plt
import pandas as pd
TIPS = sb.load_dataset("tips")
TIPS.head()
기본값으로 total_bill 열을 그리면 오른쪽에 여러 개의 flier가 표시됩니다.
sb.boxplot(x=TIPS["total_bill"])
plt.show()
출력:
이상치 마커 없이 동일한 그림을 만들려면 showfliers=False를 전달하세요.
sb.boxplot(x=TIPS["total_bill"], showfliers=False)
plt.show()
출력:
Seaborn이 이상치로 표시하는 값 이해하기
Seaborn은 (Matplotlib을 통해) 어떤 점이 사분위수로부터 1.5 × IQR 너머에 있을 때 그 점을 이상치로 표시합니다. 여기서 IQR은 Q3 − Q1입니다. 수염은 그 울타리 안에 여전히 있는 가장 극단적인 데이터 포인트까지 도달하며, 그 밖에 있는 모든 것은 flier로 그려집니다.
이 규칙은 total_bill에 대해 describe() 함수로 재현할 수 있습니다. 이 함수는 이 열에 대해 Q1 = 13.35, 중앙값 = 17.80, Q3 = 24.13을 보고합니다. 따라서 IQR은 10.78이므로, 울타리는 13.35 − 1.5 × 10.78 = −2.82와 24.13 + 1.5 × 10.78 = 40.30입니다. 244개의 청구서 중 9개가 위쪽 울타리 위에 있으며(최댓값은 50.81), 그 9개의 점이 바로 첫 번째 그림의 flier입니다. 그것들은 데이터 오류가 아니라는 점에 유의하세요 — 레스토랑 기록에서 가장 큰 청구서일 뿐입니다.
showfliers=False로 이상치 마커 숨기기
showfliers=False는 그려지는 것만 변경합니다. 상자, 중앙값, 수염은 이상치를 포함하여 전체 데이터로부터 이전과 똑같이 계산되며, flier 마커는 단순히 렌더링되지 않습니다. 또한 그림은 멀리 떨어진 점들을 수용하기 위해 더 이상 늘어나지 않으므로, 상자와 수염을 더 쉽게 읽을 수 있습니다.
이상치가 유효한 데이터이고 목표가 프레젠테이션일 때 — 예를 들어, 몇 개의 극단적인 값이 그림의 나머지를 압축할 때 — 이 옵션을 선택하세요. 데이터 세트나 통계는 아무것도 변하지 않으므로, 추가로 정당화하거나 공개할 것이 없습니다.
분석상 필요한 경우에만 이상치 값을 제거하거나 상한 처리하기
때로는 그림이 아니라 분석 자체가 변경되어야 합니다. 센서 오류, 데이터 입력 오류, 또는 소수의 극단적인 값으로 왜곡되는 모델 등이 그 경우입니다. 그럴 때만 값을 변경해야 하며, 이후에 보고하는 통계는 변경된 데이터를 기준으로 계산하고 그 사실을 명시해야 합니다.
이상치를 제거하려면, Seaborn이 사용하는 것과 동일한 울타리로 필터링하세요(사분위수 값 자체로 필터링하지 마세요 — Q1과 Q3 사이의 범위로 필터링하면 양쪽에서 유효한 데이터의 4분의 1이 버려집니다).
q1 = TIPS["total_bill"].quantile(0.25)
q3 = TIPS["total_bill"].quantile(0.75)
iqr = q3 - q1
filtered = TIPS[(TIPS["total_bill"] >= q1 - 1.5 * iqr) & (TIPS["total_bill"] <= q3 + 1.5 * iqr)]
sb.boxplot(x=filtered["total_bill"])
plt.show()
대신 이상치를 상한 처리(윈저화)하려면 — 모든 행을 유지하면서 극단적인 값을 울타리까지 끌어당기려면 — clip을 사용하세요.
capped = TIPS["total_bill"].clip(lower=q1 - 1.5 * iqr, upper=q3 + 1.5 * iqr)
sb.boxplot(x=capped)
plt.show()
출력:
두 연산 모두 데이터를 변경합니다. 제거하면 가장 큰 청구서 9개가 완전히 사라지고, 상한 처리하면 그 값들이 40.30으로 다시 쓰입니다. 그 값들을 신뢰할 수 없거나 제한해야 할 이유가 있을 때 사용하세요 — 그리고 단지 더 깔끔한 차트를 원했던 것뿐이라면, showfliers=False로 돌아가서 데이터는 그대로 두세요.