[Python pandas] 분기 단위의 기간 날짜 범위 만들기, timestamp와 변환하기 (Quarterly period frequencies and range, conversion b/w timestamp)
Python 분석과 프로그래밍/Python 데이터 전처리 2019. 12. 30. 12:30지난번 포스팅에서는 Python pandas에서 시간대를 확인, 설정, 변경하는 방법(https://rfriend.tistory.com/505)을 소개하였습니다.
이번 포스팅에서는 Python pandas에서
(1) 분기 단위의 기간 주기 만들기 (quarterly period frequencies)
(2) 분기 단위의 기간 날짜-범위 만들기 (quarterly period date-range)
(3) 분기 단위의 기간과 timestamp 간 변환하기 (conversion between quarterly period and timestamp)
(4) 분기 단위 기간으로 집계하기 (quarterly period group by aggregation)
에 대해서 소개하겠습니다.
이번 포스팅은 특히, 금융, 회계 분야에서 분기 단위(fiscal year quarters) 실적 집계, 분석할 때 pandas로 하기에 유용한 기능들입니다.
[ 그림1. pandas 분기 단위의 기간 범위 만들기 (Quarterly Period Range) ]
(1) 분기 단위의 기간 주기 만들기 (quarterly period frequencies) |
pandas Period() 함수를 사용해서 the Fiscal Year 2020 4 Quarter 를 만들어보겠습니다. 회기년도 '2020-Q4'는 위의 [그림 1] 에서 보는 바와 같이, 2019.3월~5월(2020- Q1), 2019.6월~8월(2020-Q2), 2019.9월~11월(2020-Q3), 2019.12월~2020.2월(2020-Q4) 의 기간으로 구성되어 있습니다. (회계년도 2020 에 2019년의 3월~12월이 포함되어서 좀 이상하게 보일 수도 있는데요, 그냥 이렇습니다. ^^')
import pandas as pd import numpy as np p = pd.Period('2020Q4', freq='Q-FEB') p [Out]: Period('2020Q4', 'Q-FEB') |
pandas의 asfreq() 메소드를 사용하면 pandas Period 객체를 원하는 주기(Period frequency)로 변환할 수 있습니다. 위의 2020-Q4 의 분기 단위의 기간(Quarterly Period)를 asfreq() 메소드를 사용해 (a) 분기별 시작 날짜(starting date)와 끝 날짜(ending date), (b) 분기별 공휴일이 아닌 시작 날짜(staring business date)와 공휴일이 아닌 끝 날짜 (ending business date)로 변환해 보겠습니다.
(a) converting from Period to Date: 'D' | (b) converting from Period to Business Date: 'B' |
# starting date p.asfreq('D', how='start')
# ending date p.asfreq('D', how='end') [Out]: Period('2020-02-29', 'D') |
# starting business date p.asfreq('B', how='start') [Out]: Period('2019-12-02', 'B') # ending business date p.asfreq('B', how='end') [Out]: Period('2020-02-28', 'B') |
asfreq() 메소드를 chain으로 연속으로 이어서
(a) 분기별 ending business date를 선택하고 --> (b) starting(how-='start) minutes (freq='T' or freq='min')의 주기(frequency)로 변환한다거나,
(c) 분기별 ending business date를 선택하고 --> 이를 (d) ending minutes('T', or 'min') 로 변환하거나,
(e) 분기별 ending business date를 선택하고 --> 이를 (f) ending seconds 로 변환
하는 것이 모두 가능합니다.
# (a) from ending Business date --> (b) to starting Minutes p.asfreq('B', how='end').asfreq('T', how='start') [Out]: Period('2020-02-28 00:00', 'T') # (c) from ending Business date --> (d) to ending Minutes p.asfreq('B', how='end').asfreq('T', how='end') [Out]: Period('2020-02-28 23:59', 'T') # (e) from Business date --> (f) to Seconds p.asfreq('B', how='end').asfreq('S', how='end') [Out]: Period('2020-02-28 23:59:59', 'S') |
(2) 분기 단위의 기간 범위 만들기 (quarterly period range) |
pandas의 date_range() 함수로 날짜-시간 범위의 DatetimeIndex 객체를 만들 듯이, pandas의 period_range('start', 'end', freq='Q-[ending-month]') 함수를 사용해서 분기 단위의 기간 범위(quarterly period range)를 만들 수 있습니다. (참고로 freq='A-DEC' 는 12월을 마지막으로 가지는 년 단위 기간(yearly period)라는 뜻이며, freq='Q-FEB'는 2월달을 마지막으로 가지는 분기 단위 기간(quarterly period)라는 뜻입니다)
아래 예는 2020-Q1 ~ 2020-Q4 기간(pd.period_range('2020Q1', '2020Q4')의 2월달을 마지막으로 하는 분기 단위의 기간(freq='Q-FEB')을 만든 것입니다.
p_rng = pd.period_range('2020Q1', '2020Q4', freq='Q-FEB') p_rng
|
asfreq() 메소드를 사용해서 위에서 생성한 '2020-Q1' ~ '2020-Q4' 기간(period with a Quarter ending at February)의 공휴일이 아닌 시작 날짜(staring business date)와 끝 날짜(ending business date)로 변환해보겠습니다.
# convert period into deisred frequency using asfreq() methods # starting business day per quarter 'Q-FEB' p_rng.asfreq('B', how='start') [Out]: PeriodIndex(['2019-03-01', '2019-06-03', '2019-09-02', '2019-12-02'], dtype='period[B]', freq='B') # ending business day per quarter 'Q-FEB' p_rng.asfreq('B', how='end') [Out]: PeriodIndex(['2019-05-31', '2019-08-30', '2019-11-29', '2020-02-28'], dtype='period[B]', freq='B')
|
기간(Period) 객체를 frequency로 변환한 후에 산술 연산(arithmetic operation)이 가능합니다. 아래 예는 2월달에 끝나는 4 분기의 ending business date에 1 day 를 더한것입니다.
# arithmatic operation: plus one day p_rng.asfreq('B', how='end') + 1 [Out]: PeriodIndex(['2019-06-03', '2019-09-02', '2019-12-02', '2020-03-02'], dtype='period[B]', freq='B')
|
아래의 예는 period object를 ending business date로 먼저 변환하고, 이를 다시 starting hour frequency로 변환한 후에 여기에 12 hours 를 더한 것입니다.
# period ending Business day, starting Hour p_rng.asfreq('B', how='end').asfreq('H', how='start') [Out]: PeriodIndex(['2019-05-31 00:00', '2019-08-30 00:00', '2019-11-29 00:00',
'2020-02-28 00:00'],
dtype='period[H]', freq='H') # plus 12 hours p_12h_rng = p_rng.asfreq('B', how='end').asfreq('H', how='start') + 12 p_12h_rng [Out]: PeriodIndex(['2019-05-31 12:00', '2019-08-30 12:00', '2019-11-29 12:00', '2020-02-28 12:00'], dtype='period[H]', freq='H') |
(3) 분기 단위의 기간과 timestamp 간 변환하기 (conversion between quarterly period and timestamp) |
pandas date_range() 로 만든 날짜-시간 DatetimeIndex를 pandas.to_period() 메소드를 사용해서 PeriodIndex로 변환할 수 있습니다.
import pandas as pd # generate dates range with 12 Months ts = pd.date_range('2020-01-01', periods = 12, freq='M') ts
# convert from DatetimeIndex to PeriodIndex p = ts.to_period() p
|
반대로, pandas.to_timestamp() 메소드를 사용해서 PeriodIndex를 DatetimeIndex로 변환할 수 있습니다.
# convert from PeriodIndex to DatetimeIndex with starting month('M') p.asfreq('B', how='end').asfreq('M', how='start').to_timestamp() [Out]: DatetimeIndex(['2020-01-01', '2020-02-01', '2020-03-01', '2020-04-01',
'2020-05-01', '2020-06-01', '2020-07-01', '2020-08-01',
'2020-09-01', '2020-10-01', '2020-11-01', '2020-12-01'],
dtype='datetime64[ns]', freq='MS') # convert from PeriodIndex to DatatimeIndex with ending minutes('T') p.asfreq('B', how='end').asfreq('T', how='end').to_timestamp() DatetimeIndex(['2020-01-31 23:59:00', '2020-02-28 23:59:00',
'2020-03-31 23:59:00', '2020-04-30 23:59:00',
'2020-05-29 23:59:00', '2020-06-30 23:59:00',
'2020-07-31 23:59:00', '2020-08-31 23:59:00',
'2020-09-30 23:59:00', '2020-10-30 23:59:00',
'2020-11-30 23:59:00', '2020-12-31 23:59:00'],
dtype='datetime64[ns]', freq='BM')
|
(4) 분기 기간 단위 집계 (quarterly period group by aggregation) |
간단한 월 단위 pandas Series 를 분기 단위 Period Index를 가진 Series로 변환한 후에, 분기 단위로 평균을 집계해보겠습니다.
ts = pd.date_range('2020-01-01', periods = 12, freq='M') ts_series = pd.Series(range(len(ts)), index=ts) ts_series
# convert from DatatimeIndex to Quarterly PeriodIndex ts_series.index = ts.to_period(freq='Q-FEB') ts_series [Out]: 2020Q4 0
2020Q4 1
2021Q1 2
2021Q1 3
2021Q1 4
2021Q2 5
2021Q2 6
2021Q2 7
2021Q3 8
2021Q3 9
2021Q3 10
2021Q4 11 Freq: Q-FEB, dtype: int64 # quarterly groupby mean aggregation ts_series.groupby(ts_series.index).mean() [Out]: 2020Q4 0.5
2021Q1 3.0
2021Q2 6.0
2021Q3 9.0
2021Q4 11.0
Freq: Q-FEB, dtype: float64 |
참고로, 아래는 resample() 메소드로 downsampling 해서 분기 단위로 평균을 집계해본 것인데요, 위의 to_period(freq='Q-FEB')로 frequency를 변환해서 groupby()로 집계한 것과 년도(2020 vs. 2021)가 서로 다릅니다.
ts = pd.date_range('2020-01-01', periods = 12, freq='M') ts_series = pd.Series(range(len(ts)), index=ts) ts_series.resample('Q-FEB').mean() [Out]: 2020-02-29 0.5
2020-05-31 3.0
2020-08-31 6.0
2020-11-30 9.0
2021-02-28 11.0
Freq: Q-FEB, dtype: float64
|
resample 시 kind='period' 옵션을 설정해주면 ts.to_period(freq='Q-FEB') 를 groupby 한 결과와 동일한 값을 얻을 수 있습니다.
ts_series.resample('Q-FEB', kind='period').mean() [Out]: 2020Q4 0.5 2021Q1 3.0 2021Q2 6.0 2021Q3 9.0 2021Q4 11.0 Freq: Q-FEB, dtype: float64
|
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)