호기심 많은 분석가

[BoostCamp] Data_Viz_1. Line Plot & Scatter Plot 본문

Coding/BoostCamp

[BoostCamp] Data_Viz_1. Line Plot & Scatter Plot

DA Hun 2021. 8. 17. 01:58
 

부스트캠프

개발자의 지속 가능한 성장을 위한 학습 커뮤니티

boostcamp.connect.or.kr

(2-2) Line Plot 사용하기

기본 Line Plot

1. Line plot이란?

  • Line Plot은 연속적으로 변화하는 값을 순서대로 점으로 나타내고, 이를 선으로 연결한 그래프
  • 꺾은선 그래프, 선 그래프, line chart, line graph 등의 이름으로 사용됨
  • 시간/순서에 대한 변화에 적합하여 추세를 살피기 위해 사용
    • 시계열 분석에 특화!!
  • 신기하게 .line이 아니라 .plot()

Line Plot

2. Line plot의 요소

  • 5개 이하의 선을 사용하는 것을 추천
    • 더 많은 선은 중첩으로 인한 가독성 하락
  • 그렇다면 이를 구별하는 요소는 어떤 것이 있을까?
    1. 색상 (color)
    2. 마커 (marker, markersize)
    3. 선의 종류 (linestyle, linewidth)
      1. solid, dashed, dashdot, dotted, None

Line Style

3. Line plot을 위한 전처리

  • 시시각각 변동하는 데이터(Ex) 주식)는 Noise로 인해 패턴 및 추세 파악이 어려움
  • Noise의 인지적인 방해를 줄이기 위해 smoothing 사용

smooth

# Tip, to_datetime에 error를 처리해주는 parameter가 존재
pd.to_datetime(stock['date'], format='%Y-%m-%d', errors='raise')

# 비율 고정, 아래의 경우 1대 1 사각형 생성
fig.add_subplot(111, aspect=1)

# random.seed(1996), 랜덤 값 고정
np.random.seed(1996)
np.random.rand(7) # 항상 같은 랜덤 값이 나온다
# rolling 문법을 통해 moving average 구해줌, window의 숫자만큼 앞에 있는 데이터와
# mean(평균)을 취해준다.
google_rolling = google.rolling(window=20).mean()

# dpi : 고해상도 지정, default=100, sharex : x축 고정
fig, axes = plt.subplots(2, 1, figsize=(12, 7), dpi=300, sharex=True)

axes[0].plot(google.index,google['close'])
axes[1].plot(google_rolling.index,google_rolling['close'])

plt.show()

정확한 Line Plot

  • 오용을 줄여보자

1. 추세에 집중

  • Bar plot과 다르게 꼭 축을 0에 초점을 둘 필요는 없다
    • 추세를 보기 위한 목적이므로
  • 너무 구체적인 line plot보다는 생략된 line plot이 더 나을 수 있다.
    • Grid, Annotate 등 모두 제거
    • 디테일한 정보를 표로 제공하는 것을 추천
  • 생략되지 않는 선에서 범위를 조정하여 변화율 관찰 (.set_ylim())
from matplotlib.ticker import MultipleLocator
# 축 간격을 조정해주는 명령어
ax1.xaxis.set_major_locator(MultipleLocator(1))
ax1.yaxis.set_major_locator(MultipleLocator(0.05))    
ax1.grid(linewidth=0.3)

# 1) verticalalignment (va)
#  - center : 수직방향으로 좌표 중앙에 놓임
#  - top : 좌표가 텍스트 위에 놓임
#  - bottom : 좌표가 텍스트 아래 놓임
#  - baseline : 텍스트의 baseline 에 따라 달라짐

# 2) horizontal alignment (ha)
#  - center : 수평방향으로 좌표 중앙에 놓임
#  - left : 좌표가 텍스트 왼쪽에 놓임
#  - right : 좌표가 텍스트 오른쪽에 놓임
ax1.set_title(f"Line Plot (information)", loc='left', fontsize=12, va= 'bottom', fontweight='semibold')

