데이터 분포 시각화: 바이올린 플롯의 이해와 파이썬 구현

바이올린 플롯 소개

바이올린 플롯(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')의 지원입니다.

태그: python Data Visualization Violin Plot matplotlib Seaborn

5월 29일 00:06에 게시됨