[Pandas 기초] 시계열 데이터(timeseries), Timestamp와 Period

업데이트:

1. 시계열 데이터

판다스에서 시계열 자료형은 Timestamp와 Period라는 두가지 타입이 있다.

Timestamp 자료형은 to_datetime()함수로 생성가능하며 날짜형태의 자료형을 시계열 타입으로 변환해준다.
Period 자료형은 Timestamp(datetime)객체를 다시 기간에 따른 자료형으로 이용하고자 할때 사용한다.

2. 자료형의 시계열 객체 변환 : to_datetime() , to_period()

먼저 데이터를 하나 불러와보자.

import pandas as pd
df = pd.read_csv("~/stock-data.csv")
df.head()
Date Close Start High Low Volume
0 2018-07-02 10100 10850 10900 10000 137977
1 2018-06-29 10700 10550 10900 9990 170253
2 2018-06-28 10400 10900 10950 10150 155769
3 2018-06-27 10900 10800 11050 10500 133548
4 2018-06-26 10800 10900 11000 10700 63039

그리고 데이터 요약정보를 확인한다.

df.info()
[Output]
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 6 columns):
Date      20 non-null object
Close     20 non-null int64
Start     20 non-null int64
High      20 non-null int64
Low       20 non-null int64
Volume    20 non-null int64
dtypes: int64(5), object(1)
memory usage: 1.0+ KB

현재 날짜를 나타내는 Date컬럼은 문자형(object)임을 알 수 있다.

to_datetime()함수를 이용해서 Date컬럼을 시계열 객체(Timestamp)로 변환해보자.

df['new_Date'] = pd.to_datetime(df['Date'])
print(df.head())
print('\n')
print(df.info())
print('\n')
print(type(df['new_Date'][0]))
[Output]
         Date  Close  Start   High    Low  Volume   new_Date
0  2018-07-02  10100  10850  10900  10000  137977 2018-07-02
1  2018-06-29  10700  10550  10900   9990  170253 2018-06-29
2  2018-06-28  10400  10900  10950  10150  155769 2018-06-28
3  2018-06-27  10900  10800  11050  10500  133548 2018-06-27
4  2018-06-26  10800  10900  11000  10700   63039 2018-06-26

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 7 columns):
Date        20 non-null object
Close       20 non-null int64
Start       20 non-null int64
High        20 non-null int64
Low         20 non-null int64
Volume      20 non-null int64
new_Date    20 non-null datetime64[ns]
dtypes: datetime64[ns](1), int64(5), object(1)
memory usage: 1.2+ KB
None

<class 'pandas._libs.tslibs.timestamps.Timestamp'>

기존 Date열 지우고 new_Date를 인덱스로 지정해주자.

df.drop('Date', axis = 1, inplace=True)
df.set_index('new_Date', inplace=True)

print(df.head())
print('\n')
print(df.info())
[Output]
            Close  Start   High    Low  Volume
new_Date                                      
2018-07-02  10100  10850  10900  10000  137977
2018-06-29  10700  10550  10900   9990  170253
2018-06-28  10400  10900  10950  10150  155769
2018-06-27  10900  10800  11050  10500  133548
2018-06-26  10800  10900  11000  10700   63039


<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 20 entries, 2018-07-02 to 2018-06-01
Data columns (total 5 columns):
Close     20 non-null int64
Start     20 non-null int64
High      20 non-null int64
Low       20 non-null int64
Volume    20 non-null int64
dtypes: int64(5)
memory usage: 960.0 bytes
None

데이터요약정보(info)를 확인해보면, 인덱스가 DatetimeIndex임을 알 수 있고 2018년07월02일에서 2018년06월01일 사이에 20개의 날짜가 존재하는 것을 알 수 있다.

이번에는 Timestamp와 Period의 차이를 알아보자.

# Timestamp를 Period로 변환
dates = ['2019-01-01','2020-03-01','2021-06-01']
ts_dates = pd.to_datetime(dates)
print(ts_dates)
print('\n')