Grid 유무

  • 하지만 항상 오른쪽이 옳지는 않다. 정확한 값이 필요할 경우 왼쪽 그래프를 쓸 때도 있고, 몇 년간의 추세를 보기 위해서는 오른쪽 그래프를 쓰기도 한다. → 목적이 중요

2. 간격

우리는 기울기로 그래프를 많이 이해하기 때문에 x축의 간격이 굉장히 중요하다

  • 규칙적인 간격이 아니라면 오해를 줄 수 있다
    • 그래프 상에서 규칙적일 때 : 없는 데이터에 대해 있다고 오해
    • 그래프 상에서 간격이 다를 때 : 기울기 정보의 오해
  • 규칙적인 간격의 데이터가 아니라면 각 관측 값에 점으로 표시하여 오해를 줄이자.

간격 설정의 중요성

3. 보간

  • Line은 점을 이어 만드는 요소 → 점과 점 사이에 데이터가 없기에 이를 잇는 방법(보간)
  • 데이터의 error나 noise가 포함되어 있는 경우, 데이터의 이해를 돕는 방법
    • Moving Average
    • Smooth Curve with Scipy
      • scipy.interpolate.make_interp_spline()
      • scipy.interpolate.interp1d()
      • scipy.ndimage.gaussian_filter1d()
    • Presentation에는 좋은 방법일 수 있으나
      • 없는 데이터를 있다고 생각하게 할 수 있으며
      • 작은 차이를 없앨 수 있음
      • 일반적인 분석에서는 지양할 것!
      from scipy.interpolate import make_interp_spline, interp1d
      import matplotlib.dates as dates
      
      date_np = google.index
      value_np = google['close']
      
      # Date -> Num
      date_num = dates.date2num(date_np)
      
      # smooth
      date_num_smooth = np.linspace(date_num.min(), date_num.max(), 50) 
      spl = make_interp_spline(date_num, value_np, k=3)
      value_np_smooth = spl(date_num_smooth)
      
      # print
      ax[0].plot(date_np, value_np)
      ax[1].plot(dates.num2date(date_num_smooth), value_np_smooth)
      Interploation
    • 4. 이중 축 사용
    • 한 plot에 대해 2개의 축을 이중 축 (dual axis)라고 함
    • 같은 시간 축에 대해 서로 다른 종류의 데이터를 표현하기 위해서는 축이 2개가 필요
      • .twinx() 를 사용
    • 한 데이터에 대해 다른 단위 (ex. radian과 degree)
      • [.secondary_xaxis()](https://matplotlib.org/stable/gallery/subplots_axes_and_figures/secondary_axis.html), .secondary_yaxis() 사용
    • 2개의 plot을 그리는 것 >>>>> 이중 축 사용
      • 이충 축은 지양할 것, 상관관계가 없는 데 있어보일 수 있기 때문

dual axis

# First Plot
color = 'royalblue'

ax1.plot(google.index, google['close'], color=color)
ax1.set_xlabel('date')
ax1.set_ylabel('close price', color=color)  
ax1.tick_params(axis='y', labelcolor=color)

# # Second Plot
ax2 = ax1.twinx()  
color = 'tomato'

ax2.plot(google.index, google['volume'], color=color)
ax2.set_ylabel('volume', color=color)  
ax2.tick_params(axis='y', labelcolor=color)

dual -> 각각

한 번에 2개를 그리는 것보다 따로 그리는 게 가독성이 좋다.

def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

x = np.arange(0, 360)
y = np.sin(2 * x * np.pi / 180)
ax.plot(x, y)
ax.set_xlabel('angle [degrees]')
ax.set_ylabel('signal')
ax.set_title('Sine wave')
secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('angle [rad]')

dual axis의 좋은 예

5. ETC

  • 라인 끝 단에 레이블을 추가하면 식별에 도움 (범례 대신)
x = np.linspace(0, 2*np.pi, 1000)
y1 = np.sin(x)

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))

범례보단 끝 단에 텍스트 표시

  • Min/Max 정보(또는 원하는 포인트)는 추가해주면 도움이 될 수 있음 (annotation, )
    • 두 그래프 중 하나만 주는 것보다 같이 주는 것이 트렌트 파악에 더 도움이 된다
