LITTLE BY LITTLE

시계열 데이터 Datetime / parse_dates / DatetimeIndex / Shift 본문

데이터 분석/파이썬 Basic & EDA

시계열 데이터 Datetime / parse_dates / DatetimeIndex / Shift

위나 2022. 7. 15. 22:19

datetime 오브젝트

from datetime import datetime

now1=datetime.now()
print(now1)

now2=datetime.today()
print(now2)

t1 = datetime.now()
t2 = datetime(1970,1,1)
t3 = datetime(1970, 12, 12, 13, 24, 34)


diff1 = t1 - t2
print(diff1)
print(type(diff1)) #datetime

pd.to_datetime

 

시계열 데이터는 문자열인데, 문자열은 시간 계산을 할 수 없기 때문에 datetime 오브젝트로 변환해주어야한다.

import pandas as pd
import os

from google.colab import files
myfiles = files.upload()

ebola = pd.read_csv('country_timeseries.csv')

print(ebola.info())
# date 컬럼이 object임을 확인(문자열)

ebola['date_dt'] = pd.to_datetime(ebola['Date'])
print(ebola.info()) #datetime
test_df1 = pd.DataFrame({'order_day':['01/01/15','02/01/15','03/01/15']})

test_df1['date_dt1'] = pd.to_datetime(test_df1['order_day'],format='%d/%m/%y')
test_df1['date_dt2'] = pd.to_datetime(test_df1['order_day'],format='%m/%d/%y')
test_df1['date_dt3'] = pd.to_datetime(test_df1['order_day'],format='%y/%m/%d')
print(test_df1)

test_df2 = pd.DataFrame({'order_day':['01-01-15','02-01-15','03-01-15']})
test_df2['date_dt']=pd.to_datetime(test_df2['order_day'],format='%d-%m-%y')
print(test_df2)

* 시간 형식 지정자

더보기

%a 요일 출력 / %A 요일 출력(긴 이름)  / %w 요일 출력(숫자,0부터 일요일) / %d 날짜 출력(2자리 표시)

%b 월 출력 / %B 원 출력(긴 이름) / %m 월 출력(숫자) / %y 년 출력(2자리로 표시)

%Y 년 출력(4자리로 표시) / %H 시간 출력(24시간) / %I 시간 출력(12시간) / %p AM 또는 PM 출력

%M 분 출력(2자리로 표시) / %S 초 출력(2자리로 표시) / %f 마이크로초 출력 

%z : UTC 차이 출력 / %Z 기준 지역 이름 출력 / %j 올해의 지난 일 수 출력 

%U 올해의 지난 수 출력 / %c 날짜와 시간 출력 / %x 날짜 출력 / %X 시간 출력

%G 년 출력 / %u 요일 출력 / %V 올해의 지난 주 수 출력

파일 불러올 때 datetime으로 불러오기 parse_dates=[ 해당 column ]

ebola1 = pd.read_csv('country_timeseries.csv',parse_dates=['Date'])

print(ebola.info())

문자열로 저장된 날짜를 시리즈에 담아서 datetime으로 변환하기

date_series = pd.Series(['2018-05-16','2018-05-17','2018-05-18'])
d1 = pd.to_datetime(date_series)
print(d1)

datetime의 year,month,day 속성으로 년,월,일 정보 바로 추출 가능

print(d1[0].year)
print(d1[0].month)
print(d1[0].day)

dt 접근자 사용하기

접근자 이용하지 않고, 인덱스가 3인 데이터의 년,월,일 데이터 추출

ebola = pd.read_csv('country_timeseries.csv')
ebola['date_dt'] = pd.to_datetime(ebola['Date'])

print(ebola[['Date','date_dt']].head())

print(ebola['date_dt'][3].year)
print(ebola['date_dt'][3].month)
print(ebola['date_dt'][3].day)

dt 접근자 이용해서 인덱스 쓸필요없이 바로 접근 가능

ebola['year'] = ebola['date_dt'].dt.year

print(ebola[['Date','date_dt','year']].head())

 

사례별 시계열 데이터 계산하기

 

 

에볼라 최초 발병일 계산

 

ebola 데이터 뒤쪽 5개 데이터

에볼라 데이터프레임의 마지막 행과 열을 5개씩 살펴본 결과, 시간이 역순으로 설정되어있다는 것을 알 수 있다. 따라서 시간 순으로 데이터를 살펴보려면 마지막부터 봐야한다.

print(ebola.iloc[-5:,:5])

min으로 최초 발병일을 알 수 있다.

print(ebola['date_dt'].min())

각 발병일자에서 최초 발병일자를 빼서 에볼라의 진행정도 (outbreak_d)를 알 수 있다.