# Timestamp를 Period변환
pr_day = ts_dates.to_period(freq='D')   #1일의 기간
print(pr_day)
pr_month = ts_dates.to_period(freq='M') #1개월의 기간
print(pr_month)
pr_year = ts_dates.to_period(freq='A')  #1년의 기간
print(pr_year)
[Output]
DatetimeIndex(['2019-01-01', '2020-03-01', '2021-06-01'], dtype='datetime64[ns]', freq=None)

PeriodIndex(['2019-01-01', '2020-03-01', '2021-06-01'], dtype='period[D]', freq='D')
PeriodIndex(['2019-01', '2020-03', '2021-06'], dtype='period[M]', freq='M')
PeriodIndex(['2019', '2020', '2021'], dtype='period[A-DEC]', freq='A-DEC')

보는 바와 같이 Period객체는 to_period(freq='기간인수')를 통해 datetime변수에 대해 어떤 기간에 따른 자료형을 생성하고자 할때 주로 활용된다. 이는 바로 아무 자료형에나 사용할 수 없고 datetime타입에 대해 적용가능하다.

3. 시계열 데이터 만들기 : date_range() , period_range()

3-1. Timestamp 배열

Timestamp를 배열하는 date_range()함수는 파이선의 내장함수인 range()함수와 비슷한 개념이다.

다음과 같이 옵션을 설정해주면 원하는 Timestamp(datetime)배열을 얻을 수 있다.

import pandas as pd
ts_ms = pd.date_range(start = '2019-01-01',     # 날짜 범위 시작
                     end = None,                # 날짜 범위 끝
                     periods = 6,               # 생성할 Timestamp 개수
                     freq = 'MS',               # 시간 간격(MS : 월의 시작일)
                     tz = 'Asia/Seoul')         # 시간대(timezone)
