📌 교내 융합소프트웨어프로젝트 수업에서 진행한 개인 데이터 분석 프로젝트에 대한 시리즈 글 입니다.
📌 서치한 자료들을 참고하여 프로젝트 데이터에 적용해 실습을 진행해보았습니다. 개인적으로 의문점이 들었던 부분은 이모지로 체크해두었기 때문에 해당 게시물은 참고용으로만 보아주시면 좋을 것 같습니다.
시계열 데이터 분석 기본
모델
👀 정상성
◽ 정상 프로세스 : 시간에 관계 없이 평균과 분산이 일정한 시계열 데이터
◽ 비정상 프로세스 : 시간에 관계 없이 평균과 분산이 일정하지 않은 시계열 데이터
👉 가로축을 현재 데이터와의 시점 차이로 y 축을 ACF 로 시각화할 때 특정 패턴이 없으면 정상 프로세스로 간주한다.
◾ AC autocorrelation : 자기 자신의 데이터와의 관계를 의미
👀 시계열 기본 모형
◽ AR 자기 회귀 : 이전 관측값의 오차항이 이후 관측값에 영향을 주는 모형
◽ MA 이동평균 : 관측값이 이전의 연속적인 오차항의 영향을 받는 모형
◽ ARMA : AR + MA 모델
◽ ARIMA : 시계열 값에 따라 변동하는 값의 평균을 통합하여 자동으로 회귀분석을 하는 모델
- 비정상 시계열인 ARMA 모델에 차분을 d 번 수행하여 정상 시계열로 변형할 때 사용하는 모델로, 기존 AR, MA, ARMA 모델은 데이터가 항상 정상이어야 하는 지점을 극복해 나온 모형이다.
from statsmodels.tsa.arima_model import ARIMA
import statsmodels.api as sm
model = ARIMA(df["target"].values, order(2, 1, 2)) # 👀 order(p,d,q)
model_fit = model.fit(trend="c", full_output = True, disp = True)
model_fit.summary()
# 예측값 시각화
model_fit.plot_predict()
# 데이터 예측
forecast_data = model_fit.forecast(steps=N) # N : 예측할 날짜수
👀 시계열 딥러닝 분석
◽ RNN, LSTM, GRU
👀 시계열 데이터 시각화
from matplotlib import pyplot
df.plot()
pyplot.show()
Prophet
0️⃣ Prophet
👀 페이스북이 만든 시계열 분석 라이브러리 at business-time series
◽ 기존 시계열 분석 방법 : auto.arima , ets 지수평활법, seasonal naive 방법, tbats (주,년도 계절성 고려)
◽ ARIMA 등 기존 시계열 모형과 달리 시간에 종속적인 구조를 가지고 있지 않다. Curve fitting 으로 문제를 해결한다.
◽ g(t) : 반복적인 요소를 가지지 않은 트렌드/추세 Growth
- Linear Growth vs Non-linear Growth
- 변경점을 선택하여 추세의 변화를 자동으로 감지 가능
◽ s(t) : 사용자들의 행동 양식으로 주기적으로 나타나는 패턴 Seasonality
- 방학,휴가,온도,주말 등
- 연간/주간 계절 성분
◽ h(t) : 주기성을 가지진 않지만 전체 추이에 큰 영향을 주는 이벤트가 존재 Holidays
- 이벤트 앞뒤로 window 범위를 지정해 해당 이벤트가 미치는 영향의 범위를 설정할 수 있다.
◽ e : 정규분포를 따르는 잔차
◽ 기존 시계열 방법과 비교했을 때, forecast 에 대한 에러 비율이 가장 낮은 것이 prophet 이다.
👀 용어 정리
◾ Capacities : 시계열 데이터 전체의 최대값
◾ Change Points : 추세가 변화하는 시점
◾ Holidays & Seasonality : 추세에 영향을 미치는 시기적 요인들
◾ Smoothing : 각 요소들이 전체 추이에 미치는 영향의 정도
→ 직관적인 파라미터들을 쉽게 조정하여 Prophet 을 반복적으로 수행한다.
👀 Prophet 을 사용하기 좋은 경우
◾ 많은 시계열 데이터 (연 단위 이상이면 좋음)
◾ 불규칙적으로 일어나지만 사전에 시점을 알고있는 이벤트가 있는 경우 ex. 한국 시리즈, 크리스마스
◾ 결측치가 어느정도 존재하거나 아웃라이어가 많은 경우
◾ 특정 이벤트로 인해 장기적인 추이가 변할 수 있는 경우 ex. 신제품 출시, 디자인 변경
◾ 지표가 선형적으로 증가하지 않을 경우 : 증가할 수 있는 지표의 최대치가 존재하고 이를 알고있는 경우
📑 분석 예제
◽ 비트코인 가격 Trend : 2017년 4월~6월 일별 데이터로 7월 추이 예측
1️⃣ 기본 사용법
👀 파라미터
참고자료
💨 https://today-1.tistory.com/41
💨 https://predictor-ver1.tistory.com/4
💨 Prophet 파라미터 : https://velog.io/@choijhyeok/Prophet-1-parameter-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
◾ growth = 'linear' : 선형 비선형 선택
◾ growth = 'logistic' : cap, floor 이라는 값을 설정. 정해진 기준은 없고 모델을 돌리고 난 후 설정하는 것을 추천
◾ 추세 관련 파라미터
changepoints | change points 가 발생하는 시점들의 날짜 list를 직접 지정 |
n_changepoints | change_prior_scale 에 따라 변동점의 숫자가 자동적으로 지정되는데, CP 의 개수를 직접 지정하고 싶은 경우 사용 ((default = 25) |
changepoint_range | CP 의 기존 데이터 수 대비 최대 비율 (0.8~0.95) ◾ 디폴트 0.8 ◾ 오버피팅을 피하기 위해 학습 데이터의 앞부분의 몇 %를 사용할 것인지 지정해주는 파라미터 |
chagepoint_prior_scale ⭐⭐⭐ | CP 추정 민감도 (0~1), 높을수록 민감 (값을 크게할수록 유동적으로 찾으나 - 빨간 점선의 개수가 많아짐, 오버피팅 우려가 있다) 👉 추세에 덜 유연하게 반영하려면 0.05보다 작게 👉 추세에 유연하게 반영하려면 0.05보다 크게 👉 모델 성능에 큰 영향력을 줬던 파라미터 |
◾ 계절성 관련 파라미터
seasonality_mode | 계절성 모델 : 'additive' or 'multiplicative' ◾ 시계열 데이터 진폭이 점점 증가하거나 감소할 때 사용 : multiplicative ◾ 시계열 데이터 진폭이 일정할 때 사용 : additive |
seasonality_prior_scale ⭐⭐⭐ | 계절성 추정 민감도 (10이 default, 값이 높을수록 계절성의 영향도가 높아짐) 👉값의 범위 : (0.01 ~ 10) |
yearly_seasonality ⭐⭐⭐ | ◾ 연계절성 (10 이 default) → 값을 올리면 계절성의 fitting 이 더 복잡해진다. ◾ 'auto', 'True', 'False' → True 면 연간 트렌드를 분석해서 패턴을 자동으로 학습 |
weekly_seasonality | 월계절성 |
daily_seasonality |
일계절성 |
◾ 휴일 관련 파라미터
holidays | 휴일 또는 이벤트 시점 등을 직접 지정하여 넣는 것이 가능 ◾ 데이터 프레임 형태로 이벤트 날짜를 정의하고 그것을 파라미터로 설정 |
holidays_prior_scale ⭐⭐⭐ | 휴일 추정 민감도 (높을수록 민감) 👉 값의 범위 : (0.01 ~ 10) |
◾ 기타
interval_width | 추세 예측 정확도 구간 범위 |
mcmc_samples | 계절성 예측 정확도 제어 (계절성의 신뢰구간 설정) |
# Applying Prophet Model
fit_default_prophet = Prophet(
# 1) linear, nonlinear
growth='linear',
# 2) Trend
changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
n_changepoints=25, # CP의 수
changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
changepoint_prior_scale=0.05, # CP 추정 민감도로 높을수록 민감
# 3) Seasonality
seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
yearly_seasonality='auto', # 연계절성
weekly_seasonality='auto',# 월계절성
daily_seasonality='auto', #일계절성
# 4) Holiday
holidays=None, # 휴일 또는 이벤트 시점
dataframe holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
# 5) Others
interval_width=0.8, # 추세 예측 정확도 구간범위
mcmc_samples=0, # 계절성 예측 정확도 제어
)
'앱 접속자' 시계열 데이터 분석해보기
!pip install -q fbprophet==0.7.1
from fbprophet import Prophet
① 데이터를 Prophet 에 맞도록 가공한다.
◽ 이때 필요한 칼럼은 ds, y 2개이다.
◽ ds 는 2022-05-12과 같은 날짜 칼럼
◽ y 는 분석하고자 하는 target feature 변수에 해당
💨 int 로 되어있는 날짜 변수를 datetime 으로 변환하기
# 날짜형으로 변환
app_use['연월일'] = app_use['연월일'].astype(str)
app_use['연월일'] = pd.to_datetime(app_use['연월일'])
print(app_use['연월일'])
df = app_use[['연월일','접속자']]
df.rename(columns={'연월일':'ds','접속자':'y'}, inplace=True)
② Prophet 객체를 생성하고 fitting
m = Prophet() # default growth = 'linear'
m.fit(df)
◽ 상한과 하한을 설정할 경우엔 Prophet 객체를 생성할 때 growth='logistic' 을 추가한다.
③ 예측값까지 포함한 시계열 데이터를 담기 위한 Dataframe 생성, 예측, 시각화
◾ make_future_dataframe 을 사용하여 지정된 날짜 수만큼 미래로 확장되는 적절한 데이터 프레임을 얻을 수 있다.
◾ period = 예측할 날짜 수
◾ freq → period 에 입력한 숫자를 'd' 는 일, 'm' 은 월, 'y' 는 연을 기준으로 지정
future = m.make_future_dataframe(periods=15)
forecast = m.predict(future)
m.plot(forecast, xlabel='month', ylabel='app_come')
plt.show()
◽ forecast 결과 확인 👉 yhat_lower, yhat_upper 같이 범위로 제공해줌
forecast.columns
>>Index(['ds', 'trend', 'yhat_lower', 'yhat_upper', 'trend_lower', 'trend_upper',
'additive_terms', 'additive_terms_lower', 'additive_terms_upper',
'yearly', 'yearly_lower', 'yearly_upper', 'multiplicative_terms',
'multiplicative_terms_lower', 'multiplicative_terms_upper', 'yhat'],
dtype='object')
◽ yhat : 예측값, yhat_lower : 최소치, yhat_upper : 최대치
④ Forecast component 시각화 : Trend, Weakly, Yearly
◾ 예측에 사용된 구성요소 살펴보기 : 추세, 연간 계절성, 주간 계절성
m.plot_components(forecast)
plt.show()
✔ weekly, yearly 에서 y축이 음수 값을 가지는 이유는 🤔
◯ 데이터 상한 하한 설정
- 기존 데이터 테이블에 ['cap'] 으로 상한치를 ['floor'] 로 하한치 열을 만들고, 값을 지정하면 된다 → 이것을 fit, predict 인자로 넘겨주면 됨 👉 시각화 그래프에 상하한선을 점선으로 표기해줌
2️⃣ Trend Change Points
👀 트렌드가 변경되는 지점을 자동으로 감지해 트렌드를 예측한다
◽ 통계적으로 적절하다고 생각하는 구간으로 나누어 각 구간별로 fitting을 새로한다.
◽ 변동 포인트의 수, 데이터 길이, 어느정도 변화를 변동 지점으로 할 것인지 등을 조절해 모델을 튜닝할 수 있다.
① Changepoint_range
◽ 기본적으로 시계열 데이터의 80% 크기에서 잠재적으로 지정한다.
◽ N 은 비율값으로 ex. 0.7 을 입력
m = Prophet(changepoint_range = N)
② changepoint_prior_scale
◽ Change Point 의 유연성을 조정하는 방법으로 , 오버피팅이 심하면 너무 유연한 그래프가 나와 모든 값에 근접하고, 언더피팅일 경우에는 유연성이 부족하다.
◽ 기본값 = 0.05 👉 값을 늘리면 그래프가 유연해짐 (언더피팅 해결), 값을 줄이면 유연성이 감소(오버피팅 해결)
m = Prophet(changepoint_prior_scale=N)
③ changepoints (리스트형태로 입력)
◽ 잠재적으로 change point 일 수 있는 날짜들로 명시하지 않으면 잠재적인 chagepoint 가 자동으로 설정된다.
④ 시각화
◽ changepoint_prior_scale=0.03 로 fitting
from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)
◽ 빨간점선 : Changepoint , 빨간 실선 : Trend
◽ 각 세로 점선 사이에, 빨간 직선으로 값이 선형적으로 연결되어 있는 것을 확인해볼 수 있다. 이 빨간 선형 직선에 계절성, 휴일, 잔차등을 넣은 것이 파란색 선인 모델의 예측값이 된다.
3️⃣ Seasonality, Holiday Effects, and Regressors
👀 휴일이나 모델에 반영하고자 하는 이벤트가 있으면
dataframe 를 생성해 반영이 가능하다.
◽ Prophet 객체를 생성할 때, holidays 인자로 넘긴다.
◽ 주변 날짜를 포함시키기 위해 lower_window, upper_window 를 사용해 업데이트의 영향을 조절할 수 있다. (ex. 크리스마스 이브, 크리스마스 당일)
holiday_in_kor = pd.DataFrame({
'holiday': 'holiday_kor',
'ds': pd.to_datetime(['2017-05-05', '2018-05-05', '2019-05-05', '2020-05-05', '2021-05-05']),
'lower_window': 0,
'upper_window': 1,
})
# 👀 어린이날
m = Prophet(holidays=holiday_in_kor)
forecast = m.fit(df).predict(future)
fig = m.plot_components(forecast)
✨ KR 한국 휴일도 prophet 에서 지원해줌!
model.add_country_holidays("KR", mode="additive", lower_window=-1, upper_window=1)
4️⃣ Neuralprophet
참고자료
◾ http://insightcampus.co.kr:9090/insightcommunity/?mod=document&uid=12964 👉 S&P 주식시장 가격 예측 예제
업데이트 된 버전의 Prophet 으로 개발자들이 작업을 예측하기 위해 AR-Net 같은 딥러닝 모델을 추가했다.
pip install neuralprophet
# 혹은 pip install neuralprophet[live] 👉 모델에 대한 훈련 및 검증 손실을 실시간으로 시각화 가능
from neuralprophet import NeuralProphet
👀 훈련 매개변수
◽ validate_each_epoch : 각 시기의 유효성 검사 데이터에 대한 모델 성능을 검증할지 여부
◽ valid_p : 유효성 검사에 사용할 데이터의 비율 (0~1 사이 값)
◽ plot_live_loss : 훈련 및 검증 손실에 대한 라이브 플롯 생성여부
◽ epochs : 훈련 에포크 수
model = NeuralProphet()
metrics = model.fit(prcp_data, validate_each_epoch=True,valid_p=0.2, freq='D', plot_live_loss=True, epochs=10)
👀 예측
future = model.make_future_dataframe(data, periods=숫자)
forecast = model.predict(future)
forecasts_plot = model.plot(forecast)
👀 Trend
◽ n_changepoints : 데이터의 광범위한 트렌드(증가율)이 변화하는 포인트 수를 지정한다.
◽ trend_reg : 변경 지점 선택의 유연성을 제어하는 정규형 파라미터 : 값이 (1~100) 클수록 변경 지점의 변동성이 제한된다. 값이 작을수록 (0.0001~1.0) 변경 지점의 변동성이 커진다.
가령 위와 같은 주가 그래프가 있을 때, 가격이 크게 오르거나 내려가는 여러 포인트들과 함께 일반적으로 증가하는 추세를 보이는데, 이때 크게 오르내리는 지점을 체인지 포인트로 생각할 수 있다.
model = NeuralProphet(n_changepoints=100,trend_reg=0.05,yearly_seasonality=False,weekly_seasonality=False,daily_seasonality=False)
metrics = model.fit(data, validate_each_epoch=True,valid_p=0.2, freq='D',plot_live_loss=True,epochs=100)
# 예측
plot_forecast(model, data, periods=60)
👀 Seasonality
◽ 시계열 데이터는 계절 패턴과 연관된 경우가 많다.
model = NeuralProphet(n_changepoints=100,trend_reg=0.5,yearly_seasonality=True,weekly_seasonality=False,daily_seasonality=False)
metrics = model.fit(data, validate_each_epoch=True,valid_p=0.2, freq='D',plot_live_loss=True,epochs=100)
# 예측
plot_forecast(model, data, periods=60, historic_predictions=True)
👀 AR-Net
◽ 시계열 예측에 사용되는 자기 회귀 신경 네트워크이다.
◽ 이전 시간 단계의 과거 데이터를 사용해 다음 시간 단계에 대한 예측을 생성한다.
◽ 모형의 입력 : 이전 시간 단계의 타깃 변수 값 (자기회귀)
💨 해당 예제에선 AR-Net 이 주식시장의 변동성을 가장 잘 포착했음
model = NeuralProphet(n_forecasts=60,n_lags=60,n_changepoints=100,yearly_seasonality=True,weekly_seasonality=False,
daily_seasonality=False,batch_size=64,epochs=100,learning_rate=1.0)
# n_lages, n_forecasts 인자를 통해 (참고할 지난 데이터 일수, 예측할 일수) 를 지정해준다.
model.fit(data,freq='D',valid_p=0.2,epochs=100
plot_forecast(model, data, periods=60, historic_predictions=True)
👀 Events
◽ 일부 공휴일, 특정 기념일 등은 시계열 데이터 target 값에 중요한 작용을 미칠 수 있다.
model = model.add_country_holidays("KR", mode="additive", lower_window=-1, upper_window=1)
5️⃣ 이상치 탐지
참고자료
◾ https://towardsdatascience.com/anomaly-detection-time-series-4c661f6f165f
⭐ 이상치 검출
m = Prophet(daily_seasonality = True)
m.fit(data) # 훈련
future = m.make_future_dataframe(periods=365)
pred = m.predict(future) # 예측
m.plot(pred) # 시각화
# ⭐ 이상치 검출
andf = pred[['ds', 'trend', 'yhat', 'yhat_lower', 'yhat_upper']]
andf['y'] = y # y는 실제 시계열 리스트
andf['anomaly'] = 0 # anomaly 감지 태그 컬럼 생성
andf.loc[andf['y'] > andf['yhat_upper'], 'anomaly'] = 1
## 관측치가 최대치보다 큰경우
andf.loc[andf['y'] < andf['yhat_lower'], 'anomaly'] = -1
## 관측치가 최소치보다 작은경우
⭐ 이상치 중요도 검출
◽ 이상치의 심한 정도를 구별
◽ y 값과 yhat_upper 과의 차이 (또는 yhat_lower 와의 차이) 를 y 값으로 나누어 구한다.
andf['importance'] = 0 # 이상치 중요도 컬럼 추가
andf.loc[andf['anomaly'] == 1, 'importance'] = (andf['y'] - andf['yhat_upper']) / andf['y']
andf.loc[andf['anomaly'] == -1, 'importance'] = (andf['yhat_lower'] - andf['y']) / andf['y']
andf['score'] = andf['anomaly'] * andf['importance']
6️⃣ 모델 평가/교차검증 분석
참고자료
◾ https://dining-developer.tistory.com/25
⭐ 예측 모델 평가하기
◽ 데이터셋의 일부를 test set 으로 빼서 학습 시킨 뒤 예측이 잘 되는지 살펴보기
# y_true 따로 생성 : 마지막 12개월 제외시키기
train = df.drop(df.index[-12:])
y_true = df['y'][-12:].values
# 모델 생성 후 학습
model = Prophet()
model.fit(train)
# train set 마지막 1년 날짜 생성 (설정한 날짜 범위에 맞춰서)
last_1year = list()
for i in range(1, 13):
last_1year.append(['1968-%02d' % i])
last_1year = pd.DataFrame(last_1year, columns = ['ds'])
last_1year['ds']= pd.to_datetime(last_1year['ds'])
# 예측하고 비교하기
# 여기에서는 MAE를 살펴본다.
forecast = model.predict(last_1year) # ⭐ 위에서 생성한 날짜 범위에 맞춰 입력/예측
y_pred = forecast['yhat'].values
from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error(y_true, y_pred)
print('MAE: %.3f' % mae) # ⭐ MAE 평가지표 : 값이 작을수록 좋은 모델
# 그래프 그려보기 (실제/예측 데이터)
pyplot.plot(y_true, label='Actual')
pyplot.plot(y_pred, label='Predicted')
pyplot.legend()
pyplot.show()
⭐ 교차검증 분석
◽ 예측 기간 (horizon) 을 지정한 다음 선택적으로 초기 훈련 기간 (initial) 의 크기와 컷오프 날짜 사이의 간격 (period) 를 지정한다.
◽ 기본적으로 초기 훈련기간은 horizon 의 3개로 설정되며 cutoff 는 수평선의 절반마다 이루어진다.
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(df_prophet, itnitial = '1095 days', period = '180 days', horizon = '365 days')
df_cv.head()
👉 첫번째 컷오프(🤔) 에서 730일의 훈련 데이터로 시작하여 180일 마다 예측을 수행하여 365일 범위에서 예측 성능을 평가하기 위해 교차 검증을 수행
⭐ 모형 성능 확인
◽ 컷오프로부터의 거리 즉, 예측이 얼마나 빗나갔는지 확인
from fbprophet.diagnostics import performance_metrics
df_p = performance_metrics(df_cv)
df_p.head()
⭐ 교차검증 결과 시각화
from fbprophet.plot import plot_cross_validation_metric
fig = plot_cross_validation_metric(df_cv, metric = 'mae')
참고자료
◾ https://zzsza.github.io/data/2019/02/06/prophet/
◾ https://www.slideshare.net/lumiamitie/facebook-prophet
◾ https://teddylee777.github.io/data_science/prophet-stock-forecast
◾ https://www.youtube.com/watch?v=teD60NOLQL0&list=PLSlDi2AkDv831sk-XATACzvjE7ayqszkk&index=1
◾ 논문 리뷰 : https://koreapy.tistory.com/574
◾ 단계별로 잘 정리되어있는 블로그 : https://zamezzz.tistory.com/category/AI/Prophet
◾ Neural Prophet : https://github.com/ourownstory/neural_prophet
◾ Prophet : https://github.com/facebook/prophet
◾ Prophet 예측 : https://health-coding.tistory.com/48, https://ysyblog.tistory.com/287
'2️⃣ Study > ▢ 필사 | 프로젝트' 카테고리의 다른 글
[개인 프로젝트] 시계열 이상치 탐지 스터디 ② (0) | 2022.05.11 |
---|---|
[개인 프로젝트] 시계열 이상치 탐지 스터디 ① (0) | 2022.05.09 |
Pycaret - AutoML (0) | 2022.04.13 |
[kaggle] 2021년 여름방학 필사 스터디 파일 (0) | 2022.04.06 |
[kaggle] 필사정리 Note_5 (0) | 2022.04.02 |
댓글