빅데이터 QAQC_3기/빅데이터 QAQC_3기 TIL

TIL_251118

usungusung 2025. 11. 18. 21:32

Today I learned

 

 

1. [라이브세선] 시계열 데이터의 개요

 

MLops: 머신러닝 + operation, 주피터 노트북에만 코딩하고 끝나는게 아닌 사내 operation 시스템에 적용하는 것 까지 목표로

 

키워드: ARIMA, Prohphet, Docker, BentoML

 

(1) 시계열 분석?

  • 과거의 흐름으로 미래를 예측하는 방법론
  • 시게열 분석은 통계학&데이터 사이언스의 전공 과목에서도 전공 선택으로, 난이도가 높음
  • 과거의 트렌드로 미래를 예측할 수 있다는 논리로 많은 회사들이 시게엶 모델을 적용하고 있음
  • Meta - Prophet 모델, 딥러닝: LSTM, RNN, Transfomer(LLM)모델 등이 개발

 

- 추천 컨텐츠: 파이썬 시계열 예측 분석

https://github.com/jpub-dongdong9/TimeSeriesForecastingInPython/tree/master

 

GitHub - jpub-dongdong9/TimeSeriesForecastingInPython: Jpub 출간, 한국어 번역서를 위한 소스 코드 저장소입니

Jpub 출간, 한국어 번역서를 위한 소스 코드 저장소입니다. Contribute to jpub-dongdong9/TimeSeriesForecastingInPython development by creating an account on GitHub.

github.com

 

 

 

(2) 시계열 예측의 이해

- 시계열 데이터의 정의

  • 시간에 따라 정렬된 데이터
  • 주기적으로 기록되며, 동일한 시간단계로 분포한다고 정의

- 시계열 데이터의 구성 요소

 

a. 계절성(Seasonality)

  • 일정한 경향에 따라 반복되는 패턴
  • 주로 연간 주기를 따르며, 특정 계절에 따라 데이터가 변동을 보이는 경우
  • 일반적으로 시간에 관련된 고정된 주기를 가지고 있음(예시. 여름에 에어컨 더 잘 팔림)

 

b. 추세(Trend)

  • 지속적으로 일관된 방향으로 변화하는 장기적 패턴
  • 패턴은 증가, 감소, 일정한 상태

 

c. 주기성(Cycles)

  • 경제적, 사회적 ,정치적 요인에 의해 발생하는 불규칙한 변동 패턴
  • 장기적이고 불규칙한 패턴 - 계절성과의 차이점
  •  
개념 계절성 주기
규칙성 일정한 간격으로 반복(매년,매월) 불규칙적으로 발생
발생 원인 계절적인 요인(기후 등) 경제, 사회적인 요인(경기순환)
예측 가능성 규칙적이므로 예측 가능 변동성이 커서 예측 어려움
시간 범위 1년 이내 수년 이상

 

 

d. 잔차(Residual)

  • 흔히 오차라고 얘기함, 시계열이 통계 기반이라 '잔차'라고 한다
  • 시게열 데이터에서 추세와 계절성을 제거한 후 남는 무작위적 변화량

  • (a) 200 거래일 동안의 구글 주식 가격: 추세 (2015년이후로 꾸준히 상승)
  • (b) 200 거래일 동안의 구글 주식 가격의 일일 변동 → 3가지다 없음!
  • (c) 미국의 연간 파업 수: 추세(하락 후 상승), 주기

 

(3) 시계열 분해(Time Series Decomposition)

  • -시계열 분해를 통해 각 구성요소를 시각화하면 데이터로 파악하기 어려운 추세와 게절적 패턴을 파악하는데 큰 도움이 된다.
    • 계절적 구성요소: 시계열의 계절적 패턴, 주기는 일정 기간동안 반복적으로 발생
    • 추세는 시계열에서 느리게 움직이는 큰 변화를 말함
    • 잔차는 추세 및 계절성으로 설명할 수 없는 변동

맨 위 데이터를 시계열 분해하면 위와 같은 추세, 계절성, 잔차를 확인할 수 있음!

 

 

(4) 시계열 예측 vs 회귀예측

같은데 다름

 

 

a. 시계열 데이터는 순서가 있다.

  • 시계열 데이터의 순서를 섞게 되면 모델이 올바른 패턴을 학습할 수 없음
    • 이렇게 될 경우 '시간 종속성을 해쳤다' 라고 말함
  • 반면, 회귀분석에서는 데이터의 순서가 중요하지 않은 경우가 많음.
  • 시계열 데이터는 시간에 따른 순서가 매우 매우 줜나 중요함.

 