ax.set_xlim(-1, 21)

# max
# -1부터 최댓값의 지점(np.argmax(y))(좌표)까지 plot을 그려줌
ax.plot([-1, x[np.argmax(y)]], [np.max(y)]*2,
        linestyle='--', color='tomato'
       )

ax.scatter(x[np.argmax(y)], np.max(y), 
            c='tomato',s=50, zorder=20)

# min
ax.plot([-1, x[np.argmin(y)]], [np.min(y)]*2,
        linestyle='--', color='royalblue'
       )
ax.scatter(x[np.argmin(y)], np.min(y), 
            c='royalblue',s=50, zorder=20)

Min/Max Info

  • 보다 연한 색을 사용하여 uncertatinty 표현 가능 (신뢰구간, 분산 등)
    • Bar Plot에서는 errorbar를 통해 표현했는데, line plot에서는 Area Plot으로 표현함

Area Plot을 이용한 신뢰구간 시각화


(2-3) Scatter Plot 사용하기

  • 이전의 두 강의에서는 점, 선, 면 중에서 선과 면을 사용했다. 이번에는 마지막 점을 사용한 그래프를 사용할 것

기본 Scatter Plot

1. Scatter plot이란?

  • Scatter plot은 점을 사용하여 두 feature간의 관계를 알기 위해 사용하는 그래프
  • 산점도 등의 이름으로 사용됨
  • 직교 좌표계에서 x축/y축에 feature 값을 매핑해서 사용
  • .scatter()를 사용

2. Scatter plot의 요소

  • 점에서 다양한 variation 사용 가능 (2차원 데이터에서 N차원 데이터로 확장 가능)
    • Bar plot, line plot과 다르게 2차원 데이터에서 시작한다. 그것을 아래 variation을 통해 차원을 늘려가는 것도 가능 → 점의 요소로 차원을 늘릴 수 있다.
    • 이 색, 모양, 크기가 인지적으로 어떤 효과를 보일 지 고민하면서 시각화하자
    1. 색(color)
    2. 모양(marker)
    3. 크기(size)
ax.scatter(x, y, 
           s= s, # size, 배열로 전달해서 각각의 사이즈를 다르게 할 수 있음
           c='white',
           marker='o',
           linewidth=1,
           edgecolor='black')

Scatter plot 요소

3. Scatter plot의 목적

  • 상관 관계 확인 (양의 상관관계 / 음의 상관관계 / 없음)
    • Positive Correlation, Negative Correlation의 경우 실제 수치가 있다.
      • 피어슨 계수, 공분산 등등

상관관계

  • 세 가지를 확인하자 - 데이터의 세 가지 특징
    • 군집 - 데이터가 어떤 식으로 묶여있는가, Ex. KNN, DBSCAN, t-SNE
    • 값 사이의 차이
    • 이상치 - 신뢰구간 95% 이상, 등등

데이터의 세 가지 특성

정확한 Scatter Plot

Scatter plot의 오용을 막아보자

1. Overplotting

실제 데이터의 개수만큼 점으로 표현된다.

  • 점이 많아질수록 점의 분포를 파악하기 힘들다!
    • 투명도 조정 - 점이 많이 모여있으면 진해지게
    • 지터링 (jittering) : 점의 위치를 약간씩 변경, 하지만 다른 방법들이 더 효율적임
    • 2차원 히스토그램 : 히트맵을 사용하여 깔끔한 시각화 (x, y축 구간을 나눠서)
      • 투명도 조정보다 깔끔하지만, 구체적인 값을 알 수 없기 때문에 같이 사용하는 것을 추천
    • Contour plot : 분포를 등고선을 사용하여 표현

Overlapping

2. 점의 요소와 인지

    • 연속은 gradient, 이산은 개별 색상으로
  • 마커
    • 거의 구별하기 힘들다 + 크기가 고르지 않음
    • 잉크 비례의 원칙에 따르면 마커가 표현하는 값이 같으면 크기도 같아야하는데, 동그라미, 네모, 세모 실제 크기와 우리가 인지하는 크기가 다르다 → 조심해야함
  • 크기
    • 흔히 버블 차트 (bubble chart)라고 부름
    • 구별하기는 쉽지만 오용하기 쉬움 (원의 크기 비교)
    • 관계보다는 각 점간 비율에 초점을 둔다면 좋음
    • SWOT 분석 등에 활용 가능

