자기상관
주요 개념
- 자기상관함수(ACF)
- 차분
- 계절적으로 조정된 데이터
- 추세와 계절성을 제거한 나머지 성분
자기상관함수
- 자기상관함수(ACF, Autocorrelation Function): 1시점, 2시점, 3시점 등의 간격으로 자기상관을 구한 것
- 시차 k: 비교하는 두 관측값 사이의 시간 간격
- rk: 시차 k에서의 자기상관계수
- 시계열의 정상성·계절성 등 구조를 탐색하는 데 사용
무작위로 움직이는 경우

양의 자기상관이 있는 경우

추세가 있는 비정상 시계열

실습 프롬프트
🤖 AI 프롬프트
washington_temp.xlsx로 월평균 기온을 구하고 ACF로 계절 패턴을 살펴봐줘.
전년 같은 달과의 차분, 계절 조정, 추세와 계절 성분을 제거한 뒤의 ACF를 비교하고 남은 자기상관을 설명해줘.
실습 준비
washington_temp.xlsx: 워싱턴 DC 기온 데이터Year,Month,Day: 연·월·일AvgTemperature: 일별 평균 기온. 화씨(°F) 단위를 유지
import pandas as pd
temp = pd.read_excel('washington_temp.xlsx')
temp.head()
실행 결과
Unnamed: 0 Region Country State City Month Day \
0 1687055 North America US Maryland Washington DC 1 1
1 1687056 North America US Maryland Washington DC 1 2
2 1687057 North America US Maryland Washington DC 1 3
3 1687058 North America US Maryland Washington DC 1 4
4 1687059 North America US Maryland Washington DC 1 5
Year AvgTemperature
0 1995 40.6
1 1995 39.8
2 1995 29.3
3 1995 33.0
4 1995 20.9
날짜 인덱스 설정
- 컬럼으로 나뉜 연·월·일을 하나의 날짜로 결합
temp['date'] = pd.to_datetime(temp[['Year', 'Month', 'Day']])
- 날짜를 행 인덱스로 지정
temp.set_index('date', inplace=True)
월평균 기온
- 월별로 묶어 평균 기온 계산
ME: 월말을 기준으로 결과 표시
monthly = temp.resample('ME').AvgTemperature.mean()
monthly.head()
실행 결과
date
1995-01-31 38.903226
1995-02-28 34.017857
1995-03-31 49.200000
1995-04-30 55.916667
1995-05-31 65.267742
Freq: ME, Name: AvgTemperature, dtype: float64
monthly.plot()
실행 결과
<Axes: xlabel='date'>
<Figure size 640x480 with 1 Axes>

ACF 구하기
acf(): 시차별 자기상관계수를 배열로 반환- 배열의 첫 값은 시차 0의 자기상관인 1
- 월별 자료에서 배열의 인덱스 6과 12는 각각 6개월과 12개월 시차
from statsmodels.tsa.stattools import acf
acf_values = acf(monthly)
acf_values
실행 결과
array([ 1. , 0.83115217, 0.47467309, 0.00663062, -0.46502868,
-0.80701026, -0.92863316, -0.79835449, -0.45824698, 0.00253566,
0.46149188, 0.79540151, 0.91171097, 0.7838514 , 0.44951811,
-0.00177934, -0.44842724, -0.77479739, -0.88350088, -0.76231924,
-0.43924376, 0.00369917, 0.43941603, 0.76217074, 0.87282319])
acf_values[6] # 6개월 시차
실행 결과
np.float64(-0.9286331582763904)
- 6개월 시차의 자기상관: 약 -0.929. 강한 음의 상관
acf_values[12] # 12개월 시차
실행 결과
np.float64(0.9117109695809359)
- 12개월 시차의 자기상관: 약 +0.912. 강한 양의 상관
ACF 시각화
from statsmodels.graphics.tsaplots import plot_acf
plot_acf(monthly);
실행 결과
<Figure size 640x480 with 1 Axes>

- 하늘색 음영: 기본 설정에서 0을 중심으로 표시한 시차별 약 95% 신뢰구간
- 막대가 음영 밖에 있으면 해당 시차의 자기상관이 0과 다르다는 통계적 증거
- 시차가 커지면 비교에 사용할 수 있는 관측값 쌍의 수는 감소
- 신뢰구간의 폭은 자료와 계산 방식에 따라 달라지며, 이 그래프에서는 시차가 커질수록 넓어지는 모습
차분
- 차분(differencing): 일정 시차를 둔 관측값의 차이
- 월별 자료의 1차 차분: 전월 대비 변화량
- 추세를 줄여 비정상 시계열을 정상 시계열로 만드는 데 활용
- 차분만으로 정상성이 항상 보장되지는 않으며 처리 후의 구조를 확인
dropna(): 이전 값이 없어 차이를 계산하지 못한 관측값 제외
diff1 = monthly.diff().dropna()
diff1.plot()
실행 결과
<Axes: xlabel='date'>
<Figure size 640x480 with 1 Axes>

