부스트캠프 AI Tech 4기

(Data Viz) Bar Plot 실습

쉬엄쉬엄블로그 2023. 6. 9. 13:04
728x90

1. 기본 Bar Plot

  • bar() : 기본적인 bar plot
  • barh() : horizontal bar plot
!pip install matplotlib==3.3.2


import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt


fig, axes = plt.subplots(1, 2, figsize=(12, 7))

x = list('ABCDE')
y = np.array([1, 2, 3, 4, 5])

axes[0].bar(x, y)
axes[1].barh(x, y)

plt.show()

# 막대 그래프의 색은 다음과 같이 변경을 전체로 하거나, 개별로 할 수도 있다. 
# 개별로 할 때는 막대 개수와 같이 색을 리스트로 전해야 한다.

fig, axes = plt.subplots(1, 2, figsize=(12, 7))

x = list('ABCDE')
y = np.array([1, 2, 3, 4, 5])

clist = ['blue', 'gray', 'gray', 'gray', 'red']
color = 'green'
axes[0].bar(x, y, color=clist)
axes[1].barh(x, y, color=color)

plt.show()

2. 다양한 Bar Plot

데이터 : http://roycekimmons.com/tools/generated_data/exams

 

Exam Scores

Tools → Data Generators OverviewThis is a fictional dataset and should only be used for data science training purposes.This data set includes scores from three exams and a variety of personal, social, and economic factors that have interaction effects up

roycekimmons.com

  • 1000명 학생 데이터
  • feature에 대한 정보는 head(), describe(), info() 등으로 확인
  • unique(), value_counts() 등으로 종류나 큰 분포 확인
  • feature들
    • 성별 : female / male
    • 인종민족 : group A, B, C, D, E
    • 부모님 최종 학력 : 고등학교 졸업, 전문대, 학사 학위, 석사 학위, 2년제 졸업
    • 점심 : standard와 free/reduced
    • 시험 예습 : none과 completed
    • 수학, 읽기, 쓰기 성적 (0~100)
student = pd.read_csv('./StudentsPerformance.csv')
student.sample(5)

  • 그룹에 따른 정보 시각화

성별에 따른 race/ethincity 분포

group = student.groupby('gender')['race/ethnicity'].value_counts().sort_index()
display(group)
print(student['gender'].value_counts())

2-1. Multiple Bar Plot

fig, axes = plt.subplots(1, 2, figsize=(15, 7))
axes[0].bar(group['male'].index, group['male'], color='royalblue')
axes[1].bar(group['female'].index, group['female'], color='tomato')
plt.show()

  • 각 barplot은 자체적으로 y 범위를 맞추기에 좀 더 y축의 범위를 공유할 수 있다.
  • 방법1은 subplot을 만들 때, sharey 파라미터를 사용하는 방법이다.
fig, axes = plt.subplots(1, 2, figsize=(15, 7), sharey=True)
axes[0].bar(group['male'].index, group['male'], color='royalblue')
axes[1].bar(group['female'].index, group['female'], color='tomato')
plt.show()

  • 방법2는 y축 범위를 개별적으로 조정하는 방법이다. 반복문을 사용하여 조정할 수 있다.
    • Group간의 비교가 어렵다는 단점이 있다.
fig, axes = plt.subplots(1, 2, figsize=(15, 7))
axes[0].bar(group['male'].index, group['male'], color='royalblue')
axes[1].bar(group['female'].index, group['female'], color='tomato')

for ax in axes:
    ax.set_ylim(0, 200)

plt.show()

2-2. Stacked Bar Plot

  • 쌓아서 보면 그룹 A, B, C, D, E에 대한 전체 비율은 알기 쉽다.
  • bottom 파라미터를 사용해서 아래 공간을 비워둘 수 있다.
fig, axes = plt.subplots(1, 2, figsize=(15, 7))

