Data Analysis & ML/시계열분석

[시계열 분석] 정확도를 높이기 위한 Prophet 파라미터 활용

YSY^ 2022. 2. 13. 19:20

아래 포스팅에서 이어 진행됩니다

https://ysyblog.tistory.com/287

 

[시계열 분석] Prophet

Prophet 알고리즘 Paper: https://peerj.com/preprints/3190.pdf Quick Start: https://facebook.github.io/prophet/docs/quick_start.html 기본가정 자동화 된 기술은 상황에 맞게 튜닝하기 어렵고 경험적 지식을..

ysyblog.tistory.com

 

Growth 파라미터 

1. Saturating(데이터의 상한과 하한 설정)

  • 로지스틱 설정하여 비선형적 추정
  • Y 데이터의 상한과 하한을 반드시 설정해 주어야함. (cap, floor)
  • 파라미터에서 growth = "saturating" 으로 설정
  • Test 데이터도 상한, 하한값 설정 가능
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.05, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality='auto', # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])
fig = prophet.plot(pred_prophet)
add_changepoints_to_plot(fig.gca(), prophet, pred_prophet)
plt.xticks(rotation=90)
plt.show()

검은색 점선으로 상한과 하한 값이 설정되어 있다.

fig = prophet.plot_components(pred_prophet)
ax = fig.get_axes()
for i in range(len(ax)):
    ax[i].tick_params(axis="x", labelsize=15, rotation=90)
plt.show()

Trend 에 상한과 하한이 설정되어 있다.
이전보다 정확도가 더 좋아졌다.

Trend 파라미터

1. changepoint_prior_scale (추정 민감도)

  • 기본보다 10배 높임 (0.05 -> 0.5)
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality='auto', # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])
fig = prophet.plot(pred_prophet)
add_changepoints_to_plot(fig.gca(), prophet, pred_prophet)
plt.xticks(rotation=90)
plt.show()

changepoint의 숫자가 많이 늘어났다.
이전보다 더 좋아졌다.

Seasonality 파라미터

1. yearly_seasonality (연계절성)

  • auto : 알아서 지정
  • true : 강제로 지정
  • auto에서 true로 변경해서 확인
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])
fig = prophet.plot(pred_prophet)
add_changepoints_to_plot(fig.gca(), prophet, pred_prophet)
plt.xticks(rotation=90)
plt.show()

끝부분의 데이터가 아래로 가고 있다.
이전보다 더 안좋아졌다. -> 해당 데이터에서는 연간 추정이 별 효과가 없다

2. seasonality_prior_scale (계절성 민감도)

  • seasonality_prior_scale 를 10에서 20으로 증가시킨다
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])

민감도를 더 높여도 큰 차이는 없다.

3. add_seasonality(계절성 추가)

  • 계절성 파라미터를 추가로 넣을 수 있다 (add_seasonality)
  • 월 계절성을 추가해보겠다.
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

### monthly seasonality ###
prophet.add_seasonality(name='monthly', period=24*7*4, fourier_order=1)

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])
fig = prophet.plot_components(pred_prophet)
ax = fig.get_axes()
for i in range(len(ax)):
    ax[i].tick_params(axis="x", labelsize=15, rotation=90)
plt.show()

monthly 계절성 지표가 추가되었다.
성능은 더 안좋아졌다.

 

Holiday 파라미터

1. add_country_holidays (이벤트 효과 자동입력)

  • 해당 국가의 이벤트 날짜를 자동으로 넣어준다
  • country_name 으로 국가를 설정한다.
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=None, # 휴일 또는 이벤트 시점 dataframe
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

### holiday ###
prophet.add_country_holidays(country_name='US')

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])

빨간색 네모처럼 특정 event가 일어난 날짜는 예측을 다르게 해준다
hoilday 지표가 추가되었다.
정확도가 조금 더 좋아졌다.

 

2. 이벤트 효과 수동입력

  • 데이터프레임 형식으로 추가한다
  • lower_window : 해당 날짜 이전 날짜까지 포함
  • upper_window : 해당 날짜 이후 날짜까지 포함
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

### holiday ### -> 이벤트 수동입력
newyear = pd.DataFrame({'holiday': 'newyear',
                        'ds': pd.to_datetime(['2011-01-01', '2012-01-01']),
                        'lower_window': 0, # 이전날짜 포함범위
                        'upper_window': 1}) # 이후날짜 포함범위
