본문 바로가기
공부/통계학

Differential (차분) python

by signature95 2022. 1. 19.
728x90
반응형

차분을 하는 이유는 non-stationary한 데이터를 차분을 통해 stationary하게 만들어주는 것이다.

데이터를 안정화하는 작업은 제곱, 로그화, 루트, 차분이 있는데 이번에는 차분을 해볼 것이다.

 

정상성에 대해서는 다음 포스트를 참고하면 된다.

2022.01.19 - [공부/모델링] - Stationary test (정상성 검정) python

 

Stationary test (정상성 검정) python

시계열 데이터를 다루게 된다면, 정상성 검정이라는 것을 시행해야 한다. 시계열 데이터를 통해 회귀를 하게 된다면, 이는 과거 데이터를 가지고 미래를 예측하는 것과 같다. 따라서 통계적 속

signature95.tistory.com

 

이번에는 정상성 검정 포스트에서 다룬 데이터를 기반으로 차분을 진행해 볼 것이다.

 

차분은 t 시점의 데이터가 t-1 시점 데이터에 비해 얼마나 증감했는지 알 수 있게 된다.

식은 다음과 같다.

n차 차분을 진행한 경우

식을 보면 알 수 있듯, k개의 시점이 있는 데이터에서 1차 차분을 진행하게 되면, 총 n 개의 데이터가 소실되는 단점이 존재한다.

 

1차 차분에 대한 식은 다음과 같다.

 

이를 파이썬으로 확인해보자

 

데이터는 앞 포스트와 동일한 divvy_data를 활용하였다.

divvy_daily.csv
0.05MB

 

rides = data["rides"].to_frame(name="rides") # 데이터의 행을 역순으로 뒤집는 부분 
rides = rides.loc[::-1]
rides["lag_1"] = rides["rides"].shift(periods=1) 

print(rides)
>>>

            rides   lag_1
date                     
12/31/2017    593     NaN
12/30/2017    519   593.0
12/29/2017   1049   519.0
12/28/2017   1267  1049.0
12/27/2017   1117  1267.0
...           ...     ...
1/5/2014       32     1.0
1/4/2014      181    32.0
1/3/2014        6   181.0
1/2/2014      111     6.0
1/1/2014       95   111.0

shift함수를 통해 t기의 데이터를 t-1기로 밀어낸 부분이다. 따라서 index의 값은 lag_1에서 하나씩 밀린 것을 확인할 수 있다.

 

그렇다면 이번엔 차분을 해보자. 

차분은 직접 빼는 부분 (diff_1 = rides column - lag_1 column) & diff 함수를 이용한 부분으로 데이터를 구해보았다.

rides['직접 구한 diff_1'] = rides['rides'] - rides['lag_1'] 
rides['함수로 구한 diff_1'] = rides['rides'].diff(1) 
print(rides)

>>>

            rides   lag_1  직접 구한 diff_1  함수로 구한 diff_1
date                                                  
12/31/2017    593     NaN           NaN            NaN
12/30/2017    519   593.0         -74.0          -74.0
12/29/2017   1049   519.0         530.0          530.0
12/28/2017   1267  1049.0         218.0          218.0
12/27/2017   1117  1267.0        -150.0         -150.0
...           ...     ...           ...            ...
1/5/2014       32     1.0          31.0           31.0
1/4/2014      181    32.0         149.0          149.0
1/3/2014        6   181.0        -175.0         -175.0
1/2/2014      111     6.0         105.0          105.0
1/1/2014       95   111.0         -16.0          -16.0

즉, 1차 차분을 하는 방식은 lag_1로 데이터를 하나씩 미룬다음 그것을 직접 뺴주는 방법이라고 보면 된다.

 

2차 차분의 경우, 거의 사용할 일은 없다. 하지만 식을 보면 다음과 같이 쓸 수 있다.

따라서 이를 파이썬으로 구현하면 다음과 같다. (기존에는 lag_2로 단순히 시기를 2단계 미뤄서 진행했었는데, 이 부분이 잘못되었다고 지적해주시는 분 덕분에 올바르게 수정할 수 있게되었음)

# 앞서 1차 차분에서 진행했던 값의 컬럼을 변경해주고 drop한다
rides["diff_1"] = rides["함수로 구한 diff_1"]
rides = rides.drop(columns=['함수로 구한 diff_1', '직접 구한 diff_1'])