group_cnt = student['race/ethnicity'].value_counts().sort_index()
axes[0].bar(group_cnt.index, group_cnt, color='darkgray')
axes[1].bar(group['male'].index, group['male'], color='royalblue')
axes[1].bar(group['female'].index, group['female'], bottom=group['male'], color='tomato')

for ax in axes:
    ax.set_ylim(0, 350)

plt.show()

2-3. Percentage Stacked Bar Plot

fig, ax = plt.subplots(1, 1, figsize=(12, 7))

group = group.sort_index(ascending=False) # 역순 정렬
total=group['male']+group['female'] # 각 그룹별 합


ax.barh(group['male'].index, group['male']/total, 
        color='royalblue')

ax.barh(group['female'].index, group['female']/total, 
        left=group['male']/total, 
        color='tomato')

ax.set_xlim(0, 1)
for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False) # spines : 테두리

plt.show()

2-4. Overlapped Bar Plot

  • 겹치는 투명도는 꼭 정해진 것이 아닌 다양한 실험을 통해 선택하면 된다.
group = group.sort_index() # 다시 정렬

fig, axes = plt.subplots(2, 2, figsize=(12, 12))
axes = axes.flatten()

for idx, alpha in enumerate([1, 0.7, 0.5, 0.3]):
    axes[idx].bar(group['male'].index, group['male'], 
                  color='royalblue', 
                  alpha=alpha)
    axes[idx].bar(group['female'].index, group['female'],
                  color='tomato',
                  alpha=alpha)
    axes[idx].set_title(f'Alpha = {alpha}')

for ax in axes:
    ax.set_ylim(0, 200)


plt.show()

2-5. Grouped Bar Plot

  • 3가지 테크닉
    • x축 조정
    • width 조정
    • xticks, xticklabels
  • 원래 x축이 0, 1, 2, 3로 시작한다면
    • 한 그래프는 0-width/2, 1-width/2, 2-width/2 로 구성하면 되고
    • 한 그래프는 0+width/2, 1+width/2, 2+width/2 로 구성하면 된다.
fig, ax = plt.subplots(1, 1, figsize=(12, 7))

idx = np.arange(len(group['male'].index))
width=0.35

ax.bar(idx-width/2, group['male'], 
       color='royalblue',
       width=width)

ax.bar(idx+width/2, group['female'], 
       color='tomato',
       width=width)

ax.set_xticks(idx)
ax.set_xticklabels(group['male'].index)

plt.show()

  • 추가적으로 label + legend를 달아 색에 대한 설명도 추가하면 좋다.
fig, ax = plt.subplots(1, 1, figsize=(12, 7))

idx = np.arange(len(group['male'].index))
width=0.35

ax.bar(idx-width/2, group['male'], 
       color='royalblue',
       width=width, label='Male')

ax.bar(idx+width/2, group['female'], 
       color='tomato',
       width=width, label='Female')

ax.set_xticks(idx)
ax.set_xticklabels(group['male'].index)
ax.legend()    

plt.show()

  • 그룹의 개수에 따른 x좌표
    • 2개 : -1/2, +1/2
    • 3개 : -1, 0, +1 (-2/2, 0, +2/2)
    • 4개 : -3/2, -1/2, +1/2, +3/2
  • $-\frac{N-1}{2}$에서 $\frac{N-1}{2}$까지 분자에 2간격으로 커지는 것이 특징이다.
  • index i(zero-index)에 대해서는 다음과 같이 x좌표를 계산할 수 있다.
    $x+\frac{-N+1+2\times i}{2}\times width$
  • 인종/민족 그룹에 따른 Parental Level of Education Grouped Bar Plot
group = student.groupby('parental level of education')['race/ethnicity'].value_counts().sort_index()
group_list = sorted(student['race/ethnicity'].unique())
edu_lv = student['parental level of education'].unique()

fig, ax = plt.subplots(1, 1, figsize=(13, 7))

x = np.arange(len(group_list))
width=0.12