점의 요소

3. 인과관계와 상관관계

  • 인과 관계 (causal relation)과 상관 관계 (correlation)은 다름!
    • 분석 과정에서 꼭 고민해볼 것
    • 상관 관계는 두 개의 feature가 비슷한 정도가 있어서 같이 커질 수 있다
    • 인과 관계는 x축 때문에 y축이 변한다
  • 인과 관계는 항상 사전 정보와 함께 가정으로 제시할 것
    • 상관 관계가 있다고 항상 인과 관계가 있는 것은 아님
  • 상관관계는 추후 heatmap에서 다시 다룰 예정

4. 추세선

  • 추세선을 사용하면 scatter의 패턴을 유추할 수 있음
    • 단, 추세선이 2개 이상이 되면 가독성이 떨어지므로 주의.

추세선

5. ETC

  • Grid는 지양, 사용한다면 최소한으로 - Scatter plot과 상성이 안좋음
    • 점같이 작은 것들과 겹치면 정보가 오용될 수가 있음
    • 색은 무채색으로
  • 범주형이 포함된 관계에서는 heatmap 또는 bubble chart를 추천

Grid

6. 실습 코드

  • Matplotlib dataart를 검색하면 다양한 것들을 배울 수 있다.
  • 특정 조건에 따라 색을 다르게 하여 주의를 줄 수 있다.
slc_mean = iris['SepalLengthCm'].mean()
swc_mean = iris['SepalWidthCm'].mean()

ax.scatter(x=iris['SepalLengthCm'], 
           y=iris['SepalWidthCm'],
           c=['royalblue' if yy <= swc_mean else 'gray' for yy in iris['SepalWidthCm']]
          )
# scatter_plot을 할 때는 종종 잘리는 부분이 있을 수 있어서 약간씩 조정해준다
ax.set_xlim(0, 4.55)
ax.set_ylim(0, 8.05)

Mean에 따른 색 변환

  • 위와 같이 반복문과 조건문으로 구분할 수도 있지만 범례를 사용할 예정이므로 세 번 나눠그리는 편이 더 편하다.
for species in iris['Species'].unique():
    iris_sub = iris[iris['Species']==species]
    ax.scatter(x=iris_sub['PetalLengthCm'], 
               y=iris_sub['PetalWidthCm'], 
               label=species)

종류별 시각화

  • 시각적인 주의를 주기 위해서 선을 사용
for species in iris['Species'].unique():
    iris_sub = iris[iris['Species']==species]
    ax.scatter(x=iris_sub['PetalLengthCm'], 
               y=iris_sub['PetalWidthCm'], 
               label=species)

ax.axvline(2.5, color='gray', linestyle=':')    
ax.axhline(0.8, color='gray', linestyle=':')

시각적 효과를 위해 선 사용

  • 좀 더 다양한 관점에서 보기 위해 다음과 같이 그려본다
feat = ['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']

for i, f1 in enumerate(feat):
    for j, f2 in enumerate(feat):
        if i <= j : 
            axes[i][j].set_visible(False)
            continue
        for species in iris['Species'].unique():
            iris_sub = iris[iris['Species']==species]
            axes[i][j].scatter(x=iris_sub[f2], 
                               y=iris_sub[f1], 
                               label=species, 
                               alpha=0.7)
        if i == 3: axes[i][j].set_xlabel(f2)
        if j == 0: axes[i][j].set_ylabel(f1)

# 자동으로 명시된 여백에 관련된 서브플롯 파라미터를 조정
plt.tight_layout()

다양한 효과를 이용한 시각화

 

[AI Tech]Daily Report

Naver AI Tech BoostCamp 2기 캠퍼 허정훈 2021.08.03 - 2021.12.27 https://bit.ly/3oC70G9

www.notion.so