데이터분석과 개발

[시계열 분석] 정상성이란? 본문

AI(시계열)/시계열분석

[시계열 분석] 정상성이란?

긍정적인마인드 2023. 1. 3. 22:28

* 공부한 걸 정리한 글이므로 틀린 내용이 있을 수 있습니다.

* 글을 계속 수정하며 업데이트 할 예정입니다.

 

시계열 데이터 분석을 하기 전 시계열이 정상성을 가지는 지(stationary) 확인합니다. 

평균과 분산이 일정해야 분석할 수 있다고 하는데 사실 와닿지 않았었습니다.

 

그래서 가장 간단한 시계열 AR(1) 이라고 가정하고 정상성일때와 아닐 때를 확인해보았습니다.

 

먼저 AR(1)의 식은 Yt = a * Yt-1 + white_noise 로 나타낼 수 있습니다.

식을 통해 기간은 2022년 1월1일 부터,

첫번째 Y[0]값을 2, 

노이즈(white_noise)는 np.random.rand() 을 통한 난수로,

a(계수)에 따라 시계열 데이터를 만들어보려 합니다.

 

1. a = 0.9일때

 

num_timestep = 1000
np.random.seed(100)
time_range = pd.date_range(start='2022-01-01',periods=num_timestep)

# 계수가 0.9인 AR(1) 시계열
a = 0.9
c = 2
y = np.zeros(num_timestep)
y[0] = c
for t in range(1,num_timestep):
    noise = np.random.randn()
    y[t] = a*y[t-1] + noise
    
df = pd.DataFrame(y , index=time_range, columns=['y'])

# 시각화
plt.figure(figsize=(10,5),constrained_layout=True)
plt.plot(df['y'], label='y')
plt.xticks(rotation=30)
plt.title(f'AR(1): a = {a}')
plt.legend()

2. a = 1.2

 

위의 코드에서 앞의 계수값만 1이 넘는 값으로 설정해 보았습니다. 그랬더니 이상한 그래프가 나왔습니다. 분명 첫번째값 2로 넣었는데 왜 계속 0값이지... 라고 생각했지만

확인해보기위해 직접 앞의 0~20, 20~40 데이터를 직접 그려봤습니다. 그 결과 값이 엄청나게 빠르게 증가하고 있는 모습을 볼 수 있었습니다.

(다시 첫번째 그래프를 확인했더니 1e79 가 붙어있었군요..!)

보시다시피 그래프가 끝도 없이 올라가고 있습니다. 이런 데이터라면 분석이 의미가 없을 것 같네요.

 

3. a = -1.2 

이번엔 절대값이 1이상인 음수 값을 넣어보았습니다. 앞의 그래프와 마찬가지로 엄청 큰값이 그래프에 그려졌네요.

마찬가지로 끊어서 그래프를 그려보았을때 양수와 음수를 차례대로 왔다갔다 하고 있는 모습입니다. 역시 값이 너무 커져서 분석을 할 수 없겠네요.

 

4. a= 1

앞의 경우 절대값이 1보다 컸을 때 데이터가 끝없이 발산한다는 사실을 알았습니다.

그렇다면 a=1 일때는 어떨까 궁금했습니다.

일정한 구간 내에서 데이터가 움직이지만 변동폭이 조금 큰 것 같네요.

정상성인지 아닌지에 대한 결과는 밑에서 확인하겠습니다.

 

* ADF test

 

ADF test 란 데이터가 정상성인지 판별해주는 통계적인 방법입니다. 

Dicky-Fuller test가 AR(1) 시계열을 판별해주는 테스트이고

더 나아가 AR(2)이상의 시계열을 판별해주는 테스트가 Adjusted Dicky_Fuller test라고 합니다 

귀무가설: 

대립가설: 

 

유투브에 좋은 adf test 설명 영상이 있어서 설명을 듣고 따라 코드를 쳐봤습니다. 

ADF test 에 대한 통계적인 설명이 있으니 시간 있으신 분들은 한번 들어보시면 좋을 것 같습니다.

adfuller 함수를 사용하는 실습 코드입니다.

from statsmodels.tsa.stattools import adfuller

def perform_adf_test(series):
    result = adfuller(series)
    print('ADF Statistic: %f' %  result[0])
    print('p-value: %f' %  result[1])

 

영상에서는 AR(2)모형을 통해 시계열 데이터를 만들었습니다. 

def make_AR_series(lags, coefs, length):
    
    # 계수를 array 형태로
    coefs = np.array(coefs)
    
    # initial values: AR공식 처음 계산에 쓰이는 과거값(yt-1, yt-2, ...)
    series = [np.random.normal() for _ in range(lags)]
    
    for _ in range(length):
        # 이전값 마지막 lag수 만큼 거꾸로
        prev_val = series[-lags:][::-1]
        
        # 노이즈
        noise = np.random.normal()
        
        # AR공식에 의한 새로운 값
        new_val = np.sum(coefs * np.array(prev_val) ) + noise 
        
        series.append(new_val)
        
    return series

 

* 정상성 테스트 결과 확인

(1) AR(1)

 

이 코드를 사용해서 앞에서 제가 구했던 AR(1) 시계열들이 정상(stationary)인지 확인해보겠습니다.

a 의 절대값이 1보다 같거나 크면 p-value값이 0.05이상으로 정상이 아님을 알 수 있습니다.

## lag1, a= 0.8 인 경우
series = make_AR_series(1, 0.8, 1000)
perform_adf_test(series)

# 출력값
ADF Statistic: -11.065879
p-value: 0.000000

## lag1, a= 1.2 인 경우
series = make_AR_series(1, 1.2, 100)
perform_adf_test(series)

# 출력값
ADF Statistic: 11.399264
p-value: 1.000000

## lag1, a= 1 인 경우
series = make_AR_series(1, 1, 100)
perform_adf_test(series)

# 출력값
ADF Statistic: -1.804719
p-value: 0.378122

 

(2) AR(2)

 

AR(2) 의 결과도 살펴보겠습니다.  계수가 0.5에서 조금만 넘어도 바로 정상성을 띄지 않게 되네요! 

## lag2, a= 0.3, 0.5 인 경우
series = make_AR_series(2, [0.3,0.5], 1000)
perform_adf_test(series)

# 출력값
ADF Statistic: -9.052711
p-value: 0.000000

## lag2, a= 0.4, 0.6 인 경우
series = make_AR_series(2, [0.4,0.6], 1000)
perform_adf_test(series)

# 출력값
ADF Statistic: -1.638712
p-value: 0.462934

 

이번 포스팅에서는 정상성의 직관적인 의미를 한번 정리해보았습니다.

정상성 검증이 안되면 분석을 할 수 없다는 사실을 깨달았습니다. 앞으로 분석하기 전에 꼭 정상성 검증을 할 계획입니다!

감사합니다.

 

출처: https://www.youtube.com/watch?v=1opjnegd_hA