시계열의 간격 변경과 집계
주요 개념
asfreq: 지정한 날짜의 값 선택ffill,bfill: 새 날짜의 빈 값 채우기resample: 시간 구간별 집계rolling: 이동 구간별 계산
실습 프롬프트
🤖 AI 프롬프트
GOOG.xlsx로 월말 주가, 연평균 주가, 이동 평균을 구하고 그래프로 비교해줘.
특정 날짜의 값을 고르는 것, 기간별로 집계하는 것, 이동 평균을 구하는 것의 차이를 설명해줘.
주가 데이터 준비
GOOG.xlsx의 날짜를 인덱스로 설정하고 시간순으로 정렬
df = pd.read_excel(
'GOOG.xlsx', parse_dates=['Date'], index_col='Date'
)
df.sort_index(inplace=True)
일정 간격으로 데이터 뽑기
asfreq(): 지정한 빈도의 날짜에 해당하는 값을 선택- 매월 말일의 주가
df.Price.asfreq('ME')
실행 결과
Date
2014-03-31 555.45
2014-04-30 525.22
2014-05-31 NaN
2014-06-30 573.70
2014-07-31 570.03
...
2021-08-31 2909.24
2021-09-30 2665.31
2021-10-31 NaN
2021-11-30 2849.04
2021-12-31 2893.59
Freq: ME, Name: Price, Length: 94, dtype: float64
- 빈도 문자열의 기본 구분: 연(
Y), 분기(Q), 월(M), 주(W), 일(D) - 연·분기·월의 실제 빈도 표기에는 시작(
S) 또는 끝(E)을 지정
| 빈도 | 의미 |
|---|---|
YS |
연초 |
YE |
연말 |
QS |
분기초 |
QE |
분기말 |
MS |
월초 |
ME |
월말 |
W |
매주 일요일 |
D |
매일 |
B |
월요일부터 금요일까지의 영업일 |
BYE |
연말의 마지막 영업일 |
QS-FEB |
2월 1일부터 3개월 간격 |
W-WED |
매주 수요일 |
- 위 표의 영업일 빈도(
B,BYE): 월요일부터 금요일 기준. 거래소 공휴일은 별도 달력 설정 필요 - 원자료의 시작일과 종료일 사이에서 지정한 빈도의 날짜를 생성
- 원하는 날짜에 관측값이 없으면
NaN표시 asfreq()는 각 구간의 마지막 관측값을 선택하거나 평균을 계산하는 집계와 구별
그래프 겹쳐 그리기
- 두
.plot()을 같은 셀에서 실행하여 원자료와 연말 영업일 주가를 겹쳐 표시
df.Price.plot(alpha=0.3)
df.Price.asfreq('BYE').plot(color='red', style='o-')
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