b. 시계열에는 피처가 데이터 하나.

  • 회귀분석의 경우, 여러 피처를 사용해 목표 변수를 예측하는 것이 일반적임.

  • 시계열 분석에서는 시간의 흐름에 따라 특정 시점에 관측된 값에 기반해, 주로 과거의 값(피처)을 사용하여 미래의 값을 예측합니다.

  • 과거 시점의 데이터 자체가 피처 역할, 시간 의존성이 핵심임
    • 자기회귀모델(AR): 과거 값을 기반으로 미래 값을 에측
    • 이동평균모델(MA): 과거의 잔차(Residuals)를 활용해 예측

 

(5) 베이스라인 실습

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

pd.options.mode.chained_assignment = None
기본 라이브러리 불러오기

마지막은 경고 표시 끔 이소리임
깃허브에 있는 데이터를 복사하여 파일 칸으로 가져오는 코드임.
df = pd.read_csv('/content/TimeSeriesForecastingInPython/data/jj.csv')
df.head()
Plot data with train/test split
fig, ax = plt.subplots()

ax.plot(df['date'], df['data'])
ax.set_xlabel('Date')
ax.set_ylabel('Earnings per share (USD)')
ax.axvspan(80, 83, color='#808080', alpha=0.2)

plt.xticks(np.arange(0, 81, 8), [1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980])

fig.autofmt_xdate()
plt.tight_layout()

# plt.savefig('figures/CH02_F01_peixeiro.png', dpi=300)
-  ax.axvspan(80, 83, color='#808080', alpha=0.2)
구간 80~83을 #808080으로 하이라이트

-  fig.autofmt_xdate()
X축 라벨이 겹치지 않도록 자동 회전


 Split to train/test
- 훈련 데이터: 1960년부터 1979년까지 분기
- 테스트 데이터: 1980년도4개의 분기
train = df[:-4]
test = df[-4:]
test


요 뒤에서 4개 빼고 싹 다 train으로 돌리겠다!

 

 

A. Predict Historical mean: 단순 평균으로 예측해볼까

historical_mean = np.mean(train['data'])
historical_mean
np.float64(4.308499987499999)
test.loc[:, 'pred_mean'] = historical_mean

test
MAPE(Mean Absolute Percentage Error)
예측 오차를 백분율로 나타낸 지표
예측값-실제값의 차이를 백분위로 표현하여 직관적ㅇ니 이해
0%에 가까울 수록 좋은 모
def mape(y_true, y_pred):
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
 
mape_hist_mean = mape(test['data'], test['pred_mean'])
mape_hist_mean
np.float64(70.00752579965119)
fig, ax = plt.subplots()

ax.plot(train['date'], train['data'], 'g-.', label='Train')
ax.plot(test['date'], test['data'], 'b-', label='Test')
ax.plot(test['date'], test['pred_mean'], 'r--', label='Predicted')
ax.set_xlabel('Date')
ax.set_ylabel('Earnings per share (USD)')
ax.axvspan(80, 83, color='#808080', alpha=0.2)
ax.legend(loc=2)

#2년간격으로 8씩 증가하는 배열을 생성하여 x축을 정리
plt.xticks(np.arange(0, 85, 8), [1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980])

#x축 눈금 자동서식
fig.autofmt_xdate()
#여백 제거
plt.tight_layout()

# plt.savefig('figures/CH02_F06_peixeiro.png', dpi=300)
  • 전체 평균으로 진행한 결과, 올바르지 못한 데이터임을 알 수 있음. predict 부분 봐바라...

 

B. Predict last year mean: 직전 데이터를 이용 - train에서 마지막 4분기 데이터 평균

last_year_mean = np.mean(train['data'][-4:])
last_year_mean
np.float64(12.96)
test.loc[:, 'pred__last_yr_mean'] = last_year_mean

test
mape_last_year_mean = mape(test['data'], test['pred__last_yr_mean'])
mape_last_year_mean
np.float64(15.5963680725103)
fig, ax = plt.subplots()

ax.plot(train['date'], train['data'], 'g-.', label='Train')
ax.plot(test['date'], test['data'], 'b-', label='Test')
ax.plot(test['date'], test['pred__last_yr_mean'], 'r--', label='Predicted')
ax.set_xlabel('Date')
ax.set_ylabel('Earnings per share (USD)')
ax.axvspan(80, 83, color='#808080', alpha=0.2)
ax.legend(loc=2)

