바이올린 플롯 소개
바이올린 플롯(Violin Plot)은 데이터의 분포 형태와 밀도를 동시에 보여주는 고급 시각화 기법입니다. 이 그래프는 상자 수염 그림(Box Plot)과 커널 밀도 추정(KDE, Kernel Density Estimation)을 결합하여, 중심 경향성뿐 아니라 전체적인 분포 모양까지 직관적으로 전달합니다. 특히 다중 피크(multimodal)를 가진 데이터셋에서 그 유용성이 두드러집니다.
바이올린의 외곽선은 KDE 곡선을 좌우 대칭으로 확장한 형태로, 넓은 부분일수록 해당 값 근처에 많은 데이터가 집중되어 있음을 의미합니다. 내부에는 상자 수염 그림 요소가 포함되어 있어 사분위수, 중앙값, 이상치 범위 등을 함께 표현할 수 있습니다.
상자 수염 그림과의 비교
상자 수염 그림은 최소값, 제1사분위수(Q1), 중앙값(Q2), 제3사분위수(Q3), 최대값 및 이상치를 명확히 보여주지만, 데이터가 정규분포인지, 이중봉우리(bimodal) 형태인지 여부는 파악하기 어렵습니다. 반면 바이올린 플롯은 이러한 한계를 극복하여, 예를 들어 두 개의 뚜렷한 밀도 피크를 갖는 분포에서도 그 특성을 명확히 드러냅니다.
아래 코드는 표준 정규분포와 이중 정규 혼합분포에 대해 히스토그램+밀도곡선, 상자 수염 그림, 바이올린 플롯을 비교하는 예제입니다.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# 폰트 설정
plt.rcParams['font.family'] = 'DejaVu Sans'
def visualize_distribution(data, title):
fig, axes = plt.subplots(3, 1, figsize=(8, 6), sharex=True)
# 히스토그램 + KDE
sns.histplot(data, kde=True, ax=axes[0])
axes[0].set_title("Histogram with KDE")
axes[0].set_ylabel("Count")
# 상자 수염 그림
sns.boxplot(x=data, ax=axes[1])
axes[1].set_title("Box Plot")
axes[1].set_ylabel("Value")
# 바이올린 플롯
sns.violinplot(x=data, ax=axes[2])
axes[2].set_title("Violin Plot")
axes[2].set_xlabel("Data Values")
axes[2].set_ylabel("Density")
fig.suptitle(title, fontsize=14)
plt.tight_layout()
plt.show()
# 표준 정규분포 샘플 생성
normal_sample = np.random.normal(loc=0, scale=1, size=5000)
visualize_distribution(normal_sample, "Standard Normal Distribution")
# 이중 정규 혼합분포 생성
bimodal_sample = np.concatenate([
np.random.normal(loc=-2, scale=0.8, size=2500),
np.random.normal(loc=2, scale=0.8, size=2500)
])
visualize_distribution(bimodal_sample, "Bimodal Distribution")
Matplotlib을 이용한 바이올린 플롯 작성
Matplotlib의 violinplot 함수는 세밀한 제어가 가능하며, 다양한 옵션을 제공합니다.
fig, ax = plt.subplots(figsize=(7, 5))
result = ax.violinplot(
dataset=[normal_sample, bimodal_sample],
positions=[1, 2],
vert=False,
widths=0.7,
showmeans=False,
showmedians=True,
quantiles=[[0.25, 0.75], [0.25, 0.75]],
points=200,
bw_method='scott'
)
# 스타일 조정
for pc in result['bodies']:
pc.set_facecolor('#D4EDDA')
pc.set_edgecolor('#28A745')
pc.set_alpha(0.7)
result['cmedians'].set_color('red')
result['cmedians'].set_linewidth(2)
ax.set_yticks([1, 2])
ax.set_yticklabels(['Normal', 'Bimodal'])
ax.set_title('Customized Violin Plot using Matplotlib')
ax.grid(axis='x', linestyle='--', alpha=0.6)
plt.show()
반환값 result는 각 구성 요소(PolyCollection, LineCollection 등)를 담은 딕셔너리이며, 이를 통해 각 요소의 색상, 두께, 투명도 등을 개별적으로 수정할 수 있습니다.
Seaborn을 통한 시각화
Seaborn은 더 간결하고 미적으로 우수한 출력을 제공하며, 판다스 데이터프레임과 자연스럽게 연동됩니다.
import pandas as pd
# 데이터 준비
df = pd.DataFrame({
'Values': np.concatenate([normal_sample, bimodal_sample]),
'Group': ['Normal'] * len(normal_sample) + ['Bimodal'] * len(bimodal_sample)
})
# 바이올린 플롯 생성
plt.figure(figsize=(8, 5))
sns.violinplot(
data=df,
x='Group',
y='Values',
palette='Blues',
inner='quartile',
linewidth=1.2,
saturation=0.8
)
plt.title('Violin Plot using Seaborn')
plt.xlabel('Distribution Type')
plt.ylabel('Sample Values')
plt.grid(axis='y', alpha=0.3)
plt.show()
Seaborn의 주요 장점은 hue 매개변수를 통한 그룹 비교, 자동 조정된 색상 팔레트, 그리고 통계적 내부 마커(inner='box', 'quartile', 'point')의 지원입니다.