ebola['outbreak_d'] = ebola['date_dt'] - ebola['date_dt'].min()
print(ebola[['Date','Day','outbreak_d']].head())

 

파산한 은행의 수 계산하기

 

 

from google.colab import files
myfiles = files.upload()

banks_no_dates= pd.read_csv('banklist.csv')
banks.head()

Date에 해당하는 열을 datetime 오브젝트로 불러오기

banks = pd.read_csv('banklist.csv',parse_dates=[5,6])
print(banks_no_dates.info())

dt접근자와 quarter 속성으로 은행이 파산한 분기 알아보기

banks['closing_quarter'],banks['closing_year'] = (banks['Closing Date']
                                                  .dt.quarter,banks['Closing Date']
                                                  .dt.year)
print(banks.head())

groupby 메소드,size()로 연도별 파산한 은행의 개수 구하기

closing_year = banks.groupby(['closing_year']).size()
print(closing_year)

그래프로 표현

import matplotlib.pyplot as plt
fig, ax = plt.subplots() # ax = axis
ax = closing_year.plot()
plt.show()

fig, ax = plt.subplots()
ax = closing_year_q.plot()
plt.show()

테슬라 주식 데이터로 시간 계산하기

pip install pandas-datareader

from google.colab import files
myfiles = files.upload()

tesla = pd.read_csv('tesla_stock_quandl.csv')
print(tesla.head())
tesla.info()

Object를 datetime으로 바꿔서 시간 계산하기 → 계산하는 컬럼에 (인덱스0번째) parse 옵션줘서 읽어오기

tesla = pd.read_csv('tesla_stock_quandl.csv',parse_dates=[0])
tesla.info() #Date 컬럼이 datetime으로 바뀜

이제 dt접근자를 사용할 수 있으니 2010년의 6월 데이터만 추출

print(tesla.loc[(tesla.Date.dt.year == 2010) & (tesla.Date.dt.month == 6)])

datetime 오브젝트를 인덱스로 설정해서 데이터 추출해보기

tesla.index = tesla['Date']
print(tesla.index)

2015년 데이터 추출

print(tesla['2015'].iloc[:5,:5])

2010년 6월 데이터 추출

print(tesla['2010-06'].iloc[:,:5])

 


시간간격과 인덱스 TimedeltaIndex

 

만약 최초 5일간 수집된 데이터만 보고 싶다면, 시간간격을 인덱스로 지정하여 데이터를 추출하면 된다.

date 열에서 최솟값을 빼면 '흐른 시간(ref_date)'가 된다.

tesla['ref_date']=tesla['Date'] - tesla['Date'].min()
print(tesla.head())

tesla.index = tesla['ref_date']
print(tesla.iloc[:5,:5])

# 최초 5일의 데이터 추출
print(tesla['5day':].iloc[:5,:5])

 


시간 범위와 인덱스

 

결측치가 있는 에볼라 데이터 다루기

ebola = pd.read_csv('country_timeseries.csv',parse_dates=[0])

print(ebola.iloc[:5,:5]) #앞쪽 데이터 nan 존재
print(ebola.iloc[-5:,:5]) #뒤쪽 데이터 nan 존재

2014-12-31부터 2015-01-05 사이의 시간 인덱스 정하기 ( range ( start = , end = ) 이용 )

head_range = pd.date_range(start='2014-12-31', end='2015-01-05')
print(head_range)

 

원본 데이터 손상 방지를 위해서 앞쪽의 5개만 추출해서 df를 만들고,

위에서 생성한 시간 범위 head_range를 인덱스로 설정하기 위해서 먼저 Date컬럼을 인덱스로 지정하기

ebola_5 = ebola.head()
ebola_5.index = ebola_5['Date']
ebola_5.reindex(head_range)
print(ebola_5.iloc[:5,:5])

 