# 2차 차분을 시행하기 위해 1차 차분 값을 lag=1 적용하여 미뤄준다
rides['diff_1 + lag_1'] = rides['diff_1'].shift(1)

# 2차 차분값 도출
rides['diff_1 + lag_1'] = rides['diff_1'].shift(1)
rides['직접 구한 diff_2'] = rides['diff_1'] - rides['diff_1 + lag_1']
rides['함수로 구한 diff_2'] = rides['rides'].diff().diff()

print(rides)

>>>

            rides   lag_1  diff_1  diff_1 + lag_1  직접 구한 diff_2  함수로 구한 diff_2
date                                                                          
12/31/2017    593     NaN     NaN             NaN           NaN            NaN
12/30/2017    519   593.0   -74.0             NaN           NaN            NaN
12/29/2017   1049   519.0   530.0           -74.0         604.0          604.0
12/28/2017   1267  1049.0   218.0           530.0        -312.0         -312.0
12/27/2017   1117  1267.0  -150.0           218.0        -368.0         -368.0
...           ...     ...     ...             ...           ...            ...
1/5/2014       32     1.0    31.0          -830.0         861.0          861.0
1/4/2014      181    32.0   149.0            31.0         118.0          118.0
1/3/2014        6   181.0  -175.0           149.0        -324.0         -324.0
1/2/2014      111     6.0   105.0          -175.0         280.0          280.0
1/1/2014       95   111.0   -16.0           105.0        -121.0         -121.0

 

 

 

그러면 차분을 했던 데이터의 정상성을 검정해보자

diff_data = data['rides'].diff(1).dropna()

# 표 그리기
plt.figure(figsize=(16,9))
plt.plot(diff_data.values, alpha=.7)
plt.hlines(y=diff_data.mean(), xmin=-50, xmax=1500, colors='red', linestyles='dashed')
plt.ylabel('divvy_rider')
plt.show()

1차 차분을 한 데이터 + 평균선

 

추가)

2차차분에 대한 시각화는 다음과 같다.

diff_data = data['rides'].diff().diff().dropna() 

# 표 그리기 
plt.figure(figsize=(16,9)) 
plt.plot(diff_data.values, alpha=.7) 
plt.hlines(y=diff_data.mean(), xmin=-50, xmax=1500, colors='red', linestyles='dashed') 
plt.ylabel('divvy_rider') 
plt.show()

 

 

ADF, KPSS 검정은 앞 포스트를 참고하면 된다.

 

adf_test(diff_data)

>>>

Results of Dickey-Fuller Test:
Test Statistic                -9.252496e+00
p-value                        9.827854e-14
Lags Used                      2.100000e+01
Number of Observations Used    1.435000e+03
Critical Value (1%)           -3.965093e+00
Critical Value (5%)           -3.413554e+00
Critical Value (10%)          -3.128854e+00
dtype: float64
정상시계열이 아니라는 귀무가설을 5.0%의 유의수준으로 기각할 수 있으므로 해당 데이터는 정상성이 보장됩니다.
kpss_test(diff_data)

>>>

Results of KPSS Test:
Test Statistic            0.043502
p-value                   0.100000
Lags Used                52.000000
Critical Value (10%)      0.119000
Critical Value (5%)       0.146000
Critical Value (2.5%)     0.176000
Critical Value (1%)       0.216000
dtype: float64
정상시계열이 맞다는 귀무가설을 5.0%의 유의수준으로 기각할 수 없으므로 해당 데이터는 정상성이 보장됩니다.
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/statsmodels/tsa/stattools.py:2015: InterpolationWarning: The test statistic is outside of the range of p-values available in the
look-up table. The actual p-value is greater than the p-value returned.

 

이렇게 이번에는 차분을 통해서 비정상 시계열을 안정화하는 작업을 해보았다. (물론 정상화를 위해서는 차분외에도 log 치환 등도 존재한다. 하지만 이번에는 차분만 다루는 것으로 하였다)

 

다음글에서 ACF가 이어집니다.

2022.01.20 - [공부/모델링] - ACF (auto-correlative function, 자기상관함수) python

 

ACF (auto-correlative function, 자기상관함수) python

자기상관함수는 보통 시계열 분석으로 도출된 잔차가 시간의 흐름에 따라 상관성이 존재하는지 확인하는 함수이다. 물론 ARIMA를 시행할 때, p,q를 설정하기 위해서도 ACF를 활용하기도 한다. 이번

signature95.tistory.com

 

728x90

댓글