항공사 승객수요 스케일 변환(Log / Box-Cox)
# 라이브러리 호출
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
import scipy as sp
%reload_ext autoreload
%autoreload 2
from module import stationarity_adf_test, stationarity_kpss_test
# 데이터 준비
data = sm.datasets.get_rdataset("AirPassengers")
raw = data.data.copy()
# Box-Cox 변환 모수 추정
# 정규분포의 특정 범위(x)에서 lambda를 바꿔가며 정규성(measure:y)이 가장 높은 lambda(l_opt)를 선정
x, y = sp.stats.boxcox_normplot(raw.value, la=-3, lb=3) # 정규화 할 데이터, 어떤 수치에서 부터 어디까지 수치를 넣어줌(-3 ~ 3)
y_transfer, l_opt = sp.stats.boxcox(raw.value) #정규분포로 변환된 y 및 x수치를 변환해줌
print('Optimal Lambda: ', l_opt)
plt.plot(x, y)
plt.axvline(x=l_opt, color='r', ls="--")
plt.tight_layout()
plt.show()
# QQ-plot로 정규성 검증
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()
- boxcox는 값을 최대한 정규분포로 만들어줌
항공사 승객수요 정상성 변환
# 라이브러리 호출
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
%reload_ext autoreload
%autoreload 2
from module import stationarity_adf_test, stationarity_kpss_test
# 데이터 준비
data = sm.datasets.get_rdataset("AirPassengers")
raw = data.data.copy()
# 데이터 전처리
## 시간 인덱싱
if 'time' in raw.columns:
raw.index = pd.date_range(start='1/1/1949', periods=len(raw['time']), freq='M')
del raw['time']
## 정상성 확보
plt.figure(figsize=(12,8))
raw.plot(ax=plt.subplot(221), title='Y', legend=False)
np.log(raw).plot(ax=plt.subplot(222), title='log(Y)', legend=False)
raw.diff(1).plot(ax=plt.subplot(223), title='diff1(Y)', legend=False)
np.log(raw).diff(1).plot(ax=plt.subplot(224), title='diff1(log(Y))', legend=False)
plt.show()
### 미변환 데이터 정상성 체크
display('Non-transfer:')
plt.figure(figsize=(12,8))
raw.plot(ax=plt.subplot(222), title='Y', legend=False)
plt.show()
candidate_none = raw.copy()
display(stationarity_adf_test(candidate_none.values.flatten(), []))
display(stationarity_kpss_test(candidate_none.values.flatten(), []))
sm.graphics.tsa.plot_acf(candidate_none, lags=100, use_vlines=True)
plt.tight_layout()
plt.show()
- adf(추세에 민감한 통계량) : 비정상
- kpss(계절성에 민감한 통계량) : 비정상
- acf그래프 : 비정상
### 로그 변환
display('Log transfer:')
plt.figure(figsize=(12,8))
np.log(raw).plot(ax=plt.subplot(222), title='log(Y)', legend=False)
plt.show()
candidate_trend = np.log(raw).copy()
display(stationarity_adf_test(candidate_trend.values.flatten(), []))
display(stationarity_kpss_test(candidate_trend.values.flatten(), []))
sm.graphics.tsa.plot_acf(candidate_trend, lags=100, use_vlines=True)
plt.tight_layout()
plt.show()
- adf(추세에 민감한 통계량) : 비정상
- kpss(계절성에 민감한 통계량) : 비정상
- acf그래프 : 비정상
### 로그+추세차분(1회) 변환
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: # 정상데이터가 아니라면 차분값을 1로 변환
trend_diff_order = trend_diff_order_initial + 1
print('Trend Difference: ', trend_diff_order)
display('Log and trend diffrence transfer:')
plt.figure(figsize=(12,8))
np.log(raw).diff(trend_diff_order).plot(ax=plt.subplot(224), title='diff1(log(Y))', legend=False)
plt.show()
candidate_seasonal = candidate_trend.diff(trend_diff_order).dropna().copy()
display(stationarity_adf_test(candidate_seasonal.values.flatten(), []))
display(stationarity_kpss_test(candidate_seasonal.values.flatten(), []))
sm.graphics.tsa.plot_acf(candidate_seasonal, lags=100, use_vlines=True)
plt.tight_layout()
plt.show()
- adf(추세에 민감한 통계량) : 비정상 (로그 취한 사례보다는 정상에 가까움)
- kpss(계절성에 민감한 통계량) : 정상
- acf그래프 : 비정상(계절성이 남아있음)
### 로그+추세차분+계절차분 변환
# 추세차분을 했던것(candidate_seasonal)을 가지고 와서 acf를 측정하고 acf가 가장 높은 값의 위치를 가지고 옴
seasonal_diff_order = sm.tsa.acf(candidate_seasonal)[1:].argmax() + 1
print('Seasonal Difference: ', seasonal_diff_order) # 12
display('Log and trend+seasonal diffrence transfer:')
# 추세차분을 했던것(candidate_seasonal)을 가지고 와서 계절 차분을 해줌
candidate_final = candidate_seasonal.diff(seasonal_diff_order).dropna().copy()
display(stationarity_adf_test(candidate_final.values.flatten(), []))
display(stationarity_kpss_test(candidate_final.values.flatten(), []))
sm.graphics.tsa.plot_acf(candidate_final, lags=100, use_vlines=True)
plt.tight_layout()
plt.show()
- adf(추세에 민감한 통계량) : 정상
- kpss(계절성에 민감한 통계량) : 정상
- acf그래프 : 정상
해당 포스팅은 패스트캠퍼스의 <파이썬을 활용한 시계열 데이터 분석 A-Z 올인원 패키지> 강의를 듣고 정리한 내용입니다
728x90
반응형
'Data Analysis & ML > 시계열분석' 카테고리의 다른 글
[시계열분석] 시계열 알고리즘 - 일반 선형확률 과정(2) - AR(자기회귀) (0) | 2021.08.14 |
---|---|
[시계열분석] 시계열 알고리즘 - 일반 선형확률 과정(1) - MA(이동평균) (0) | 2021.08.07 |
[시계열분석] 정상성 변환 방법론 (0) | 2021.06.27 |
[시계열분석] 정상성이란 (0) | 2021.06.19 |
[시계열분석] 시계열 데이터 전처리 실습(Python)(2) - 다중공선성 제거 (0) | 2021.03.08 |