시간 범위의 주기 설정하기

 

  • 시간 범위를 인덱스로 지정하면 DatetimeIndex 자료형이 만들어진다.
  • DatetimeIndex에는 freq 속성이 포함되어있다.
  • freq 속성값을 지정하면 시간 간격을 조정하여 DatetimeIndex를 만들 수 있다.
    • req : 속성값으로 사용할 수 있는 시간 주기
    • B : 평일만 포함 / C : 사용자가 정의한 평일만 포함 / D : 달력 일자 단위 / W : 주간 단위 
    • M : 월의 마지막 날만 포함 / SM : 15일과 월 마지막 날만 포함 / BM : M주기의 값이 휴일이면 제외하고 평일만 포함
    • CBM : BM에 사용자 정의 평일을 적용 / MS : 월 시작일만 포함 / SMS : 월 시작일과 15일만 포함
    • BMS : MS주기의 마지막 값이 휴일이면 제외하고 평일만 포함
    • CBMS : BMS에 사용자 정의 평일을 적용
    • Q : 3,6,9,12월 마지막 날만 포함
    • BQ : 3,6,9,12월 분기 마지막 날이 휴일이면 제외하고, 평일만 포함
    • BQS : 3,6,9,12,월 분기 시작일이 휴일이면 제외하고, 평일만 포함
    • A : 년의 마지막날만 포함 / BA : 년의 마지막 날이 휴일이면 제외하고 평일만 포함
    • AS : 년의 시작일만 포함 / BAS : 년의 시작일이 휴일이면 제외하고 평일만 포함
    • BH : 평일을 시간단위로 포함 (9:00~16:00) / H : 시간단위로 포함(00:00~00:00)
    • T : 분 단위 포함 / S : 초 단위 포함 / L : 밀리초 단위 포함 / U : 마이크로초 단위 포함 / N : 나노초 단위 포함
  • date_range 메소드의 freq 인자값을 B로 설정하여, 평일만 포함된 DatetimeIndex 만들기
print(pd.date_range('2017-01-01','2017-01-07',freq='B'))

 


시간 범위 수정하고 데이터 밀어내기 - Shift

 

나라별 에볼라 확산속도를 비교하고 싶을 때, 발생하기 시작한 날짜를 옮기는 것이 좋다.

ebola.head()

Date열을 인덱스로 지정하고,  x축을 Date열로, y축을 사망자수로 지정하여 그래프를 그려보자.

import matplotlib.pyplot as plt

ebola.index = ebola['Date']

fig, ax = plt.subplots()
ax = ebola.iloc[0:, 1:].plot(ax=ax) #맨 끝 열이 death임
ax.legend(fontsize=7, loc=2, borderaxespad=0.)
plt.show()

위 그래프의 문제점은 " 각 나라의 에볼라 발병일이 달라 그래프가 그려지기 시작한 지점도 다르다는 것 "

→ 에볼라 발병일을 동일한 날짜로 옮겨주기

ebola_sub = ebola[['Day','Cases_Guinea','Cases_Liberia']]
print(ebola_sub.tail(10))

ebola = pd.read_csv('country_timeseries.csv',parse_dates=['Date'])
print(ebola.head().iloc[:,:5])

print(ebola.tail().iloc[:,:5])

 

최댓값과 최솟값으로 시간 범위를 생성하여 new_idx에 저장하자. 이렇게 하면 날짜가 아예 없었던 데이터의 인덱스 생성 가능

ebola.index=ebola['Date']
new_idx = pd.date_range(ebola.index.min() , ebola.index.max())

print(new_idx) 
#ebola데이터는 시간 역순으로 되어있음, reverse해주기
new_idx = reversed(new_idx)

reindex를 사용하여 새로 생성한 인덱스를 새로운 인덱스로 지정해주자.

ebola = ebola.reindex(new_idx)
print(ebola.head().iloc[:,:5])

 

last_valid_index , first_valid_index 를 이용하여 각 나라의 에볼라 발병일을 구하기

 

last_valid = ebola.apply(pd.Series.last_valid_index)
print(last_valid)

first_valid = ebola.apply(pd.Series.first_valid_index)
print(first_valid)

각 나라의 에볼라 발병일의 출발선을 동일하게 하려면 처음 발병한 날(earliest date)에서 각 나라의 에볼라 발병일을 뺀 만큼 옮겨주면 된다. Shift_values 샤용

earliest_date = ebola.index.min()
print(earliest_date)

shift_values = last_valid - earliest_date
print(shift_values)

Shift 메소드는 괄호 안의 인자값(d)만큼 데이터를 밀어내는 역할을 한다.

ebola_dict = {}
for idx, col in enumerate(ebola):
    d = shift_values[idx].days
    shifted = ebola[col].shift(d)
    ebola_dict[col] = shifted

딕셔너리 다시 데이터프레임으로 변환

ebola_shift = pd.DataFrame(ebola_dict)
print(ebola_shift.tail())

마지막으로 인덱스를 Day열로 지정하고, 필요없는 열을 삭제하고, 준비된 데이터프레임으로 그래프 제대로 그리기

ebola_shift.index = ebola_shift['Day']
ebola_shift = ebola_shift.drop(['Day','Date'],axis=1)
print(ebola_shift.tail())

fig, ax = plt.subplots()
ax = ebola_shift.iloc[:, :].plot(ax=ax)
ax.legend(fontsize=7,loc=2,borderaxespad=0.)
plt.show()
Comments