Seaborn 박스플롯: Python에서 박스 플롯을 생성하고 사용자 정의하는 방법
Updated on
데이터가 어떻게 분포되어 있는지 이해하는 것은 데이터 분석에서 가장 기본적인 작업 중 하나입니다. 모델을 실행하거나 결론을 도출하기 전에 이상값을 발견하고, 그룹을 비교하고, 편향을 식별해야 합니다. 하지만 DataFrame의 원시 숫자를 응시하는 것만으로는 전체 그림을 얻기 어렵습니다. seaborn 박스플롯은 전체 분포를 중앙값, 분산 및 이상값을 한눈에 보여주는 간결하고 읽기 쉬운 그래픽으로 압축하여 이 문제를 해결합니다.
이 가이드에서는 Python의 seaborn 라이브러리를 사용하여 박스 플롯을 생성, 사용자 정의 및 해석하는 방법을 배웁니다. 모든 코드 예제는 seaborn에 내장된 실제 데이터셋을 사용하므로 Jupyter 노트북에서 즉시 실행할 수 있습니다.
박스 플롯이란?
박스 플롯(상자 수염 그림이라고도 함)은 다섯 가지 요약 통계를 기반으로 분포를 표시하는 표준화된 방법입니다:
| 구성 요소 | 의미 |
|---|---|
| 중앙값 선 | 데이터셋의 중간값(50번째 백분위수) |
| 박스(IQR) | 사분위수 범위, Q1(25번째 백분위수)에서 Q3(75번째 백분위수)까지 |
| 하단 수염 | Q1 - 1.5 * IQR 범위 내의 가장 작은 데이터 포인트 |
| 상단 수염 | Q3 + 1.5 * IQR 범위 내의 가장 큰 데이터 포인트 |
| 이상값 포인트 | 수염 범위 밖에 있는 개별 데이터 포인트 |
박스는 데이터의 중간 50%를 포착합니다. 높은 박스는 높은 변동성을 의미하고, 낮은 박스는 값이 밀집되어 있음을 의미합니다. 중앙값 선이 박스 내에서 중심에서 벗어나 있으면 분포가 편향되어 있습니다. 수염 너머의 점은 조사할 가치가 있는 잠재적 이상값을 표시합니다.
여러 범주의 분포를 나란히 비교해야 할 때 박스 플롯이 특히 효과적이므로 탐색적 데이터 분석의 필수 요소가 됩니다.
기본 Seaborn 박스플롯 구문
seaborn에서 박스플롯을 생성하려면 sns.boxplot()이라는 하나의 함수만 필요합니다. 최소한 데이터를 전달하고 플롯할 변수를 지정합니다.
import seaborn as sns
import matplotlib.pyplot as plt
# 내장 데이터셋 로드
tips = sns.load_dataset("tips")
# 기본 수직 박스플롯
sns.boxplot(data=tips, y="total_bill")
plt.title("총 청구액 분포")
plt.show()이것은 total_bill 값의 분포를 보여주는 단일 박스를 생성합니다. 함수는 사분위수, 수염 및 이상값을 자동으로 계산합니다.
범주형 변수로 데이터를 분할하려면 x 매개변수를 추가합니다:
sns.boxplot(data=tips, x="day", y="total_bill")
plt.title("요일별 총 청구액")
plt.show()이제 나란히 네 개의 박스를 볼 수 있으며, 각 요일에 하나씩 표시되어 한 주 동안의 지출 패턴을 쉽게 비교할 수 있습니다.
다양한 데이터 형식에서 박스플롯 생성
Seaborn은 여러 데이터 형식을 우아하게 처리합니다. 다음은 가장 일반적인 시나리오입니다.
롱 형식 DataFrame(정돈된 데이터)
대부분의 seaborn 함수는 각 행이 단일 관찰이고 열이 변수를 나타내는 롱 형식(정돈된) 데이터에서 가장 잘 작동합니다. tips 데이터셋은 이미 이 형식입니다:
# 롱 형식: 각 행은 한 번의 레스토랑 방문
sns.boxplot(data=tips, x="day", y="total_bill")
plt.show()와이드 형식 DataFrame
데이터가 그룹당 하나의 열(와이드 형식)인 경우에도 seaborn은 직접 박스플롯을 생성할 수 있습니다:
import pandas as pd
import numpy as np
# 와이드 형식 데이터 생성
np.random.seed(42)
wide_df = pd.DataFrame({
"Group A": np.random.normal(50, 10, 100),
"Group B": np.random.normal(60, 15, 100),
"Group C": np.random.normal(45, 8, 100),
})
sns.boxplot(data=wide_df)
plt.title("세 그룹 비교(와이드 형식 데이터)")
plt.ylabel("값")
plt.show()Seaborn은 자동으로 각 열을 별도의 범주로 취급하고 나란히 플롯합니다.
특정 DataFrame 열 선택
더 큰 DataFrame에서 특정 숫자 열만 시각화하려면 먼저 필터링합니다:
iris = sns.load_dataset("iris")
# 측정 열만 선택
measurement_cols = iris[["sepal_length", "sepal_width", "petal_length", "petal_width"]]
sns.boxplot(data=measurement_cols)
plt.title("아이리스 특징 분포")
plt.xticks(rotation=15)
plt.show()Seaborn 박스플롯 사용자 정의
Seaborn은 박스 플롯의 모양과 동작을 조정하기 위한 광범위한 옵션을 제공합니다.
색상과 팔레트
palette 매개변수를 사용하여 색 구성표를 변경하거나 모든 박스에 단일 색을 설정합니다:
# 명명된 팔레트 사용
sns.boxplot(data=tips, x="day", y="total_bill", palette="Set2")
plt.title("사용자 정의 팔레트")
plt.show()# 모든 박스에 단일 색상
sns.boxplot(data=tips, x="day", y="total_bill", color="skyblue")
plt.title("균일한 색상")
plt.show()인기 있는 팔레트 옵션에는 "Set2", "pastel", "muted", "deep", "husl", "coolwarm"이 있습니다.
수평 vs 수직 방향
가로 박스플롯을 생성하려면 축을 바꿉니다. 범주 레이블이 길 때 유용합니다:
sns.boxplot(data=tips, x="total_bill", y="day", orient="h")
plt.title("수평 박스플롯")
plt.show()hue 매개변수를 사용한 그룹화된 박스플롯
hue 매개변수는 각 범주를 하위 그룹으로 분할하여 비교에 두 번째 차원을 추가합니다:
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex")
plt.title("요일 및 성별별 총 청구액")
plt.legend(title="성별")
plt.show()이제 각 요일에 두 개의 박스(성별당 하나)가 표시되어 일주일 내내 남성과 여성의 지출 패턴을 간단하게 비교할 수 있습니다.
그림 크기 제어
Seaborn 플롯은 matplotlib에서 그림 크기를 상속합니다. sns.boxplot()을 호출하기 전에 설정합니다:
plt.figure(figsize=(12, 6))
sns.boxplot(data=tips, x="day", y="total_bill", hue="smoker", palette="muted")
plt.title("요일 및 흡연 상태별 총 청구액")
plt.show()스웜 또는 스트립 플롯 오버레이 추가
박스플롯은 분포를 요약하지만 개별 데이터 포인트를 숨깁니다. 모든 관찰을 표시하려면 스웜 플롯 또는 스트립 플롯을 오버레이합니다:
plt.figure(figsize=(10, 6))
sns.boxplot(data=tips, x="day", y="total_bill", palette="pastel")
sns.stripplot(data=tips, x="day", y="total_bill", color="0.3", size=3, jitter=True, alpha=0.5)
plt.title("스트립 플롯 오버레이가 있는 박스플롯")
plt.show()plt.figure(figsize=(10, 6))
sns.boxplot(data=tips, x="day", y="total_bill", palette="pastel")
sns.swarmplot(data=tips, x="day", y="total_bill", color="0.25", size=3, alpha=0.6)
plt.title("스웜 플롯 오버레이가 있는 박스플롯")
plt.show()스웜 플롯은 점이 겹치지 않도록 배치하여 데이터 밀도를 더 잘 파악할 수 있습니다. 데이터 포인트가 많을 때는 스트립 플롯을 사용하고, 적을 때는 스웜 플롯을 사용합니다(스웜 플롯은 수천 개의 포인트에서 느려질 수 있음).
Seaborn 박스플롯 매개변수 참조
다음은 sns.boxplot()에서 가장 일반적으로 사용되는 매개변수에 대한 빠른 참조입니다:
| 매개변수 | 유형 | 설명 |
|---|---|---|
data | DataFrame, 배열 또는 리스트 | 입력 데이터 구조 |
x, y | str 또는 배열 | 축의 변수 |
hue | str | 색상 코딩된 하위 그룹의 그룹화 변수 |
order | str 리스트 | 범주 수준을 플롯하는 순서 |
hue_order | str 리스트 | hue 수준의 순서 |
orient | "v" 또는 "h" | 플롯의 방향 |
color | str | 모든 요소에 대한 단일 색상 |
palette | str, 리스트 또는 딕셔너리 | 다른 수준의 색상 |
saturation | float | 원래 채도의 비율(0에서 1) |
fill | bool | 색상으로 박스를 채울지 여부(seaborn >= 0.13) |
width | float | 박스의 너비(기본값 0.8) |
dodge | bool | 범주 축을 따라 hue 그룹을 이동할지 여부 |
fliersize | float | 이상값 마커의 크기 |
linewidth | float | 박스를 둘러싼 선의 너비 |
whis | float 또는 튜플 | IQR의 배수로서의 수염 길이(기본값 1.5) |
ax | matplotlib Axes | 플롯을 그릴 Axes 객체 |
분포 비교
여러 열을 나란히
여러 숫자 특징의 분포를 비교할 때는 DataFrame을 롱 형식으로 변환합니다:
iris = sns.load_dataset("iris")
# 와이드에서 롱 형식으로 변환
iris_long = iris.melt(id_vars="species", var_name="measurement", value_name="cm")
plt.figure(figsize=(12, 6))
sns.boxplot(data=iris_long, x="measurement", y="cm", palette="Set3")
plt.title("아이리스 측정값 비교")
plt.show()hue를 사용한 그룹 비교
범주와 그룹화 변수를 모두 결합하여 두 차원에 걸쳐 분포를 비교합니다:
plt.figure(figsize=(14, 6))
sns.boxplot(data=iris_long, x="measurement", y="cm", hue="species", palette="husl")
plt.title("품종별 아이리스 측정값")
plt.legend(title="품종", bbox_to_anchor=(1.05, 1), loc="upper left")
plt.tight_layout()
plt.show()이것은 각 측정 유형이 세 개의 박스(품종당 하나)를 표시하는 그룹화된 박스플롯을 생성하여 품종 간 비교를 즉시 가능하게 합니다.
Seaborn 박스플롯 vs Matplotlib 박스플롯
seaborn과 matplotlib 모두 박스 플롯을 생성할 수 있지만 사용 편의성과 시각적 품질에서 크게 다릅니다.
| 기능 | Seaborn sns.boxplot() | Matplotlib ax.boxplot() |
|---|---|---|
| 기본 미학 | 세련되고 출판 가능 | 기본, 최소 스타일링 |
| DataFrame 통합 | pandas DataFrame 기본 지원 | 수동으로 배열 추출 필요 |
| Hue 그룹화 | 내장 hue 매개변수 | 수동 위치 지정 및 색상 지정 |
| 팔레트 | 한 줄로 팔레트 할당 | 수동 색상 리스트 관리 |
| 통계 주석 | 스웜/스트립 플롯의 쉬운 오버레이 | 수동 산점 오버레이 필요 |
| 사용자 정의 깊이 | 중간(matplotlib에 위임) | 완전한 저수준 제어 |
| 학습 곡선 | 낮음 | 중간에서 높음 |
| 코드 장황함 | 그룹화된 플롯에 1-2줄 | 동등한 것에 10-20줄 |
결론: 빠른 탐색적 분석과 깔끔한 시각화에는 seaborn을 사용하세요. 모든 요소에 대해 픽셀 수준의 제어가 필요할 때는 matplotlib로 돌아가세요.
# Matplotlib 박스플롯(더 장황함)
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 5))
data_by_day = [tips[tips["day"] == d]["total_bill"].values for d in ["Thur", "Fri", "Sat", "Sun"]]
bp = ax.boxplot(data_by_day, labels=["Thur", "Fri", "Sat", "Sun"], patch_artist=True)
for patch, color in zip(bp["boxes"], ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072"]):
patch.set_facecolor(color)
ax.set_title("Matplotlib 박스플롯(수동 스타일링)")
ax.set_ylabel("총 청구액")
plt.show()# Seaborn 동등품(간결함)
sns.boxplot(data=tips, x="day", y="total_bill", palette="Set3",
order=["Thur", "Fri", "Sat", "Sun"])
plt.title("Seaborn 박스플롯(한 줄)")
plt.show()박스 플롯 vs 바이올린 플롯: 언제 무엇을 사용할까
Seaborn은 sns.violinplot()도 제공하며, 이는 요약 통계만이 아니라 분포의 전체 밀도 형태를 보여줍니다. 각각을 선택하는 경우는 다음과 같습니다:
| 기준 | 박스 플롯 | 바이올린 플롯 |
|---|---|---|
| 최적 용도 | 빠른 요약 통계 및 이상값 탐지 | 분포의 전체 형태 이해 |
| 이상값 표시 | 예, 개별 점으로 | 아니요(밀도 곡선에 흡수됨) |
| 이봉성 표시 | 아니요 | 예(두 개의 돌출부로 표시) |
| 가독성 | 높음, 비기술 청중에게도 | 더 많은 설명 필요 |
| 공간 효율성 | 컴팩트 | 더 넓고 더 많은 수평 공간 차지 |
| 성능 | 빠른 렌더링 | 대규모 데이터셋에서 느림(KDE 계산) |
경험 법칙: 빠른 확인을 위해 박스플롯으로 시작하세요. 분포에 여러 피크 또는 비정상적인 형태가 있다고 의심되면 바이올린 플롯으로 전환하세요.
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
sns.boxplot(data=tips, x="day", y="total_bill", palette="Set2", ax=axes[0])
axes[0].set_title("박스 플롯")
sns.violinplot(data=tips, x="day", y="total_bill", palette="Set2", ax=axes[1])
axes[1].set_title("바이올린 플롯")
plt.tight_layout()
plt.show()대화형 대안: PyGWalker로 분포 탐색
정적 박스 플롯은 보고서와 노트북에 적합하지만 초기 탐색 단계에서는 매번 코드를 다시 작성하지 않고도 다른 변수를 차트에 넣고 빼고 싶을 때가 많습니다.
PyGWalker (opens in a new tab)는 Jupyter Notebook 내에서 직접 모든 pandas DataFrame을 대화형 Tableau와 유사한 시각적 탐색 인터페이스로 변환하는 오픈 소스 Python 라이브러리입니다. 필드를 축으로 드래그하기만 하면 박스 플롯, 바이올린 플롯, 히스토그램, 산점도 등을 만들 수 있습니다. 코드 변경이 필요하지 않습니다.
pip install pygwalkerimport pandas as pd
import pygwalker as pyg
tips = pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/tips.csv")
walker = pyg.walk(tips)UI가 로드되면 day를 X축으로, total_bill을 Y축으로 드래그한 다음 박스플롯 마크 유형을 선택합니다. 바이올린 플롯으로 즉시 전환하거나, 색상 차원을 추가하거나, 모든 열로 필터링할 수 있으며, 모두 한 줄의 추가 코드도 작성하지 않고 가능합니다.
이것은 모든 사람이 Python을 작성하는 것은 아닌 팀에 특히 유용합니다. 노트북을 공유하고 이해관계자들이 직접 데이터를 탐색하도록 하세요.
| Kaggle에서 PyGWalker 실행 (opens in a new tab) | Google Colab에서 PyGWalker 실행 (opens in a new tab) | GitHub의 PyGWalker (opens in a new tab) |
|---|
자주 묻는 질문
seaborn 박스플롯에서 이상값을 제거하려면 어떻게 해야 합니까?
whis 매개변수를 더 큰 값(예: whis=3.0)으로 설정하여 수염을 연장하고 이상값으로 표시되는 포인트 수를 줄입니다. 또는 flierprops={"marker": ""}를 설정하여 수염 계산을 변경하지 않고 이상값 마커를 완전히 숨깁니다.
DataFrame을 사용하지 않고 seaborn 박스플롯을 플롯할 수 있습니까?
예. 원시 배열이나 리스트를 직접 전달할 수 있습니다: sns.boxplot(x=["A"]*50 + ["B"]*50, y=np.random.randn(100)). 그러나 축 레이블이 자동으로 생성되므로 명명된 열이 있는 DataFrame을 사용하는 것이 좋습니다.
sns.boxplot에서 이상값 마커 스타일을 변경하려면 어떻게 해야 합니까?
flierprops 매개변수에 딕셔너리를 전달합니다: sns.boxplot(data=tips, x="day", y="total_bill", flierprops={"marker": "D", "markerfacecolor": "red", "markersize": 5}). 이렇게 하면 이상값 마커가 빨간색 다이아몬드로 변경됩니다.
seaborn 박스플롯에서 hue와 x의 차이점은 무엇입니까?
x 매개변수는 수평 축의 기본 범주 그룹을 정의합니다. hue 매개변수는 각 범주 내에 보조 그룹을 추가하여 나란히 배치된 색상 박스로 표시합니다. 간단한 비교에는 x만 사용하고 성별이나 상태와 같은 두 번째 변수로 각 범주를 분해하려면 hue를 추가합니다.
seaborn 박스플롯을 파일로 저장하려면 어떻게 해야 합니까?
플롯을 생성한 후 plt.savefig("boxplot.png", dpi=300, bbox_inches="tight")를 호출합니다. Seaborn 플롯은 내부적으로 matplotlib 그림이므로 모든 matplotlib 저장 메서드가 작동합니다. 지원되는 형식에는 PNG, PDF, SVG, EPS가 있습니다.
결론
seaborn 박스플롯은 데이터가 어떻게 분포되어 있는지 이해하고, 이상값을 발견하고, 그룹을 비교하는 가장 빠른 방법 중 하나입니다. sns.boxplot()을 사용하면 한 줄의 코드로 원시 DataFrame에서 출판 가능한 품질의 시각화로 이동할 수 있습니다. hue 매개변수는 추가 노력 없이 그룹화된 비교를 추가하며, 스트립 또는 스웜 플롯을 오버레이하면 박스 플롯이 추상화하는 개별 데이터 포인트 세부 정보를 채웁니다.
노트북 및 보고서의 정적 분석을 위해 seaborn 박스플롯은 능가하기 어렵습니다. pandas 데이터 위에 대화형 탐색 레이어가 필요할 때 PyGWalker (opens in a new tab)와 같은 도구를 사용하면 코드 변경 없이 시각화를 구축하고 반복할 수 있습니다.
위의 기본 예제로 시작하여 팔레트와 오버레이를 실험하면 모든 데이터 분포 질문에 대한 신뢰할 수 있는 시각적 도구 키트를 갖게 될 것입니다.