for idx, g in enumerate(edu_lv):
    ax.bar(x+(-len(edu_lv)+1+2*idx)*width/2, group[g], 
       width=width, label=g)

ax.set_xticks(x)
ax.set_xticklabels(group_list)
ax.legend()    

plt.show()

3. 정확한 Bar Plot

3-1. Principle of Proportion Ink

  • 성별에 따른 성적을 막대그래프로 비교
score = student.groupby('gender').mean().T
score

fig, axes = plt.subplots(1, 2, figsize=(15, 7))

idx = np.arange(len(score.index))
width=0.3

for ax in axes:
    ax.bar(idx-width/2, score['male'], 
           color='royalblue',
           width=width)

    ax.bar(idx+width/2, score['female'], 
           color='tomato',
           width=width)

    ax.set_xticks(idx)
    ax.set_xticklabels(score.index)

axes[0].set_ylim(60, 75)

plt.show()

  • 비교를 위한다면 세로를 늘리는게 더 좋을 수 있다.
fig, ax = plt.subplots(1, 1, figsize=(6, 10))

idx = np.arange(len(score.index))
width=0.3

ax.bar(idx-width/2, score['male'], 
       color='royalblue',
       width=width)

ax.bar(idx+width/2, score['female'], 
       color='tomato',
       width=width)

ax.set_xticks(idx)
ax.set_xticklabels(score.index)



plt.show()

3-2. 적절한 공간 활용

  • X/Y axis Limit (.set\_xlim(), .set\_ylime())
  • Margins (.margins())
  • Gap (width)
  • Spines (.spines\[spine\].set\_visible())
group_cnt = student['race/ethnicity'].value_counts().sort_index()

fig = plt.figure(figsize=(15, 7))

ax_basic = fig.add_subplot(1, 2, 1)
ax = fig.add_subplot(1, 2, 2)

ax_basic.bar(group_cnt.index, group_cnt)
ax.bar(group_cnt.index, group_cnt,
       width=0.7,
       edgecolor='black',
       linewidth=2,
       color='royalblue'
      )

ax.margins(0.1, 0.1)

for s in ['top', 'right']:
    ax.spines[s].set_visible(False)

plt.show()

3-3. 복잡함과 단순함

group_cnt = student['race/ethnicity'].value_counts().sort_index()

fig, axes = plt.subplots(1, 2, figsize=(15, 7))

for ax in axes:
    ax.bar(group_cnt.index, group_cnt,
           width=0.7,
           edgecolor='black',
           linewidth=2,
           color='royalblue',
           zorder=10
          )

    ax.margins(0.1, 0.1)

    for s in ['top', 'right']:
        ax.spines[s].set_visible(False)

axes[1].grid(zorder=0)

for idx, value in zip(group_cnt.index, group_cnt):
    axes[1].text(idx, value+5, s=value,
                 ha='center', 
                 fontweight='bold'
                )

plt.show()

3-4. ETC

  • 오차막대(errorbar)를 사용하여 편차 등의 정보를 추가
score_var = student.groupby('gender').std().T
score_var

fig, ax = plt.subplots(1, 1, figsize=(10, 10))

idx = np.arange(len(score.index))
width=0.3


ax.bar(idx-width/2, score['male'], 
       color='royalblue',
       width=width,
       label='Male',
       yerr=score_var['male'],
       capsize=10
      )

ax.bar(idx+width/2, score['female'], 
       color='tomato',
       width=width,
       label='Female',
       yerr=score_var['female'],
       capsize=10
      )

ax.set_xticks(idx)
ax.set_xticklabels(score.index)
ax.set_ylim(0, 100)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

ax.legend()
ax.set_title('Gender / Score', fontsize=20)
ax.set_xlabel('Subject', fontweight='bold')
ax.set_ylabel('Score', fontweight='bold')

plt.show()

 

출처: 부스트캠프 AI Tech 4기(NAVER Connect Foundation)