본문 바로가기
Analysis/Time series

Lecture 10. 타겟 데이터 정상성 변환

by 5ole 2021. 3. 27.

 

 

정상성 (Stationarity)

 

  • 평균, 분산, 공분산이 시간의 흐름에 따라 변하지 않음

 

정상성 / 평균, 분산, 공분산 비정상

 

  • 약정상 - 두 변수 비교

 

  1. 𝐸(𝑋𝑡) = 𝜇  for all time 𝑡 (The first moment estimation)
  2. 𝑉𝑎𝑟(𝑋𝑡) = 𝐸(𝑋^2𝑡) − 𝐸(𝑋𝑡)^2 <∞  for all time 𝑡 (The second moment estimation)
  3. 𝐶𝑜𝑣(𝑋𝑖𝑠,𝑋𝑖𝑘) = 𝐶𝑜𝑣(𝑋𝑖(𝑠+ℎ), 𝑋𝑖(𝑘+ℎ))=𝑓(ℎ)  for all time  𝑠, 𝑘, ℎ (The cross moment estimation)                                                => covariance just depends on .

 

  • 강정상

 

  • 예시 - White noise
  • 약정상은 두 변수로 비교했다면, 강정상은 세 변수부터 모든 변수들의 정상성을 확인함

 

  • 비정상 확률과정

 

  • 예시 - Random walk
  • 일차모멘트, 이차모멘트가 변화

 

랜덤 워크 - 차분하면 white noise

 

 

  • 용어

 

  • Stationary Process: 정상성인 시계열데이터를 발생시키는 데이터셋(프로세스)
  • Stationary Model: 정상성인 시계열데이터를 설명하는 모델
  • Trend Stationary: 트랜드를 제거하면 정상성인 시계열데이터
  • Seasonal Stationary: 계절성을 제거하면 정상성인 시계열데이터
  • Difference Stationary: 차분을하면 정상성인 시계열데이터
  • Strictly Stationary: 시간 흐름에 따라 "통계적 특성"이 변하지 않음

 


 

  • 비정상성 Y를 정상성으로 변환함 ( 필수 아님 )
  • 안정성과 예측력 향상 - 모델이 단순해져 overfitting 감소
  • 로그, 차분, Box-Cox 등
  • 잔차 정상성 변환 후 통계량으로 확인

 

 

 

1. 로그 변환

 

  • 시간과 비례해 분산이 커지는 경우에 적절

 

분산이 일정한 값으로 나오는 것을 확인할 수 있음

 


 

2. 차분(diff)

 

  • 계절성(seasonality), 추세(trend) 효과 제거 가능

 

 

(1) 계절성 제거 방법

 

    1. 계절성함수 추정해 제거

 

    2. 차분으로 계절성 제거 

 

 

(2) 추세 제거 방법

 

    1. 추세함수 추정해 제거

 

    2. 차분으로 계절성 제거 

 


 

 

3. Box-Cox 변환

 

  • 정규분포가 아닌 데이터를 정규분포로 변환함
  • 여러 파라미터를 넣어보고 가장 정규성을 높여주는 값을 사용

 

# lambda를 바꿔가며 정규성(measure:y)이 가장 높은 lambda(l_opt)를 선정

x, y = sp.stats.boxcox_normplot(raw.value, la=-3, lb=3) # -3 ~ 3 범위에서 test
y_transfer, l_opt = sp.stats.boxcox(raw.value)
print('Optimal Lambda: ', l_opt)

 

가장 정규성이 높은 0.1480

 

plt.figure(figsize=(12,4))
sm.qqplot(raw.value, fit=True, line='45', ax=plt.subplot(131))
plt.title('Y')
sm.qqplot(np.log(raw.value), fit=True, line='45', ax=plt.subplot(132))
plt.title('Log(Y)')
sm.qqplot(y_transfer, fit=True, line='45', ax=plt.subplot(133))
plt.title('BoxCox(Y)')
plt.tight_layout()
plt.show()

 

QQplot으로 정규성 확인

 


 

 

