[BoostCamp]Day15 데이터 시각화 실습
부스트캠프 15일차 공부 정리.
from google.colab import drive
drive.mount('/content/drive')
path = '/content/drive/MyDrive/boostcamp/' # 데이터 저장 경로
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(12, 7)) # (가로, 세로) 인치단위
fig.set_facecolor('lightgray') # 배경색
ax1 = fig.add_subplot(1, 3, 1, aspect = 3) # 가로 1개, 세로 3개, 1번째, aspect로 비율 조정 가능
ax2 = fig.add_subplot(1, 3, 2, aspect = 1.2) # 가로 1개, 세로 3개, 2번째
ax3 = fig.add_subplot(1, 3, 3) # 가로 1개, 세로 3개, 2번째
ax1.plot([1, 1, 1], color='r') # 한 글자로 정하는 색상
ax1.plot([2, 2, 2], color='forestgreen') # color name
ax1.plot([3, 3, 3], color='#000000') # hex code
ax2.plot([1, 1, 1], label='1') # label : 범례추가
ax2.plot([2, 2, 2], label='2')
ax2.plot([3, 3, 3], label='3')
ax3.plot([1, 1, 1])
ax3.plot([2, 2, 2])
ax3.plot([3, 3, 3])
ax2.set_title('Basic Plot') # 제목 추가
ax2.set_xticks([0, 1, 2, 3, 4]) # x축 범위 추가
ax2.legend() # label : 범례추가
ax2.grid() # 바깥 실선(격자) 추가
ax3.set_xticks([0, 1, 2])
ax3.set_xticklabels(['zero', 'one', 'two']) # x축 값 입력
ax3.text(x=1, y=2, s='This is Text') # 텍스트 추가
plt.show()
# fig.savefig('file_names', dpi = 150) # png 파일로 저장, dpi로 해상도 높일 수도 있음
Figure는 큰 틀(언제나 1개), Ax는 각 플롯이 들어가는 공간(N개) 입니다.
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, aspect=1) # aspect : x, y 범위 고정
np.random.seed(970725)
x = np.random.rand(20)
y = np.random.rand(20)
ax.scatter(x, y)
ax.set_xlim(0, 1.05)
ax.set_ylim(0, 1.05)
plt.show()
aspect 함수를 사용하면 x, y의 스케일을 맞출 수 있습니다.
student = pd.read_csv(path + 'StudentsPerformance.csv')
student.sample(5)
head 보다 sample을 보면 데이터를 더 잘 파악할 수 있습니다.
student.describe(include='all')
describe 함수를 사용할 때 include='all' 옵션을 사용하면 범주형 변수도 나타나고, unique 등 특징도 알 수 있어 좋습니다.
group = student.groupby('gender')['race/ethnicity'].value_counts().sort_index() # index 기준으로 정렬
fig, axes = plt.subplots(1, 2, figsize=(15, 7), sharey=True) # sharey : Y축 고정
axes[0].bar(group['male'].index, group['male'], color='royalblue')
axes[1].bar(group['female'].index, group['female'], color='tomato', alpha=0.9) # alpha : 투명도
plt.show()
sharey = True 옵션을 사용하면 두 그래프의 Y 축을 맞춰줄 수 있어 좋은 시각화를 할 수 있습니다.
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)
plt.show()
퍼센트르 반영한 가로방향 그래프입니다. ax.spines['top'].set_visible(False) 으로 외각선을 없앨 수도 있습니다.
score = student.groupby('gender').mean().T
score_var = student.groupby('gender').std().T
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, # 막대 위 선(모자)
edgecolor='black', # 겉 테두리 색깔
linewidth=2, # 겉 테두리 두께
)
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()
오차막대, 박스 겉 테두리선 등 신경써서 꾸민 그래프입니다. width은 폭을 조정하고, yerr에 분산값을 넣어주면 오차막대가 생깁니다.
capsize은 오차막대 위, 아래 선을 추가해줍니다. edgecolor는 박스 테두리를 채워줍니다. linewidth은 그 테두리 두께 크기를 정합니다.
bar 그래프 관련 기타 참고 사항으로 잉크양과 실제 값은 비례하는 것이 좋습니다. 값에 시작은 0부터 진행되면 좋겠군요.
또 사람의 눈은 2차원을 가장 잘 인식하기 때문에 필요성이 떨어지는 복잡함은 지양하는 것이 좋겠습니다.
line 시각화는 주로 시계열 자료에서 추세을 나타내고자 할 때 쓰임니다.
추세가 중요한 경우 bar 그래프와 달리 꼭 0을 시작점으로 잡을 필요는 없습니다.
fig, ax = plt.subplots(1, 1, figsize=(5, 5))
np.random.seed(97)
x = np.arange(7)
y = np.random.rand(7)
ax.plot(x, y,
color='black', # 색깔
marker='*', # 마커
linestyle='solid', # 선의 종류 (`solid`, `dashed`, `dashdot`, `dotted`, `None`)
)
plt.show()
점은 크게 색, 마커, 선의 종류 3가지 요소가 존재합니다.
stock = pd.read_csv(path + 'prices.csv')
stock['date'] = pd.to_datetime(stock['date'], format='%Y-%m-%d', errors='raise')
stock.set_index("date", inplace = True)
apple = stock[stock['symbol']=='AAPL']
google = stock[stock['symbol']=='GOOGL']
google.sample(5)
미국 주식 자료입니다. 추세가 있는 시계열 자료이기 때문에 line 시각화가 어울립니다.
google_rolling = google.rolling(window=20).mean()
fig, axes = plt.subplots(2, 1, figsize=(12, 7), dpi=300, sharex=True) # dpi : 해상도(디폴트 100), sharex : x축 고정
axes[0].plot(google.index,google['close'])
axes[1].plot(google_rolling.index,google_rolling['close'])
plt.show()
우선 dpi은 해상도를 보장해주는 옵션입니다. 저는 잘 모르겠는데 확실히 또렷하다고 합니다.
이런 노이즈가 많이 껴있는 시계열 자료는 추세를 잘 보여주기 위해 이동평균 기법을 사용합니다.
fig = plt.figure(figsize=(12, 5))
x = np.linspace(0, 2*np.pi, 1000)
y1 = np.sin(x)
y2 = np.cos(x)
ax = fig.add_subplot(111, aspect=1)
ax.plot(x, y1,
color='#1ABDE9',
linewidth=2,)
ax.plot(x, y2,
color='#F36E8E',
linewidth=2,)
ax.text(x[-1]+0.1, y1[-1], s='sin', fontweight='bold',
va='center', ha='left',
bbox=dict(boxstyle='round,pad=0.3', fc='#1ABDE9', ec='black', alpha=0.3))
ax.text(x[-1]+0.1, y2[-1], s='cos', fontweight='bold',
va='center', ha='left',
bbox=dict(boxstyle='round,pad=0.3', fc='#F36E8E', ec='black', alpha=0.3))
ax.spines['top'].set_visible(False) # 테두리 선 없앰
ax.spines['right'].set_visible(False) # 테두리 선 없앰
plt.show()
line 그래프는 위와 같이 범례를 따로 만드는 것 보다 선 끝에 무슨 항목인지 표시해 주는 것이 가독성이 좋습니다.
fig, ax = plt.subplots()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.text(x=0.5, y=0.5, s='Text\nis Important',
fontsize=20,
fontweight='bold',
fontfamily='serif',
color='royalblue',
fontstyle = 'italic',
linespacing=2,
va='center', # top, bottom, center 위 아래 정렬 (중요)
ha='center', # left, right, center 왼쪽, 오른쪽 정렬 (중요)
rotation='horizontal', # vertical 글짜 방향(수평/수직)
# bbox는 딕셔너리 형태로 넣어줘야, 적용할 수 있는 것이 더 많아 검색 필요
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.4)
)
fig.text(0.2, 0.9, s='Figure Text') # 위치(가로, 세로) 기반 텍스트 작성
plt.show()
기본적으로 text는 크게 4개 요소가 존재합니다.
- 크기(fontsize)
- 굵기(fontweight)
- 글꼴(fontfamily)
- 스타일(fontstyle)
이 외에는 bbox나 정렬, 그 외 세부사항으로 나뉩니다.
텍스트 작성에는 fig, ax 두 곳에서 모두 가능하며 fig는 비율로, ax는 좌표로 인지합니다.
데이터를 구분 짓는데 시각적으로 가장 강력하고 효과적인 것이 색 입니다. 기존 정보에서 사용하는 색을 사용하면(네이버 - 초록색, 카카오 - 노란색) 설명력이 크게 높아집니다.
색은 RGB 보다는 HSL로 이해하는 것이 좋습니다.
- H : Hue(색조) : 빨강부터 보라까지를 0~360으로 표현
- S : Saturate(채도) : 선명도(파스텔톤 설명 가능)
- L : Lightness(광도) : 밝기(연하다 진하다)
하지만 너무 화려한 색을 쓰는 것 보단 하고 싶은 말을 강조하는 쪽으로 쓰는 것이 중요합니다.
student = pd.read_csv(path + 'StudentsPerformance.csv')
a_color, nota_color = 'black', 'lightgray'
colors = student['race/ethnicity'].apply(lambda x : a_color if x =='group A' else nota_color)
color_bars = [a_color] + [nota_color]*4
fig = plt.figure(figsize=(18, 15))
groups = student['race/ethnicity'].value_counts().sort_index()
ax_bar = fig.add_subplot(2, 1, 1)
ax_bar.bar(groups.index, groups, color=color_bars, width=0.5)
ax_s1 = fig.add_subplot(2, 3, 4)
ax_s2 = fig.add_subplot(2, 3, 5)
ax_s3 = fig.add_subplot(2, 3, 6)
ax_s1.scatter(student['math score'], student['reading score'], color=colors, alpha=0.5)
ax_s2.scatter(student['math score'], student['writing score'], color=colors, alpha=0.5)
ax_s3.scatter(student['writing score'], student['reading score'], color=colors, alpha=0.5)
for ax in [ax_s1, ax_s2, ax_s3]:
ax.set_xlim(-2, 105)
ax.set_ylim(-2, 105)
plt.show()
위와 같이 색을 말하고 싶은 정보를 강조하는 방법으로 사용하면 효과가 좋습니다.
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_aspect(1)
math_mean = student['math score'].mean()
reading_mean = student['reading score'].mean()
ax.axvline(math_mean, color='gray', linestyle='--') # 면인경우 axvspan
ax.axhline(reading_mean, color='gray', linestyle='--')
ax.scatter(x=student['math score'], y=student['reading score'],
alpha=0.5,
color=['royalblue' if m>math_mean and r>reading_mean else 'gray' for m, r in zip(student['math score'], student['reading score'])],
zorder=10,
)
ax.set_xlabel('Math')
ax.set_ylabel('Reading')
ax.set_xlim(-3, 103)
ax.set_ylim(-3, 103)
plt.show()
axvline 라는 선을 그리는 함수를 추가해서 내가 원하는 영역을 강조할 수 있습니다.
fig = plt.figure(figsize=(12, 6))
_ = fig.add_subplot(1,2,1)
ax = fig.add_subplot(1,2,2)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_linewidth(1.5)
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
plt.show()
각 선도 보이지 않게 할 수도(set_visible), 굵기를 두껍게 할 수도(set_linewidth), 아에 이동 할 수도(set_position) 있습니다.
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.linestyle'] = ':'
plt.rcParams['figure.dpi'] = 150
# plt.rcParams.update(plt.rcParamsDefault) # 다시 디폴트 설정으로 돌리기
plt.plot([1,2,3])
plt 자체에서 디폴트 설정을 바꿀 수도 있습니다.
plt.rcParams.update(plt.rcParamsDefault) # 디폴트 설정으로 돌리기
print(mpl.style.available)
mpl.style.use('ggplot') # ggplot 스타일로
plt.plot([1, 2, 3])
아에 스타일을 바꾸는 방법도 있습니다. 강의 내용을 빌리면 ggplot 이쁘다고 하네요.
빨간날이 하나 껴있지만 하나도 체감을 못했습니다. 월요일에 늦잠잔거 정도?
열심히 달리긴 했지만 시각화 강의 실습을 제대로 체험해본 느낌은 아니여서 정말 아쉽습니다.
강의가 좋고 실습 코드도 다시 한번 리마인드 하면 좋을 것 같습니다.
다음주에도 열심히 화이팅 해보겠습니다.
** 위 수식과 그림은 부스트캠프 AI Tech 교육 자료를 참고하였습니다.