계절성 차분
- 12개월, 즉 1년 간격의 차이
- 전년 동월 대비 변화량
diff_season = monthly.diff(12).dropna()
diff_season.plot()
실행 결과
<Axes: xlabel='date'>
<Figure size 640x480 with 1 Axes>

- ACF로 차분 후의 구조 확인
plot_acf(diff_season)
실행 결과
<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>

- 원자료의 뚜렷한 1년 반복 패턴은 크게 줄어듦
- 12개월 시차에는 강한 음의 자기상관이 남아 있으므로, 계절성 차분 뒤에도 자기상관이 모두 사라진 것은 아님
- 남은 자기상관이 있는지 확인하며, 추세와 계절성이 완전히 없어졌다고 단정하지 않음
시계열 분해
- 추세 성분: 이동 평균으로 추정
- 계절 성분: 추세를 제거한 뒤 같은 월의 값을 평균하여 추정
period=12: 월별 기온의 1년 주기
from statsmodels.tsa.seasonal import seasonal_decompose
result = seasonal_decompose(monthly, model='additive', period=12) # 1년 주기
result.plot();
실행 결과
<Figure size 640x480 with 4 Axes>

계절적으로 조정된 데이터
- 원자료에서 계절 성분을 제거
- 추세와 나머지 성분은 남음
- 계절성 차분: 이번 달 관측값에서 전년 같은 달의 관측값을 빼서 전년 동월 대비 변화량 계산
- 계절 조정: 이번 달 관측값에서 추정한 해당 월의 계절 효과를 빼서 계절적 변동을 제거
adjusted = monthly - result.seasonal
adjusted.plot()
실행 결과
<Axes: xlabel='date'>
<Figure size 640x480 with 1 Axes>

- 계절성을 제거한 데이터의 ACF 확인
acf(adjusted)
실행 결과
array([ 1.00000000e+00, 2.14233789e-01, 8.15215920e-02, 1.54031280e-01,
9.70121031e-02, 7.34873474e-02, 8.79033046e-02, 1.10419001e-01,
9.08235133e-02, 7.57487206e-02, 4.98248655e-02, 6.54641069e-02,
-1.42514574e-04, -2.47279373e-02, -1.21964401e-02, 5.85073666e-03,
1.08357905e-02, -2.37432895e-02, 1.17279651e-01, 9.09467861e-02,
4.92307456e-02, 8.81561135e-02, 2.96397517e-02, 1.14550513e-01,
3.16866370e-03])
plot_acf(adjusted);
실행 결과
<Figure size 640x480 with 1 Axes>

나머지 성분
result.resid: 추세와 계절 성분을 제거한 나머지 성분- 중심 이동 평균을 계산할 자료가 부족한 양쪽 끝에서는
NaN - ACF 계산에 사용할 나머지 성분은
dropna()로 결측값을 제외한 뒤detrended에 저장
detrended = result.resid.dropna()
result.resid.plot(); # 추세와 계절성을 제거한 나머지 성분
실행 결과
<Figure size 640x480 with 1 Axes>

acf(detrended)
실행 결과
array([ 1. , -0.00129878, -0.17042366, -0.07008368, -0.14659238,
-0.205082 , -0.08696299, 0.07628511, 0.08008361, 0.04311102,
0.0296882 , 0.05984403, -0.01926409, -0.07632135, -0.04750796,
-0.03638691, -0.01210258, -0.08175267, 0.09464654, 0.08010255,
0.01442105, 0.04091389, -0.02870085, 0.04893728, -0.09520925])
plot_acf(detrended);
실행 결과
<Figure size 640x480 with 1 Axes>

- 추세와 계절성을 제거한 뒤에도 남은 시간적 관계를 ACF로 확인
- 이 결과에서는 2·4·5개월 시차의 막대가 음의 방향으로 신뢰구간을 벗어나, 해당 시차에 음의 자기상관이 남아 있는 모습
- 계절 패턴을 줄이거나 추세·계절 성분을 분해해도 자기상관이 모두 없어지는 것은 아님
퀴즈
자기상관함수(ACF)가 나타내는 것은 무엇인가요?
퀴즈를 풀려면 대화형 기능을 불러와야 합니다.