본문 바로가기
데이터 분석/시각화

[상자 수염 그림(Box and Whisker Plot)] 2. Matplotlib을 이용하여 그룹 상자 수염 그림(박스 플롯) 그리기

by 부자 꽁냥이 2020. 12. 5.

안녕하세요~ 꽁냥이에요.

 

데이터 분석을 하다 보면 2개의 카테고리별로 범주를 나누고 해당 범주의 데이터 분포를 시각화해야 할 상황이 있지요. 이때 사용할 수 있는 그래프로 그룹 바 차트, 스택 바 차트, 또는 파이 그래프가 있습니다. 이에 대한 내용은 아래의 링크를 참고하세요.

 

Matplotlib을 이용하여 그룹 바 차트 그리기

Matplotlib을 이용하여 스택 바 차트 그리기

Matplotlib을 이용하여 하위 카테고리를 포함하는 파이 차트 그리기

 

이번 포스팅에서는 2개의 카테고리별로 데이터의 분포를 확인할 수 있는 그룹 상자 수염 그림(또는 박스 플롯)을 그리는 방법에 대하여 소개하겠습니다.


   그룹 상자 수염 그림(박스 플롯) 그리기

먼저 이번 포스팅에서 필요한 모듈을 임포트하고 데이터를 만들어보겠습니다.

 

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

import pandas as pd
import numpy as np
import seaborn as sns

from random import choices

data = {
    'Gender':choices(['male','female'],weights=[3,2],k=100),
    'Age':choices(['20','30','40','50','60'],k=100),
    'IQ':np.random.normal(120, 20, 100)
}
df = pd.DataFrame(data)

 

다음으로 박스 플롯 그림에서 요소별로 색을 지정하는 함수를 만들어줍니다. 코드에 대한 설명은 이전 포스팅과 거의 비슷하므로 여기를 참고하시면 됩니다.

 

def set_box_colors(bp, colors):
    for item in ['boxes','medians','fliers','caps','whiskers']:
        if item in ['boxes','medians','fliers']:
            for i, v in enumerate(bp[item]):
                if item == 'fliers':
                    plt.setp(v, markerfacecolor=colors[i])
                plt.setp(v, color = colors[i])
        else:
            for i, v in enumerate(zip(bp[item][::2],bp[item][1::2])):
                if v == 'whiskers':
                    plt.setp(v, color=colors[i], linewidth=2, linestyle='--')
                plt.setp(v, color=colors[i], linewidth=2)

 

이제 상자 수염 그림(박스 플롯)을 그려보도록 하겠습니다. 아래 코드를 살펴볼게요.

 

main_category = 'Gender'
sub_category = 'Age'
data_column = 'IQ'

num_sub_category = len(df[sub_category].unique())
num_main_category = len(df[main_category].unique())

sub_category_list = sorted(df[sub_category].unique())
main_category_list = sorted(df[main_category].unique())

colors = sns.color_palette('hls',num_sub_category)
margin = 0.15

fig = plt.figure(figsize=(10,10))
fig.set_facecolor('white')

main_xticks = []
for c, m in enumerate(main_category_list):
    data = []
    for s in sub_category_list:
        data.append(df.query(f'{main_category}==@m and {sub_category}==@s')[data_column])
    
    positions = range(num_sub_category*c+1,num_sub_category*(c+1)+1)
    main_xticks.append(positions)
    bp = plt.boxplot(data, positions=positions, widths=1-2*margin) ## 상자 수염 그림 출력
    set_box_colors(bp, colors)
    
fontsize = 15
    
## x축 눈금 설정
xticks = []
for mx in main_xticks:
    xticks.append((min(mx)+max(mx))/2)

plt.xticks(xticks,main_category_list, fontsize=fontsize) ## x축 눈금 라벨

## 구분선
for i in range(len(xticks)-1):
    plt.axvline((xticks[i]+xticks[i+1])/2,color='gray',linestyle='--')

## 범례
legendlines = []
for c in colors:
    legendlines.append(Line2D([0],[0],color=c, lw=3))
    
plt.legend(handles=legendlines, labels=sub_category_list)

## x, y 라벨
plt.xlabel(sub_category, fontsize=fontsize)
plt.ylabel(data_column, fontsize=fontsize)

plt.show()

 

line 1~2

먼저 상위 그룹(main_category)과 하위 그룹(sub_category)이 될 변수를 정합니다. 

 

line 5~8

상위 그룹과 하위 그룹의 특정 원소 리스트와 개수를 구합니다.

 

line 11~12

상자 수염 그림(박스 플롯)의 색상과 이웃하는 그림들 사이의 여백을 설정합니다.

 

line 19~21

상위 그룹별로 하위 그룹의 개수만큼 데이터를 만들어줍니다.

 

line 23

상자 수염 그림이 표시될 x축 위치를 정해줍니다.

 

line 25

상자 수염 그림을 출력합니다. 미리 정해둔 x축 위치를 positions 인자에 넣어주고 상자의 폭은 widths에 넣어줍니다.

 

위 코드를 실행해보세요.

 

 

상위 그룹(Gender)에 대한 하위 그룹(Age)의 개수(5) 만큼 상자 수염 그림이 그려진 것을 확인할 수 있습니다.

 

반대로 Age를 상위 그룹, Gender를 하위 그룹으로 설정하여 상자 수염 그림을 그려보겠습니다. main_category 변수에 Age, sub_category 변수에 Gender를 넣어주기만 하면 됩니다. 코드를 실행하면 다음과 같이 멋진 상자 수염 그림이 완성된 것을 확인할 수 있습니다.

 


이번 포스팅에서는 그룹 상자 수염 그림(박스 플롯)을 그리는 방법에 대해서 알아보았습니다. 부디 이 내용이 도움이 되셨으면 합니다.

 

지금까지 꽁냥이의 글 읽어주셔서 감사합니다. 안녕히 계세요.


댓글


맨 위로