plt.xticks(np.arange(0, 85, 8), [1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980])

fig.autofmt_xdate()
plt.tight_layout()

# plt.savefig('figures/CH02_F07_peixeiro.png', dpi=300)

 

 

C. Predict last know value: 마지막 측정 데이터 이용하기

last = train['data'].iloc[-1]
last
np.float64(9.99)
test.loc[:, 'pred_last'] = last

test
fig, ax = plt.subplots()

ax.plot(train['date'], train['data'], 'g-.', label='Train')
ax.plot(test['date'], test['data'], 'b-', label='Test')
ax.plot(test['date'], test['pred_last'], 'r--', label='Predicted')
ax.set_xlabel('Date')
ax.set_ylabel('Earnings per share (USD)')
ax.axvspan(80, 83, color='#808080', alpha=0.2)
ax.legend(loc=2)

plt.xticks(np.arange(0, 85, 8), [1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980])

fig.autofmt_xdate()
plt.tight_layout()

# plt.savefig('figures/CH02_F08_peixeiro.png', dpi=300)

좋은 방향은 아닌거 같죠...?

 

 

D. Naive seasonal forecast: 단순한 게절적 예측, 마지막으로 측정된 계절성이 미래에도 반복된다! 라는 개념

#1979년 마지막 5분기의 데이터
test.loc[:, 'pred_last_season'] = train['data'][-4:].values

test
mape_naive_seasonal = mape(test['data'], test['pred_last_season'])
mape_naive_seasonal
 
np.float64(11.561658552433654)

예측력 자체는 가장 좋다!
fig, ax = plt.subplots()

ax.plot(train['date'], train['data'], 'g-.', label='Train')
ax.plot(test['date'], test['data'], 'b-', label='Test')
ax.plot(test['date'], test['pred_last_season'], 'r--', label='Predicted')
ax.set_xlabel('Date')
ax.set_ylabel('Earnings per share (USD)')
ax.axvspan(80, 83, color='#808080', alpha=0.2)
ax.legend(loc=2)

plt.xticks(np.arange(0, 85, 8), [1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980])

fig.autofmt_xdate()
plt.tight_layout()

# plt.savefig('figures/CH02_F09_peixeiro.png', dpi=300)
fig, ax = plt.subplots()

x = ['hist_mean', 'last_year_mean', 'last', 'naive_seasonal']
y = [70.00, 15.60, 30.46, 11.56]

ax.bar(x, y, width=0.4)
ax.set_xlabel('Baselines')
ax.set_ylabel('MAPE (%)')
ax.set_ylim(0, 75)

for index, value in enumerate(y):
    plt.text(x=index, y=value + 1, s=str(value), ha='center')

plt.tight_layout()

# plt.savefig('figures/CH02_F10_peixeiro.png', dpi=300)

Mape가 0에 가까울 수록 가장 좋은 모델

 

(6) 베이스라인 정리

  • 모델은 가장 간단한모델부터 하나씩 변수를 바꿔가며 테스트하면 해석력이 좋아진다.
  • 베이스라인 모델은 평균을 이용한는 것이 대표적이다.
  • MAPE는 예측값이 실제값과 얼마나 차이나는지 직관적으로 측정하는 지표이다.
  • 머신러닝 모델을 어렵게 진행하는 경우가 많아요... AI 도움 받아서  이해못하는 모델코드를 써서 그걸 해석하려고 함... 응용하기 힘든 경우가 많음
  • 0에 대한 베이스 모델을 먼저 만들어보셈, 가장 간단하고 무식하고 이해하기 편한 기본을 만드셈
  • 시계열적인 내용을 넣어보고, 첨가를 통해 베이스모델보다 좋아지냐 나빠지냐를 체크
  • 왜 이 변수와 우리의 방법이 유용했냐? 를 체크해야함
  • 시게열 모델에서도 사람이 이해할 수 있는 방법으로 넣어서...

 

 

2. 태블로를 활용한 데이터 시각화

 

'빅데이터 QAQC_3기 > 빅데이터 QAQC_3기 TIL' 카테고리의 다른 글

TIL_251120  (0) 2025.11.20
TIL_251119  (0) 2025.11.19
TIL_251117  (0) 2025.11.17
TIL_251114  (0) 2025.11.14
TIL_251112  (0) 2025.11.12