2-2. Line plot

유승우·2022년 5월 11일
0

Line plot


  • Line Plot은 연속적으로 변화하는 값을 순서대로 점으로 나타내고, 이를 선으로 연결한 그래프

  • 시간/순서에 대한 변화에 적합하여 추세를 살피기 위해 사용하며 시계열 분석에 특화되어 있다.

  • 시각화에서 기본적인 plot이기 때문에 .line이 아닌 .plot()을 사용

  • 많은 선이 중첩되면 가독성이 떨어지기 때문에 5개 이하의 선을 사용하는 것을 추천한다

  • 선을 구별하는 요소

    • 색상(color)
    • 마커(marker, markersize)
    • 선의 종류(linestyle, linewidth)

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

plt.show()
  • 전처리
    • 시계열 데이터는 Noise로 인해 패턴 및 추세파악이 어렵기 때문에 Noise의 인지적인 방해를 줄이기 위해 smoothing을 사용
    • smoothing을 통해 어떤 구간에 대해 평균을 내서 전체적인 추세를 보여줌

정확한 Line plot

추세


  • 추세를 보기 위한 목적이므로 bar plot과 다르게 꼭 축을 0에 초점을 둘 필요는 없음
  • 너무 구체적인 line plot보다는 생략된 line plot이 더 나을 수 있다.
  • 생략되지 않는 선에서 범위를 조정하여 변화율을 관찰하는 것이 좋다

  • EDA를 함에 있어서 실제값이 엄청 중요하고 디테일하게 봐야한다면 왼쪽처럼 그리는게 좋고, 전체적인 추세를 본다면 오른쪽의 그래프를 사용하는 것이 좋다

간격


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

  • 위의 차트들은 동일한 데이터로 그린 차트들로 데이터는 2,3,5,7,9 에 존재하며, 1과 2사이에는 기울기가 1이고 나머지는 2로 이루어져 있다.
  • 제일 왼쪽 그림에서는 간격을 규칙적으로 놓았기 때문에 2와 3의 기울기와 3과 5의 기울기가 같아 보이는데 실제로는 2와 3사이의 기울기가 조금 더 가파르게 보여야 정상이다.
  • 가운데 그림에서는 2,4,6,8번째 데이터가 존재하는 것처럼 느껴지기 때문에, 오른쪽 그림과 같이 관측 값에 점으로 표시하여 나타낸다.

보간


  • 점과 점 사이의 데이터가 없기에 이를 잇는 방법을 보간이라 한다.
  • 데이터의 error나 noise가 포함되어 있는 경우 데이터의 이해를 돕기 위해 사용한다.
  • Line plot의 smoothing과 같은 방법도 보간의 일종인데, 직선보다는 곡선을 선호하는 smoothing은 데이터가 없는데도 있다고 오해를 할 수 있고, 작은 차이가 없어질 수 있다.
  • 따라서, Presentation에서는 곡선이 이쁘게 나타나서 좋게 보일 수 있지만, 일반적인 분석에서는 곡선과 같은 보간방법을 지양하는 것이 좋다.

from scipy.interpolate import make_interp_spline, interp1d
import matplotlib.dates as dates

fig, ax = plt.subplots(1, 2, figsize=(20, 7), dpi=300)

date_np = google.index
value_np = google['close']

date_num = dates.date2num(date_np)

# 보간 적용
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)

ax[0].plot(date_np, value_np)
ax[1].plot(dates.num2date(date_num_smooth), value_np_smooth)

plt.show()

이중 축 사용


  • 서로 다른 종류의 데이터를 표현하기 위해 또는 한 데이터에 대해 다른 단위로 표현하기 위한 경우 하나의 plot에 대해 2개의 축을 이용할 수 있다.
  • 범위가 다른데 임의로 범위를 지정해주면 상관관계가 있어보이는 경우가 생기기 때문에 이중 축은 지양할 것

  • 구글 주식 가격과 거래량의 데이터를 이중 축으로 표현했지만, 굳이 동시에 그려야 할 이유가 없는 경우에는 두 개의 그래프로 나누어 그리는 것이 좋다
fig, ax1 = plt.subplots(figsize=(12, 7), dpi=150)

# 첫번째 그래프
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)

# 두번째 그래프
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)
  • 아래와 같이 이중 축을 사용하여 sin 그래프를 degree와 radian 두 단위로 표시할 수 있다.

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

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

fig, ax = plt.subplots()
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')
# 상단에 radian 단위표시
secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('angle [rad]')
plt.show()

ETC


  • 다음과 같이 범례 대신 라인 끝 단에 레이블을 추가하여 식별에 도움을 줄 수 있다.

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))
  • 최소,최대 값과 같은 원하는 포인트를 추가해주면 도움이 될 수 있다.
# max
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)

0개의 댓글