정상성 테스트

 

  • 정상성 (Stationarity) : 평균, 분산, 공분산이 시간의 흐름에 따라 변하지 않음
  • ADF : 추세 제거 확인 검정통계량 ( H1 : 정상 )
  • KPSS : 계절성 제거 확인 검정통계량 ( H1 : 비정상 )
  • ACF : 데이터에 계절성이 포함되면 ACF의 비정상 Lag 존재 가능 / 추세가 포함되면 ACF의 비정상 Lag 존재 가능

 

def stationarity_adf_test(Y_Data, Target_name):
    if len(Target_name) == 0:
        Stationarity_adf = pd.Series(sm.tsa.stattools.adfuller(Y_Data)[0:4],
                                     index=['Test Statistics', 'p-value', 'Used Lag', 'Used Observations'])
        for key, value in sm.tsa.stattools.adfuller(Y_Data)[4].items():
            Stationarity_adf['Critical Value(%s)'%key] = value
            Stationarity_adf['Maximum Information Criteria'] = sm.tsa.stattools.adfuller(Y_Data)[5]
            Stationarity_adf = pd.DataFrame(Stationarity_adf, columns=['Stationarity_adf'])
    else:
        Stationarity_adf = pd.Series(sm.tsa.stattools.adfuller(Y_Data[Target_name])[0:4],
                                     index=['Test Statistics', 'p-value', 'Used Lag', 'Used Observations'])
        for key, value in sm.tsa.stattools.adfuller(Y_Data[Target_name])[4].items():
            Stationarity_adf['Critical Value(%s)'%key] = value
            Stationarity_adf['Maximum Information Criteria'] = sm.tsa.stattools.adfuller(Y_Data[Target_name])[5]
            Stationarity_adf = pd.DataFrame(Stationarity_adf, columns=['Stationarity_adf'])
    return Stationarity_adf



def stationarity_kpss_test(Y_Data, Target_name):
    if len(Target_name) == 0:
        Stationarity_kpss = pd.Series(sm.tsa.stattools.kpss(Y_Data)[0:3],
                                      index=['Test Statistics', 'p-value', 'Used Lag'])
        for key, value in sm.tsa.stattools.kpss(Y_Data)[3].items():
            Stationarity_kpss['Critical Value(%s)'%key] = value
            Stationarity_kpss = pd.DataFrame(Stationarity_kpss, columns=['Stationarity_kpss'])
    else:
        Stationarity_kpss = pd.Series(sm.tsa.stattools.kpss(Y_Data[Target_name])[0:3],
                                      index=['Test Statistics', 'p-value', 'Used Lag'])
        for key, value in sm.tsa.stattools.kpss(Y_Data[Target_name])[3].items():
            Stationarity_kpss['Critical Value(%s)'%key] = value
            Stationarity_kpss = pd.DataFrame(Stationarity_kpss, columns=['Stationarity_kpss'])
    return Stationarity_kpss
    
    
    
  
display(stationarity_adf_test(result.resid, []))
display(stationarity_kpss_test(result.resid, []))  
sm.graphics.tsa.plot_acf(result.resid, lags=50, use_vlines=True)

 

분산, 추세, 계절성 제거 필요

 

# 로그 변환

candidate_trend = np.log(raw).copy()

# 추세 차분

trend_diff_order_initial = 0
result = stationarity_adf_test(candidate_trend.values.flatten(), []).T
if result['p-value'].values.flatten() < 0.1:
    trend_diff_order = trend_diff_order_initial
else:
    trend_diff_order = trend_diff_order_initial + 1

candidate_seasonal = candidate_trend.diff(trend_diff_order).dropna().copy()

# 계절 차분 (acf 그래프에서 가장 높은 위치 인덱스)

seasonal_diff_order = sm.tsa.acf(candidate_seasonal)[1:].argmax() + 1 # 12
print('Seasonal Difference: ', seasonal_diff_order)

candidate_final = candidate_seasonal.diff(seasonal_diff_order).dropna().copy()

 

 

adf : 정상성 / kpss : 정상성

 

acf : 정상성

 

 

 

 

 

 

+ 참고 자료 및 출처

 

  • 김경원 < 파이썬을 활용한 시계열 데이터 분석 A-Z  강의 >  ( 패스트캠퍼스 강의 )

 

댓글