반응형
#!/usr/bin/env python
# coding: utf-8
# # Pandas V: 시계열 분석
# In[ ]:
import numpy as np
#np.set_printoptions(precision=4, suppress=True)
import pandas as pd
#pd.options.display.max_rows = 20
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
plt.rc('figure', figsize=(10, 6))
from matplotlib import rcParams
rcParams['font.family'] = 'NanumGothic'
rcParams['font.size'] = 10
# # 1. 날짜와 시간
# In[ ]:
from datetime import datetime
# In[ ]:
# 현재 시간: 마이크로초까지 지원
now = datetime.now()
now
# In[ ]:
now.year, now.month, now.day
# In[ ]:
# 시간적인 차이
delta = datetime(2011, 1, 7) - datetime(2008, 6, 24, 8, 15)
delta
# In[ ]:
# Day, Second
delta.days, delta.seconds
# In[ ]:
from datetime import timedelta
# In[ ]:
# 날짜 연산
start = datetime(2011, 1, 7)
start + timedelta(12)
# In[ ]:
start - (timedelta(12) * 2)
# #### datetime 모듈 자료형
#
# 자료형 | 설명
# :---|:---
# date | 그레고리언 달력을 사용해서 날짜(년, 월, 일)를 저장
# time | 하루 중 시간을 시간, 분, 초, 마이크로초 단위로 저장
# datetime | 날짜와 시간을 같이 저장
# timedelta | 두 datetime 값 간의 차이(일, 초, 마이크로초)를 표현
#
# ### 1.1 문자열과 datetime간 변환
# In[ ]:
stamp = datetime(2011, 1, 3)
stamp
# In[ ]:
# datetime --> 문자열
#str(stamp)
stamp.strftime('%Y-%m-%d')
# In[ ]:
# 문자열 --> datetime
value = '2011-01-03'
datetime.strptime(value, '%Y-%m-%d')
# In[ ]:
# 여러개의 문자열 처리(리스트 내포)
datestrs = ['7/6/2011', '8/6/2011']
[datetime.strptime(x, '%m/%d/%Y') for x in datestrs]
# ### 1.2 parser 유틸리티 이용
# In[ ]:
from dateutil.parser import parse
parse('2011-01-03')
# In[ ]:
parse('Jan 31, 1997 10:45 PM')
# In[ ]:
parse('6/12/2011', dayfirst=True)
# ### 1.3 pandas 이용: 색인객체로 생성
# In[ ]:
datestrs = ['2011-07-06 12:00:00', '2011-08-06 00:00:00']
pd.to_datetime(datestrs)
# In[ ]:
# 누락된 값 처리
idx = pd.to_datetime(datestrs + [None])
idx
# In[ ]:
idx[2]
# In[ ]:
pd.isnull(idx)
# ---
# # 2. 시계열 기초
# In[ ]:
from datetime import datetime
# In[ ]:
# 타임스탬프로 색인된 Series 객체 생성
dates = [datetime(2011, 1, 2), datetime(2011, 1, 5),
datetime(2011, 1, 7), datetime(2011, 1, 8),
datetime(2011, 1, 10), datetime(2011, 1, 12)]
ts = pd.Series(np.random.randn(6), index=dates)
ts
# In[ ]:
ts.index
# In[ ]:
# 색인된 시계열 객체 간의 산술연산
ts + ts[::2]
# In[ ]:
# 나노초까지 지원
ts.index.dtype
# In[ ]:
# DatetimeIndex의 스칼라 값은 pandas의 Timestamp 객체
stamp = ts.index[0]
stamp, type(stamp)
# ### 2.1 인덱싱
# In[ ]:
ts
# In[ ]:
ts[2]
# In[ ]:
stamp = ts.index[2]
ts[stamp]
# In[ ]:
# 인덱스에 문자열로 접근 가능
ts['1/10/2011']
ts['20110110']
# In[ ]:
longer_ts = pd.Series(np.random.randn(1000),
index=pd.date_range('1/1/2000', periods=1000))
longer_ts
# In[ ]:
# 문자열의 년으로 인덱싱
longer_ts['2001']
# In[ ]:
# 문자열의 년-월로 인덱싱
longer_ts['2001-05']
# In[ ]:
# datetime으로 인덱싱
ts[datetime(2011, 1, 7):]
# In[ ]:
# 문자열로 범위 지정
ts['1/6/2011':'1/11/2011']
# In[ ]:
# after 이후 날짜 잘라 버리기
ts.truncate(after='1/9/2011')
# In[ ]:
# before 이전 날짜 잘라 버리기
ts.truncate(before='1/9/2011')
# #### DataFrame
# In[ ]:
dates = pd.date_range('1/1/2000', periods=100, freq='W-WED')
long_df = pd.DataFrame(np.random.randn(100, 4),
index=dates,
columns=['Colorado', 'Texas',
'New York', 'Ohio'])
#long_df['5-2001']
long_df.loc['5-2001']
# ### 2.2 중복된 색인(시계열)
# In[ ]:
dates = pd.DatetimeIndex(['1/1/2000', '1/2/2000', '1/2/2000',
'1/2/2000', '1/3/2000'])
dup_ts = pd.Series(np.arange(5), index=dates)
dup_ts
# In[ ]:
dup_ts.index.is_unique
# In[ ]:
# 중복되지 않은 색인
dup_ts['1/3/2000']
# In[ ]:
# 중복된 색인
dup_ts['1/2/2000']
# In[ ]:
# 집계
grouped = dup_ts.groupby(level=0)
# In[ ]:
grouped.mean()
# In[ ]:
grouped.count()
# ---
# # 3. 날짜 다루기
# In[ ]:
ts
# In[ ]:
# 고정된 일 빈도로 변환
ts.resample('D').ffill()
# ### 3.1 날짜 범위 생성
# In[ ]:
# Default: 일별 타임스탬프 생성
index = pd.date_range('2012-04-01', '2012-06-01')
index
# In[ ]:
pd.date_range(start='2012-04-01', periods=20)
# In[ ]:
pd.date_range(end='2012-06-01', periods=20)
# In[ ]:
# BM: 월 영업 마감일
pd.date_range('2000-01-01', '2000-12-01', freq='BM')
# In[ ]:
# 시간 보존
pd.date_range('2012-05-02 12:56:31', periods=5)
# In[ ]:
# normalize: 자정에 맞추어 타임스탬프 정규화
pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True)
# ### 3.2 빈도와 날짜 오프셋
# In[ ]:
from pandas.tseries.offsets import Hour, Minute
# In[ ]:
# 시간 오프셋
hour = Hour()
hour
# In[ ]:
four_hours = Hour(4)
four_hours
# In[ ]:
# 오프셋 연산
Hour(2) + Minute(30)
# In[ ]:
# 4시간 주기로 생성
pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')
# In[ ]:
# 1시간 30분 간격으로 10개 생성
pd.date_range('2000-01-01', periods=10, freq='1h30min')
# In[ ]:
# 3번째 금요일(월별 옵션 만기일)
pd.date_range('2012-01-01', '2012-09-01', freq='WOM-3FRI')
# [<참고> 기본 시계열 빈도](http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases)
# ### 3.3 데이터 쉬프트
# In[ ]:
ts = pd.Series(np.random.randn(4),
index=pd.date_range('1/1/2000', periods=4, freq='M'))
ts
# In[ ]:
# data shift
ts.shift(2)
# In[ ]:
# data shift
ts.shift(-2)
# In[ ]:
# 각 인덱스를 빈도수(2개월) 만큼 이동
ts.shift(2, freq='M')
# In[ ]:
# 각 인덱스를 빈도수(3일) 만큼 이동
ts.shift(3, freq='D')
# In[ ]:
# 각 인덱스를 빈도수(90시간) 만큼 이동
ts.shift(1, freq='90T')
# In[ ]:
from pandas.tseries.offsets import Day, MonthEnd
# In[ ]:
# 오프셋만큼 날짜 쉬프트
now = datetime(2011, 11, 17)
now + 3 * Day()
# In[ ]:
# 빈도 규칙의 다음 날짜로 이동
now + MonthEnd()
# In[ ]:
now + MonthEnd(2)
# In[ ]:
# 앞으로 이동(월 말일)
offset = MonthEnd()
offset.rollforward(now)
# In[ ]:
# 뒤로 이동(월 말일)
offset.rollback(now)
# In[ ]:
ts = pd.Series(np.random.randn(20),
index=pd.date_range('1/15/2000', periods=20, freq='4d'))
ts
# In[ ]:
# groupby 와 함께 사용
ts.groupby(offset.rollforward).mean()
# In[ ]:
# <참고>
ts.resample('M').mean()
# ---
# # 4. 시간대 다루기
# In[ ]:
import pytz
# In[ ]:
pytz.common_timezones[-5:]
# In[ ]:
pytz.timezone('America/New_York')
# In[ ]:
pytz.timezone('Asia/Seoul')
# In[ ]:
pytz.timezone('UTC')
# ### 4.1 지역 시간대 변환
# In[ ]:
rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
# In[ ]:
# 지역 시간대 없음
print(ts.index.tz)
# In[ ]:
# 인덱스 생성시 지역 시간대 지정
pd.date_range('3/9/2012 9:30', periods=10, freq='D', tz='UTC')
# In[ ]:
# tz_localize(): 지역 시간대 설정
ts_utc = ts.tz_localize('UTC')
ts_utc
# In[ ]:
ts_utc.index
# In[ ]:
# tz_convert(): 지역 시간대 변경
ts_utc.tz_convert('UTC')
ts_utc.tz_convert('America/New_York')
ts_utc.tz_convert('Europe/Berlin')
ts_utc.tz_convert('Europe/Berlin')
ts_utc.tz_convert('Asia/Seoul')
# In[ ]:
# DatetimeIndex의 메소드
ts.index.tz_localize('Asia/Seoul')
# ### 4.2 지역 시간대(Timestamp 객체)
# In[ ]:
stamp = pd.Timestamp('2011-03-12 04:00')
stamp_utc = stamp.tz_localize('utc')
stamp_utc.tz_convert('Asia/Seoul')
# In[ ]:
stamp_moscow = pd.Timestamp('2011-03-12 04:00', tz='Europe/Moscow')
stamp_moscow
# In[ ]:
# Total second(나노 초)는 일정(UTC 기준)
stamp_utc.value
stamp_utc.tz_convert('America/New_York').value
# In[ ]:
stamp_utc.tz_convert('America/New_York').value
# In[ ]:
from pandas.tseries.offsets import Hour
stamp = pd.Timestamp('2012-03-12 01:30', tz='US/Eastern')
stamp
# In[ ]:
stamp + Hour()
# In[ ]:
stamp = pd.Timestamp('2012-11-04 00:30', tz='US/Eastern')
stamp
stamp + 2 * Hour()
# ### 4.3 다른 시간대 연산
# In[ ]:
# freq='B': 매 영업일
rng = pd.date_range('3/7/2012 9:30', periods=10, freq='B')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
# In[ ]:
# 서로 다른 시간대의 연산은 UTC로 변환되어 반환
ts1 = ts[:7].tz_localize('Europe/London')
ts2 = ts1[2:].tz_convert('Europe/Moscow')
result = ts1 + ts2
result.index
# ---
# # 5. 기간과 기간 연산
# In[ ]:
# 'A-DEC': 12월을 마지막 달로 하는 년 주기
p = pd.Period(2007, freq='A-DEC')
p
# In[ ]:
p + 5
# In[ ]:
p - 2
# In[ ]:
# 두 기간간의 간격
pd.Period('2014', freq='A-DEC') - p
# In[ ]:
# Period Index
# 월별 기간 범위
rng = pd.period_range('2000-01-01', '2000-06-30', freq='M')
rng
# In[ ]:
pd.Series(np.random.randn(6), index=rng)
# In[ ]:
# 'Q-DEC': 12월을 마지막 달로 하는 분기 주기
values = ['2001Q3', '2002Q2', '2003Q1']
index = pd.PeriodIndex(values, freq='Q-DEC')
index.to_timestamp()
# ### 5.1 Period의 빈도 변환
# In[ ]:
# 'A-DEC': 12월을 마지막 달로 하는 년 주기
# 2007-01 ~ 2007-12
p = pd.Period('2007', freq='A-DEC')
p
# In[ ]:
p.asfreq('M', how='start')
# In[ ]:
p.asfreq('M', how='end')
# In[ ]:
# 'A-JUN': 6월을 마지막 달로 하는 년 주기
# 2006-07 ~ 2007-06
p = pd.Period('2007', freq='A-JUN')
p
# In[ ]:
p.asfreq('M', 'start')
# In[ ]:
p.asfreq('M', 'end')
# In[ ]:
p = pd.Period('Aug-2007', 'M')
p
# In[ ]:
# 2007-07 ~ 2008-06
p.asfreq('A-JUN')
# In[ ]:
# Index 활용
rng = pd.period_range('2006', '2009', freq='A-DEC')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
# In[ ]:
ts.asfreq('M', how='start')
# In[ ]:
ts.asfreq('B', how='end')
# ### 5.2 분기 빈도
# In[ ]:
# 1월을 마지막으로 하는 분기 빈도
p = pd.Period('2012Q4', freq='Q-JAN')
p
# In[ ]:
p.asfreq('D', 'start')
# In[ ]:
p.asfreq('D', 'end')
# In[ ]:
# 'B': 매 영업일, 'T': 매 분
# 분기 영업 마감일의 오후 4시
p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60
p4pm
# In[ ]:
p4pm.to_timestamp()
# In[ ]:
# 인덱스에 활용
rng = pd.period_range('2011Q3', '2012Q4', freq='Q-JAN')
ts = pd.Series(np.arange(len(rng)), index=rng)
ts
# In[ ]:
# 인덱스에 활용
new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60
ts.index = new_rng.to_timestamp()
ts
# ### 5.3 타임스탬프와 Period간 변환
# In[ ]:
rng = pd.date_range('2000-01-01', periods=3, freq='M')
ts = pd.Series(np.random.randn(3), index=rng)
ts
# In[ ]:
# timestamp --> period
pts = ts.to_period()
pts
# In[ ]:
rng = pd.date_range('1/29/2000', periods=6, freq='D')
ts2 = pd.Series(np.random.randn(6), index=rng)
ts2
# In[ ]:
ts2.to_period('M')
# In[ ]:
pts = ts2.to_period()
pts
# In[ ]:
# period --> timestamp
pts.to_timestamp(how='end')
# ### 5.4 배열로 PeriodIndex 생성
# In[ ]:
data = pd.read_csv('data/macrodata.csv')
data.head(5)
# In[ ]:
index = pd.PeriodIndex(year=data.year, quarter=data.quarter,
freq='Q-DEC')
index
# In[ ]:
data.index = index
# In[ ]:
data.head()
# ---
# # 6. 리샘플링과 빈도 변환
# - Up sampling: 기간이 늘어남(보간 필요)
# - 예: 월 --> 일
# - Down sampling: 기간이 줄어듬(집계 필요)
# - 예: 일 --> 월
# In[ ]:
rng = pd.date_range('2000-01-01', periods=100, freq='D')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts.head()
# In[ ]:
ts.resample('M').mean()
# In[ ]:
ts.resample('M', kind='period').mean()
# ### 6.1 Downsampling
# In[ ]:
rng = pd.date_range('2000-01-01', periods=12, freq='T')
ts = pd.Series(np.arange(12), index=rng)
ts
# In[ ]:
# 'left': 시작값이 그룹의 왼쪽에 위치하도록 그룹 생성
ts.resample('5min', closed='left').sum()
# In[ ]:
# 'right': 시작값이 그룹의 오른쪽에 위치하도록 그룹 생성
ts.resample('5min', closed='right').sum()
# In[ ]:
# 표시값을 그룹의 오른쪽 값으로 설정
ts.resample('5min', closed='right', label='right').sum()
# In[ ]:
# offset 이동: shift와 같은 효과
ts.resample('5min', closed='right',
label='right', loffset='-1s').sum()
# #### Open-High-Low-Close (OHLC) resampling
# In[ ]:
ts.resample('5min').ohlc()
# ### 6.2 Upsampling
# In[ ]:
frame = pd.DataFrame(np.random.randn(2, 4),
index=pd.date_range('1/1/2000', periods=2,
freq='W-WED'),
columns=['Colorado', 'Texas', 'New York', 'Ohio'])
frame
# In[ ]:
df_daily = frame.resample('D').asfreq()
df_daily
# In[ ]:
# 결측치 채우기
frame.resample('D').ffill()
# In[ ]:
frame.resample('D').ffill(limit=2)
# In[ ]:
frame.resample('W-THU').ffill()
# ### 6.3 기간 리샘플링
# In[ ]:
frame = pd.DataFrame(np.random.randn(24, 4),
index=pd.period_range('1-2000', '12-2001',
freq='M'),
columns=['Colorado', 'Texas', 'New York', 'Ohio'])
frame.head()
# In[ ]:
annual_frame = frame.resample('A-DEC').mean()
annual_frame
# In[ ]:
# Q-DEC: Quarterly, year ending in December
annual_frame.resample('Q-DEC').ffill()
# In[ ]:
annual_frame.resample('Q-DEC', convention='end').ffill()
# In[ ]:
annual_frame.resample('Q-MAR').ffill()
# ---
# # 참고
# ## Moving Window Functions
# In[ ]:
import numpy as np
import pandas as pd
#pd.options.display.max_rows = 20
#np.set_printoptions(precision=4, suppress=True)
import matplotlib
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
plt.rc('figure', figsize=(10, 6))
matplotlib.rcParams['font.family'] = 'NanumGothic'
#matplotlib.rcParams['font.family'] = '나눔고딕'
matplotlib.rcParams['font.size'] = 10
# In[ ]:
close_px_all = pd.read_csv('data/stock_px_2.csv',
parse_dates=True, index_col=0)
close_px = close_px_all[['AAPL', 'MSFT', 'XOM']]
close_px = close_px.resample('B').ffill()
# In[ ]:
close_px.AAPL.plot()
close_px.AAPL.rolling(250).mean().plot()
# In[ ]:
# In[ ]:
plt.figure()
# In[ ]:
appl_std250 = close_px.AAPL.rolling(250, min_periods=10).std()
appl_std250[5:12]
appl_std250.plot()
# In[ ]:
expanding_mean = appl_std250.expanding().mean()
# In[ ]:
plt.figure()
# In[ ]:
close_px.rolling(60).mean().plot(logy=True)
# In[ ]:
close_px.rolling('20D').mean()
# ### Exponentially Weighted Functions
# In[ ]:
plt.figure()
# In[ ]:
aapl_px = close_px.AAPL['2006':'2007']
ma60 = aapl_px.rolling(30, min_periods=20).mean()
ewma60 = aapl_px.ewm(span=30).mean()
ma60.plot(style='k--', label='Simple MA')
ewma60.plot(style='k-', label='EW MA')
plt.legend()
# ### Binary Moving Window Functions
# In[ ]:
plt.figure()
# In[ ]:
spx_px = close_px_all['SPX']
spx_rets = spx_px.pct_change()
returns = close_px.pct_change()
# In[ ]:
corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets)
corr.plot()
# In[ ]:
plt.figure()
# In[ ]:
corr = returns.rolling(125, min_periods=100).corr(spx_rets)
corr.plot()
# ### User-Defined Moving Window Functions
# In[ ]:
plt.figure()
# In[ ]:
from scipy.stats import percentileofscore
score_at_2percent = lambda x: percentileofscore(x, 0.02)
result = returns.AAPL.rolling(250).apply(score_at_2percent)
result.plot()
# ---
# In[ ]:
# end of file
# In[ ]:
반응형
LIST
'Programming' 카테고리의 다른 글
[Python][Library] 라이브러리 별 기능 요약 (0) | 2022.01.02 |
---|---|
[Python][Library] 3. matplotlib - 1. 시각화 (0) | 2022.01.02 |
[Python][Library] 2 Pandas - 4. 그룹 연산 (0) | 2022.01.02 |
[Python][Library] 2 Pandas - 3 데이터 처리 (0) | 2022.01.02 |
[Python][Library] 2 Pandas - 2. 파일 입출력 (0) | 2022.01.02 |