기본 콘텐츠로 건너뛰기

[matplotlib]quiver()함수

[time series] 정상성(stationary) 검정

정상성(stationary) 검정

  • 정상성 판단을 위한 일반적인 지침:
    • ACF가 천천히 감소하거나 오랜 기간 유의미한 값을 가지면 비정상적일 가능성이 높습니다. 특히 선형적인 감소는 추세를, 주기적인 스파이크는 계절성을 나타낼 수 있습니다.
    • PACF에서 몇 개의 초기 시차에서만 유의미한 스파이크가 나타나고 이후 급격히 감소하면 정상적일 가능성이 높습니다.
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt

from statsmodels.tsa.stattools import acf, pacf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
st=pd.Timestamp(2024,1, 1)
et=pd.Timestamp(2025, 4,25)
trgnme="000660.KS"
trg=yf.download(trgnme,  st, et)
trg.columns=[i[0] for i in trg.columns]
close=trg["Close"]

다음은 데이터의 ACF와 PACF를 작성하기 위한 UDF입니다.

#ACF, PACF  작성 함수
def acf_pacf_plot(data, lag=10):
  f, axes=plt.subplots(1,2, figsize=(10, 3), sharey=True)
  plt.subplots_adjust(wspace=0.1)
  plot_acf(data, lags=lag, ax=axes[0])
  plot_pacf(data, lags=lag, ax=axes[1])
  plt.show()
#ACF, PACF
fig, axes=plt.subplots(1, 2, figsize=(10, 3), sharey=True)
plt.subplots_adjust(wspace=0.1)
plot_acf(close, lags=30, ax=axes[0])
axes[0].grid(True)
plot_pacf(close, lags=30, ax=axes[1])
axes[1].grid(True)
plt.show()

위 결과는 ACF는 비정상, PACF는 정상임을 나타냄. 이러한 경우에 가능한 시나리오는 다음과 같습니다.

  • 강한 추세가 존재하는 경우
    • ACF: 매우 천천히 감소 또는 오랜기간 동안 높은 값을 유지로 먼 lag에서 강한 상관성을 갖기 때문
    • PACF: 추세 영향이 제거되면 비교적 빠르게 0으로 감소하는 정상성을 보일 수 있음.
  • 계절성이 존재하는 경우
  • AR(p) 모델에서 높은 p에서 정상성을 보일 수 있음

주의사항

  • ACF 및 PACF 플롯은 시각적인 판단 도구이므로, 명확하지 않은 경우에는 ADF(Augmented Dickey-Fuller) 검정과 같은 통계적 정상성 검정을 함께 사용하는 것이 좋습니다.
  • 데이터의 크기가 작거나 복잡한 패턴을 가질 경우 ACF 및 PACF 플롯 해석이 어려울 수 있습니다.

정상성 검정 (Stationarity Test)

  • 시계열 분석 모델 (특히 ARIMA 계열)은 데이터가 정상성을 만족하는 것을 가정하는 경우가 많습니다. 정상성이란 시계열의 통계적 특성 (평균, 분산 등)이 시간에 따라 변하지 않는 성질을 의미합니다.
  • statsmodels 라이브러리의 adfuller 함수 (Augmented Dickey-Fuller test) 등의 통계적 검정을 사용하여 시계열 데이터의 정상성을 확인합니다.
  • 비정상 시계열 데이터의 경우, 차분(Differencing) 등의 방법을 통해 정상성을 확보해야 합니다.

ADF 검정(Augmented Dickey-Fuller Test): 단위근(Unit root)의 존재여부에 대한 검정으로 단위근이 존재하면 비정상(non-stationary)일 가능성이 높음.

  • 귀무가설: "단위근이 존재한다" 즉, 비정상이다.
  • 대립가설: "단위근이 존재하지 않는다" 즉, 정상이다.

ADF 검정의 주요결과

  • ADF 통계량
  • 임계값(Critical values): 유의수준(일반적으로 1%, 5%, 10%)에서의 귀무가설의 기각 여부의 기준값
  • p-값:
    • p < 0.05 : 기각, 정상성(ADF 통계량이 임계값보다 작은 경우)
    • p>= 0.05: 기각할 수 없음, 비정상