alpha: 불투명도. 0은 완전 투명, 1은 완전 불투명color: 색상style: 점과 선의 모양o-: 원형 점과 실선-: 실선--: 대시:: 점선-.: 대시와 점선
빈 데이터 채우기
- 2016년 12월 31일 전후의 데이터 확인
df.Price['2016-12-30':'2017-01-03']
실행 결과
Date
2016-12-30 771.82
2017-01-03 786.14
Name: Price, dtype: float64
-
2016년 12월 31일부터 2017년 1월 2일까지 관측값이 없음
-
아래
method는 빈도 변경으로 새로 생긴 날짜를 채우는 방법 -
원자료에 이미 있던 결측값은 이 인자로 채워지지 않음
이전 값으로 채우기
method='ffill': 해당 날짜에 관측값이 없으면 이전 값으로 채움
df.Price.asfreq('YE', method='ffill')
실행 결과
Date
2014-12-31 524.96
2015-12-31 758.88
2016-12-31 771.82
2017-12-31 1046.40
2018-12-31 1035.61
2019-12-31 1337.02
2020-12-31 1751.88
2021-12-31 2893.59
Freq: YE-DEC, Name: Price, dtype: float64
- 2016년 12월 30일의 771.82로 2016년 12월 31일을 채움
이후 값으로 채우기
method='bfill': 해당 날짜에 관측값이 없으면 이후 값으로 채움
df.Price.asfreq('YE', method='bfill')
실행 결과
Date
2014-12-31 524.96
2015-12-31 758.88
2016-12-31 786.14
2017-12-31 1065.00
2018-12-31 1035.61
2019-12-31 1337.02
2020-12-31 1751.88
2021-12-31 2893.59
Freq: YE-DEC, Name: Price, dtype: float64
- 2017년 1월 3일의 786.14로 2016년 12월 31일을 채움
리샘플
- 리샘플(
resample): 일정한 시간 구간별로 데이터를 종합 YS: 1월 1일부터 다음 해 1월 1일 직전까지를 한 구간으로 나누고, 결과를 해당 연도 1월 1일로 표시mean(): 각 구간에 실제로 관측된 주가의 평균 계산
df.Price.resample('YS').mean()
실행 결과
Date
2014-01-01 552.645699
2015-01-01 602.005556
2016-01-01 743.330277
2017-01-01 921.781394
2018-01-01 1113.225139
2019-01-01 1188.393056
2020-01-01 1481.403794
2021-01-01 2510.613452
Freq: YS-JAN, Name: Price, dtype: float64
- 2014년은 자료가 시작되는 3월 28일부터의 관측값만 포함
- 주말과 휴일을 포함한 모든 날짜의 평균이 아닌, 관측된 거래일 주가의 평균
적용 가능한 집계 함수
| 함수 | 계산 |
|---|---|
sum() |
합계 |
mean() |
평균 |
std() |
표준편차 |
sem() |
평균의 표준오차 |
max() |
최댓값 |
min() |
최솟값 |
median() |
중앙값 |
first() |
첫 값 |
last() |
마지막 값 |
ohlc() |
구간 내 첫 값, 최댓값, 최솟값, 마지막 값 |
Price에ohlc()를 적용하면 입력된 주가의 첫 값·최댓값·최솟값·마지막 값을 집계- 원자료의
Open,High,Low컬럼을 자동으로 사용하는 것은 아님
- 원자료의
구간과 결측값 처리
rule: 원하는 리샘플링 빈도. 예:'YS'closed: 구간의 왼쪽('left')과 오른쪽('right') 중 포함할 경계- 빈도를 늘릴 때 결측값 채우기: 기본적으로 새 날짜에 관측값이 없으면 비어 있으며, 채우려면 별도 방법을 지정
- 이전 값으로 채우기:
resample(...).ffill() - 이후 값으로 채우기:
resample(...).bfill() - 값을 선택하는
asfreq()에서는 앞서 사용한method인자로 지정
- 이전 값으로 채우기:
이동 평균
- 이동 구간 계산(
rolling): 관측 위치를 하나씩 옮기며 구간을 구성 - 이동 평균: 이동 구간에
mean()을 적용한 결과 rolling(365): 각 구간에 365개 관측값을 포함center=True: 결과를 구간의 중심 위치에 표시
rolling = df.Price.rolling(365, center=True) # 365개 관측값, 중심 위치에 표시
- 각 구간의 평균을 시각화
rolling.mean().plot()
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

center=True는 이후 관측값도 사용하므로, 해당 시점까지의 자료만 쓰는 실시간 예측용 특징에는 부적절- 달력상의 365일을 기준으로 묶으려면
rolling('365D')사용 - 정수 구간의 기본
min_periods는 구간 크기와 같으므로, 365개 관측값이 없는 양쪽 끝은 평균을 계산하지 않음
리샘플과 이동 평균의 차이
resample: 일정한 시간 구간으로 나누어 집계- 예: 2019년 평균, 2020년 평균
rolling: 각 관측 위치를 기준으로 이동하는 구간에서 계산- 이 실습에서는 중심 위치 전후의 관측값을 합쳐 총 365개로 평균 계산
- 주말과 휴일에 관측값이 없으므로 달력상의 365일과 구별
퀴즈
월말 날짜에 해당하는 주가를 선택하는 asfreq('ME')에 관한 설명으로 가장 적절한 것은 무엇인가요?
퀴즈를 풀려면 대화형 기능을 불러와야 합니다.