christmas = pd.DataFrame({'holiday': 'christmas',
                          'ds': pd.to_datetime(['2011-12-25', '2012-12-25']), # 미래 시점도 포함
                          'lower_window': 0, # 이전날짜 포함범위
                          'upper_window': 1}) # 이후날짜 포함범위
holidays = pd.concat([newyear, christmas])


# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=holidays, ##### 휴일 이벤트를 수동으로 넣어준다 
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

### holiday ###
prophet.add_country_holidays(country_name='US')

prophet = prophet.fit(train_prophet)
forecast = prophet.make_future_dataframe(freq='H',  #시계열 데이터 frequncy 재검증
                                                        periods=Y_test.shape[0])

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])

테스트 성능이 조금 더 좋아졌다.

 

설명변수 반영 (Additional Features)

  • 추가 feature를 넣어줄 수 있다.
  • add_regressor 함수 활용
  • 컬럼을 하나하나씩 넣어야 한다.(for문 활용)
  • 예측할 때(forecast) X값을 추가로 넣어줘야한다.
# Applying Prophet Model
### saturating ###
saturating = 'logistic'

# 데이터에 상한/하한 값 설정 필요
if saturating == 'logistic':
    train_prophet['cap'] = 900  #예측 상한값
    train_prophet['floor'] = 0 # 예측 하한값

### holiday ### -> 이벤트 수동입력
newyear = pd.DataFrame({'holiday': 'newyear',
                        'ds': pd.to_datetime(['2011-01-01', '2012-01-01']),
                        'lower_window': 0, # 이전날짜 포함범위
                        'upper_window': 1}) # 이후날짜 포함범위
christmas = pd.DataFrame({'holiday': 'christmas',
                          'ds': pd.to_datetime(['2011-12-25', '2012-12-25']), # 미래 시점도 포함
                          'lower_window': 0, # 이전날짜 포함범위
                          'upper_window': 1}) # 이후날짜 포함범위
holidays = pd.concat([newyear, christmas])


# Applying Prophet Model
prophet = Prophet(growth='saturating', #linear -> 추세를 말함
        # Trend
        changepoints=None, # CP가 발생하는 시점들의 list ['2012-01-01']
        n_changepoints=25, # CP의 수
        changepoint_range=0.8, # CP의 기존 데이터 수 대비 최대 비율
        changepoint_prior_scale=0.5, # CP 추정 민감도로 높을수록 민감
        # Seasonality
        seasonality_mode='additive', # 계절성 모델: 'additive' or 'multiplicative'
        seasonality_prior_scale=10.0, # 계절성 추정 민감도로 높을수록 민감
        yearly_seasonality= True, # 연계절성
        weekly_seasonality='auto', # 주계절성
        daily_seasonality='auto', #일계절성
        # Holiday
        holidays=holidays, ##### 휴일 이벤트를 수동으로 넣어준다 
        holidays_prior_scale=10.0, # 휴일 추정 민감도로 높을수록 민감
        # Others
        interval_width=0.8, # 추세 예측 정확도 구간범위
        mcmc_samples=0) # 계절성 예측 정확도 제어

### holiday ###
prophet.add_country_holidays(country_name='US')

### extra feature ###
target_name = X_train_feRSM.columns[:5]
for col in target_name:
    prophet.add_regressor(col)

prophet = prophet.fit(train_prophet)

# extra feature 넣기
forecast = pd.concat([forecast, 
                      pd.concat([X_train_feRSM[target_name], 
                                 X_test_feRSM[target_name]], axis=0).reset_index().iloc[:,1:]], 
                      axis=1)

# Test 데이터도 상한/하한 설정 가능
if saturating == 'logistic':
    forecast['cap'] = 700
    forecast['floor'] = 0
    
pred_prophet = prophet.predict(forecast)
pred_tr_prophet = np.ravel(pred_prophet.loc[:Y_train.shape[0]-1, ['yhat']])
pred_te_prophet = np.ravel(pred_prophet.loc[Y_train.shape[0]:, ['yhat']])

정확도가 조금 더 좋아졌다.

 

해당 포스팅은 패스트캠퍼스의 <파이썬을 활용한 시계열 데이터 분석 A-Z 올인원 패키지> 강의를 듣고 정리한 내용입니다

728x90
반응형