KPSS 검정 (Kwiatkowski-Phillips-Schmidt-Shin Test)

  • KPSS 검정은 ADF 검정과 반대로 귀무 가설이 "시계열은 정상적이다"인 검정입니다. 따라서ADF 검정과 상호 보완적으로 사용될 수 있습니다.

AD검정: statsmodels.tsa.stattools.adfuller()
KPSS 검정: .kpss()함수를 사용합니다.

이 함수들의 매개변수 autolag='AIC'는 시계열 분석에서 최적의 지연(lag) 길이를 자동으로 선택하는 방법을 의미합니다. 특히 ADF(단위근) 테스트에서 사용되며, Akaike Information Criterion(AIC)을 최소화하는 방식으로 최적의 지연 길이를 결정합니다. 즉, autolag='AIC'를 설정하면 여러 개의 지연 길이를 테스트한 후, AIC 값이 가장 낮은 지연 길이를 선택합니다. 이를 통해 불필요한 지연을 제거하고, 모델의 적합성을 최적화할 수 있습니다. 비슷한 방식으로 autolag='BIC'를 설정하면 Bayesian Information Criterion(BIC)을 기준으로 최적의 지연 길이를 선택합니다.

다음결과에 의하면 귀무가설을 기각할 수 없습니다. 즉, 단위근이 존재하므로 비정상입니다.

result=adfuller(close, autolag="AIC")
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}')
print(f'임계값: {result[4]}')
ADF Statistic: -2.447642027313806
p-value: 0.12873862241362005
임계값: {'1%': -3.4510167751522642, '5%': -2.87064334231426, '10%': -2.5716201744283174}

비정상 시계열인 경우 데이터에 추세, 계절성 또는 특정 차수의 AR 성분이 존재할 가능성이 높습니다. 데이터에 추세, 계절성 또는 특정 차수의 AR 성분이 존재할 가능성이 높습니다. 이러한 경우 차분으로 정상시계열로 전환될 수 있습니다. 특히 추세를 가진 데이터의 경우 차분은 매우 효과가 높습니다.

다음은 2차 차분을 적용한 경우 입니다.

close_dif=close.diff().diff().dropna()
close_dif.isnull().sum()
0
fig, axes=plt.subplots(1, 2, figsize=(10, 3), sharey=True)
plt.subplots_adjust(wspace=0.1)
plot_acf(close_dif, lags=30, ax=axes[0])
axes[0].grid(True)
plot_pacf(close_dif, lags=30, ax=axes[1])
axes[1].grid(True)
plt.show()
result_dif=adfuller(close_dif, autolag="AIC")
print(f'ADF Statistic: {result_dif[0]}')
print(f'p-value: {result_dif[1]}')
print(f'임계값: {result_dif[4]}')
ADF Statistic: -6.959443869660086
p-value: 9.245595177301791e-10
임계값: {'1%': -3.4523371197407404, '5%': -2.871222860740741, '10%': -2.571929211111111}

ACF가 비정상이고 PACF가 정상적인 패턴을 나타내는 경우, 차분과 같은 정상화 기법을 적용하거나, PACF의 패턴을 기반으로 AR 모델을 고려하고, 필요에 따라 계절성 분석을 수행하는 것이 적절한 대응 방법이 될 수 있습니다.

댓글

이 블로그의 인기 게시물

[Linear Algebra] 유사변환(Similarity transformation)

유사변환(Similarity transformation) n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사행렬(similarity matrix)이 되며 행렬 A를 가역행렬 P와 B로 분해하는 것을 유사 변환(similarity transformation) 이라고 합니다. $$\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B $$ 식 2는 식 1의 양변에 B의 고유값을 고려한 것입니다. \begin{align}\tag{식 2} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align} 식 2의 행렬식은 식 3과 같이 정리됩니다. \begin{align} &\begin{aligned}\textsf{det}(B - \lambda I ) & = \textsf{det}(P^{-1}(AP – \lambda P))\\ &= \textsf{det}(P^{-1}) \textsf{det}((A – \lambda I)) \textsf{det}(P)\\ &= \textsf{det}(P^{-1}) \textsf{det}(P) \textsf{det}((A – \lambda I))\\ &= \textsf{det}(A – \lambda I)\end{aligned}\\ &\begin{aligned}\because \; \textsf{det}(P^{-1}) \textsf{det}(P) &= \textsf{det}(P^{-1}P)\\ &= \textsf{det}(I)\end{aligned}\end{align} 유사행렬의 특성 유사행렬인 두 정방행렬 A와 B는 'A ~ B' 와 같...