print(ts_ms)
[Output]
DatetimeIndex(['2019-01-01 00:00:00+09:00', '2019-02-01 00:00:00+09:00',
               '2019-03-01 00:00:00+09:00', '2019-04-01 00:00:00+09:00',
               '2019-05-01 00:00:00+09:00', '2019-06-01 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='MS')

2019년01월01일부터 월의 시작일 간격으로 6개를 생성했다.
이렇게 freq=옵션을 통해 유연한 배열의 생성이 가능하다.

이번에는 월 간격, 월의 마지막 날 기준(freq='M')으로 생성하기 위한 옵션이다.

ts_me = pd.date_range('2019-01-01',
                     periods = 6,
                     freq = 'M',            #1개월 간격, 월의 마지막날 기준
                     tz = 'Asia/Seoul')   
print(ts_me)
print('\n')


ts_3m = pd.date_range('2019-01-01',
                     periods = 6,
                     freq = '3M',           # 3개월 간격, 월의 마지막 날 기준
                     tz = 'Asia/Seoul')
print(ts_3m)
print('\n')
[Output]
DatetimeIndex(['2019-01-31 00:00:00+09:00', '2019-02-28 00:00:00+09:00',
               '2019-03-31 00:00:00+09:00', '2019-04-30 00:00:00+09:00',
               '2019-05-31 00:00:00+09:00', '2019-06-30 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='M')

DatetimeIndex(['2019-01-31 00:00:00+09:00', '2019-04-30 00:00:00+09:00',
               '2019-07-31 00:00:00+09:00', '2019-10-31 00:00:00+09:00',
               '2020-01-31 00:00:00+09:00', '2020-04-30 00:00:00+09:00'],
              dtype='datetime64[ns, Asia/Seoul]', freq='3M')

3-2. Period 배열

마찬가지로 Period 배열을 생성해주는 period_range()함수를 알아보자.
Timestamp와의 차이는 Period는 기간을 나타내는 자료형 이므로, 배열을 적용할때 freq=옵션은 기간의 단위를 의미한다는 점이다.

# 1개월 길이
pr_m = pd.period_range(start = '2019-01-01',
                   	   end = None,
                       periods = 3,
                       freq = 'M')           
print(pr_m)
print('\n')

# 1시간 길이
pr_h = pd.period_range(start = '2019-01-01',
                       end = None,
                       periods = 3,
                       freq = 'H')           
print(pr_h)
print('\n')

# 2시간 길이
pr_2h = pd.period_range(start = '2019-01-01',
                        end = None,
                        periods = 3,
                        freq = '2H')          
print(pr_2h)
[Output]
PeriodIndex(['2019-01', '2019-02', '2019-03'], dtype='period[M]', freq='M')

PeriodIndex(['2019-01-01 00:00', '2019-01-01 01:00', '2019-01-01 02:00'], dtype='period[H]', freq='H')

PeriodIndex(['2019-01-01 00:00', '2019-01-01 02:00', '2019-01-01 04:00'], dtype='period[2H]', freq='2H')

4. 시계열데이터 활용

4-1. 날짜 데이터 분리 : dt.year, dt.month, dt.day

다시 처음으로 돌아와 데이터를 불러와서 Date변수를 날짜변수로 변환한 컬럼을 추가한 부분으로 돌아오자.

import pandas as pd
df = pd.read_csv("~/stock-data.csv")
df['new_Date'] = pd.to_datetime(df['Date']) #Date를 날짜변수로 변환
df.head()
Date Close Start High Low Volume new_Date
0 2018-07-02 10100 10850 10900 10000 137977 2018-07-02
1 2018-06-29 10700 10550 10900 9990 170253 2018-06-29
2 2018-06-28 10400 10900 10950 10150 155769 2018-06-28
3 2018-06-27 10900 10800 11050 10500 133548 2018-06-27
4 2018-06-26 10800 10900 11000 10700 63039 2018-06-26

datetime타입에 적용하는 dt속성을 활용해 연(year), 월(month), 일(day)을 날짜에서 분리해보자.

df['Year'] = df['new_Date'].dt.year
df['Month'] = df['new_Date'].dt.month
df['Day'] = df['new_Date'].dt.day
df.head()
Date Close Start High Low Volume new_Date Year Month Day
0 2018-07-02 10100 10850 10900 10000 137977 2018-07-02 2018 7 2
1 2018-06-29 10700 10550 10900 9990 170253 2018-06-29 2018 6 29
2 2018-06-28 10400 10900 10950 10150 155769 2018-06-28 2018 6 28
3 2018-06-27 10900 10800 11050 10500 133548 2018-06-27 2018 6 27
4 2018-06-26 10800 10900 11000 10700 63039 2018-06-26 2018 6 26

이번에는 아까 배운 to_period()함수를 이용해 표기를 변경해보자

df['Date_yr'] = df['new_Date'].dt.to_period(freq = 'A')  # 연도까지
df['Date_m'] = df['new_Date'].dt.to_period(freq = 'M')   # 연월까지
df.head()
Date Close Start High Low Volume new_Date Year Month Day Date_yr Date_m
0 2018-07-02 10100 10850 10900 10000 137977 2018-07-02 2018 7 2 2018 2018-07
1 2018-06-29 10700 10550 10900 9990 170253 2018-06-29 2018 6 29 2018 2018-06
2 2018-06-28 10400 10900 10950 10150 155769 2018-06-28 2018 6 28 2018 2018-06
3 2018-06-27 10900 10800 11050 10500 133548 2018-06-27 2018 6 27 2018 2018-06
4 2018-06-26 10800 10900 11000 10700 63039 2018-06-26 2018 6 26 2018 2018-06

4-2. 날짜 인덱스 활용

이번에는 시계열 타입을 인덱스로 두고 활용하는 방법에 대해 알아보자.

import pandas as pd
df = pd.read_csv("~/stock-data.csv")
df['new_Date'] = pd.to_datetime(df['Date'])  #Date를 날짜변수로 변환
df.set_index('new_Date',inplace=True)   #인덱스로 지정
df.head()
Date Close Start High Low Volume
new_Date
2018-07-02 2018-07-02 10100 10850 10900 10000 137977
2018-06-29 2018-06-29 10700 10550 10900 9990 170253
2018-06-28 2018-06-28 10400 10900 10950 10150 155769
2018-06-27 2018-06-27 10900 10800 11050 10500 133548
2018-06-26 2018-06-26 10800 10900 11000 10700 63039

시계열 타입이 인덱스인 경우에는, 꼭 인덱스이름과 같지 않아도 특정 연도, 연도(2018), 연월(2018-07), 연월일(2018-07-02) 등과 같이 인덱싱이 가능하다.

print(df.loc['2018-06'])      # 6월에 해당하는 row 인덱싱
print('\n')
print(df['2018-07'])          # 7월에 해당하는 row 인덱싱
print('\n')
print(df['2018-06-25' : '2018-06-20'])     # 해당기간의 인덱싱
[Output]
                  Date  Close  Start   High    Low  Volume
new_Date                                                  
2018-06-29  2018-06-29  10700  10550  10900   9990  170253
2018-06-28  2018-06-28  10400  10900  10950  10150  155769
2018-06-27  2018-06-27  10900  10800  11050  10500  133548
2018-06-26  2018-06-26  10800  10900  11000  10700   63039
2018-06-25  2018-06-25  11150  11400  11450  11000   55519
2018-06-22  2018-06-22  11300  11250  11450  10750  134805
2018-06-21  2018-06-21  11200  11350  11750  11200  133002
2018-06-20  2018-06-20  11550  11200  11600  10900  308596
2018-06-19  2018-06-19  11300  11850  11950  11300  180656
2018-06-18  2018-06-18  12000  13400  13400  12000  309787
2018-06-15  2018-06-15  13400  13600  13600  12900  201376
2018-06-14  2018-06-14  13450  13200  13700  13150  347451
2018-06-12  2018-06-12  13200  12200  13300  12050  558148
2018-06-11  2018-06-11  11950  12000  12250  11950   62293
2018-06-08  2018-06-08  11950  11950  12200  11800   59258
2018-06-07  2018-06-07  11950  12200  12300  11900   49088
2018-06-05  2018-06-05  12150  11800  12250  11800   42485
2018-06-04  2018-06-04  11900  11900  12200  11700   25171
2018-06-01  2018-06-01  11900  11800  12100  11750   32062


                  Date  Close  Start   High    Low  Volume
new_Date                                                  
2018-07-02  2018-07-02  10100  10850  10900  10000  137977


                  Date  Close  Start   High    Low  Volume
new_Date                                                  
2018-06-25  2018-06-25  11150  11400  11450  11000   55519
2018-06-22  2018-06-22  11300  11250  11450  10750  134805
2018-06-21  2018-06-21  11200  11350  11750  11200  133002
2018-06-20  2018-06-20  11550  11200  11600  10900  308596

4-3. 오늘과의 날짜 차이 열 만들기

오늘 날짜를 2019-07-18이라고 하고 경과일을 구해보자.

today = pd.to_datetime('2019-07-18')
df['time_delta'] = today - df.index
df.head()
Date Close Start High Low Volume time_delta
new_Date
2018-07-02 2018-07-02 10100 10850 10900 10000 137977 381 days
2018-06-29 2018-06-29 10700 10550 10900 9990 170253 384 days
2018-06-28 2018-06-28 10400 10900 10950 10150 155769 385 days
2018-06-27 2018-06-27 10900 10800 11050 10500 133548 386 days
2018-06-26 2018-06-26 10800 10900 11000 10700 63039 387 days

차이값을 보면 알아서 days가 붙어 표기해주는 것을 알 수 있다.

4-4. 오늘날짜 : datetime 모듈

판다스에 내장된 시계열 자료형들 외에도 datetime이라는 모듈이 존재한다. 이 모듈의 datetime.now()함수로 오늘 날짜를 초단위까지 구할 수 있는 재밌는 기능이다.

import datetime
now = datetime.datetime.now()
print(now)
print(now.year)
print(now.month)
print(now.day)
print(now.hour)
print(now.minute)
print(now.second)
print('%s-%s-%s' % (now.year, now.month, now.day))
[Output]
2019-08-19 17:58:52.512272
2019
8
19
17
58
52
2019-8-19


Reference

도서 [파이썬 머신러닝 판다스 데이터 분석]을 공부하며 작성하였습니다.

댓글남기기