[sympy] Sympy객체의 표현을 위한 함수들

Sympy객체의 표현을 위한 함수들 General simplify(x): 식 x(sympy 객체)를 간단히 정리 합니다. import numpy as np from sympy import * x=symbols("x") a=sin(x)**2+cos(x)**2 a $\sin^{2}{\left(x \right)} + \cos^{2}{\left(x \right)}$ simplify(a) 1 simplify(b) $\frac{x^{3} + x^{2} - x - 1}{x^{2} + 2 x + 1}$ simplify(b) x - 1 c=gamma(x)/gamma(x-2) c $\frac{\Gamma\left(x\right)}{\Gamma\left(x - 2\right)}$ simplify(c) $\displaystyle \left(x - 2\right) \left(x - 1\right)$ 위의 예들 중 객체 c의 감마함수(gamma(x))는 확률분포 등 여러 부분에서 사용되는 표현식으로 다음과 같이 정의 됩니다. 감마함수는 음이 아닌 정수를 제외한 모든 수에서 정의됩니다. 식 1과 같이 자연수에서 감마함수는 factorial(!), 부동소수(양의 실수)인 경우 적분을 적용하여 계산합니다. $$\tag{식 1}\Gamma(n) =\begin{cases}(n-1)!& n:\text{자연수}\\\int^\infty_0x^{n-1}e^{-x}\,dx& n:\text{부동소수}\end{cases}$$ x=symbols('x') gamma(x).subs(x,4) $\displaystyle 6$ factorial 계산은 math.factorial() 함수를 사용할 수 있습니다. import math math.factorial(3) 6 a=gamma(x).subs(x,4.5) a.evalf(3) 11.6 simpilfy() 함수의 알고리즘은 식에서 공통사항을 찾아 정리하...

sympy.solvers로 방정식해 구하기

sympy.solvers로 방정식해 구하기 대수 방정식을 해를 계산하기 위해 다음 함수를 사용합니다. sympy.solvers.solve(f, *symbols, **flags) f=0, 즉 동차방정식에 대해 지정한 변수의 해를 계산 f : 식 또는 함수 symbols: 식의 해를 계산하기 위한 변수, 변수가 하나인 경우는 생략가능(자동으로 인식) flags: 계산 또는 결과의 방식을 지정하기 위한 인수들 dict=True: {x:3, y:1}같이 사전형식, 기본값 = False set=True :{(x,3),(y,1)}같이 집합형식, 기본값 = False ratioal=True : 실수를 유리수로 반환, 기본값 = False positive=True: 해들 중에 양수만을 반환, 기본값 = False 예 $x^2=1$의 해를 결정합니다. solve() 함수에 적용하기 위해서는 다음과 같이 식의 한쪽이 0이 되는 형태인 동차식으로 구성되어야 합니다. $$x^2-1=0$$ import numpy as np from sympy import * x = symbols('x') solve(x**2-1, x) [-1, 1] 위 식은 계산 과정은 다음과 같습니다. $$\begin{aligned}x^2-1=0 \rightarrow (x+1)(x-1)=0 \\ x=1 \; \text{or}\; -1\end{aligned}$$ 예 $x^4=1$의 해를 결정합니다. solve() 함수의 인수 set=True를 지정하였으므로 결과는 집합(set)형으로 반환됩니다. eq=x**4-1 solve(eq, set=True) ([x], {(-1,), (-I,), (1,), (I,)}) 위의 경우 I는 복소수입니다.즉 위 결과의 과정은 다음과 같습니다. $$x^4-1=(x^2+1)(x+1)(x-1)=0 \rightarrow x=\pm \sqrt{-1}, \; \pm 1=\pm i,\; \pm1$$ 실수...