常用库与设置
常用库
import numpy as np
import pandas as pd
np.random.seed(12345)
import matplotlib.pyplot as plt
%matplotlib widget
plt.rc("figure", figsize=(10, 6))
PREVIOUS_MAX_ROWS = pd.options.display.max_rows
pd.options.display.max_rows = 20
np.set_printoptions(precision=4, suppress=True)
日期时间库和模块
from datetime import datetime, timedelta
import pytz # 时区处理
from dateutil.parser import parse # 解析日期字符串
from pandas.tseries.offsets import Hour, Minute # 日期偏置增量
datetime模块(Python)--日期时间
加载datetime,timedelta, date,time函数
from datetime import date, datetime, time, timedelta
datetime对象--时间戳
创建datetime对象--datetime
(self, /, *args, **kwargs)(self, /, *args, **kwargs)
dt = datetime(2021, 9, 6, 13, 33, 18)
print(dt)
属性
单位属性--year | month | day | hour | minute | second | microsecond | tzinfo 属性
dt.year
dt.month
dt.day
dt.hour
dt.minute
dt.second
dt.microsecond
dt.tzinfo
tz属性--时区
a=pd.date_range("2001-01-01", periods=4, freq="M",tz='UTC')
a.tz
提取日期时间方法--now | date | time
dt1 = datetime.now()
dt1
dt1.date()
dt1.time()
日期时间替换--replace
(year: int=..., month: int=..., day: int=..., hour: int=..., minute: int=..., second: int=..., microsecond: int=..., tzinfo: Optional[_tzinfo]=..., *, fold: int=...) -> datetime
- 不改变原datetime对象
dt.replace(year=2000, month=12, day=31, minute=0, second=0, hour=0)
格式转换
时间日期的字符串格式
-
datetime格式说明:
- 日期——年:%Y(四位数),%y(2位数);月:%m(2位);日:%d(2位)
- 时间——小时:%H(24时),%h(12时);分钟:%M(2位);秒:S%
- 星期——星期日期【0(星期天),6】:%w;一年中的第几周:%U(周日为每周第一天),%W(周一为每周第一天)
- 时区偏移——%z(+HHMM或-HHMM)
- 日期格式缩写——%F(%Y-%m-%d),%D(%m-%d-%y)
-
特定地区日期格式化选项:
- 工作日名称:%a(缩写);%A(全写)
- 月份名称:%b(简写),%B(全写)
- 日期和时间:%c
- 适合地区:%p(AM和PM的地区等效);%x(格式化日期);%X(时间)
日期转字符--strftime
- 通过日期格式符号提取对应日期部分
dt = datetime(2021, 9, 6, 13, 33, 18)
print(dt)
a = dt.strftime("%m/%d/%Y %H:%M:%S")
print(a)
字符转日期--strptime
- 通过日期格式提取字符中的日期,位置和分隔符需对应
a = "20210906"
b = datetime.strptime(a, "%Y%m%d")
print(a, b)
timedelta对象--时间间隔
创建timedelta对象
- 以days,seconds,microseconds三个时间对象共同表示时间间隔
timedelta--创建timedelta对象
(days: float=..., seconds: float=..., microseconds: float=..., milliseconds: float=..., minutes: float=..., hours: float=..., weeks: float=..., *, fold: int=...)
td = timedelta( days=100, seconds=1000, microseconds=100, milliseconds=1000, minutes=100, hours=100, weeks=100,)td
datetime对象之间的差--创建timedelta
dt = datetime(2021, 9, 6, 13, 33, 18)now = datetime.now()dt - now
提取时间间隔的单位--days | seconds | microseconds属性
td.days
td.seconds
td.microseconds
最大值,最小值,最小时间间隔属性--max | min | resolution
timedelta.max
timedelta.min
timedelta.resolution
单位转换(以秒为单位)--total_seconds
()
td.total_seconds()
日期运算--+ | - | *
dt = datetime(2021, 9, 6, 13, 33, 18)dt2 = datetime(2011, 11, 15, 22, 30)delta = dt2 - dtprint(type(delta), delta)dt3 = delta * 2 + dtprint(type(dt3), dt3)
dateutil.parser模块--解析通用格式日期字符串
from dateutil.parser import parse
parse--解析字符串日期函数
(timestr, parserinfo=None, **kwargs)
parse("2011-01-03")
parse("Jan 31, 1997 10:45 PM")
parse("6/12/2011", dayfirst=True) # dayfirst 日在开头
parse("6/12/2011")
pytz库--时区信息
import pytz
common_timezones属性--获取时区名称
pytz.common_timezones[:5]
timezone--时区名称转时区对象
(zone)
pytz.timezone('Africa/Abidjan')
pandas库
日期缺失值标识符--NaT
pd.to_datetime([None])
TimeStamp对象
- Timestamp对象内部存储-个Unix纪元(1970-1-1)至今的纳米数量UTC时间戳数值,该数值在时区变化中不变
- 时区的转换不改变时间戳的数值
Timestamp--创建
ts_input=<object object at 0x7f82f22eb750>,freq=None,tz=None,unit=None,year=None,month=None,day=None,hour=None,minute=None,second=None,microsecond=None,nanosecond=None,tzinfo=None,*,fold=None,
- unit : {'D', 'h', 'm', 's', 'ms', 'us', and 'ns'} # 整数或浮点值输入的时间单位
- tzinfo : datetime.tzinfo
- fold : {0, 1} # 是否跟随时令移动
接收日期字符串
pd.Timestamp('2017-01-01T12')
接收datetime对象
pd.Timestamp(datetime.now())
根据参数创建
pd.Timestamp(1513393355.5, unit='s')
pd.Timestamp(1513393355, unit='s', tz='US/Pacific')
a=pd.Timestamp(2017, 1, 1, 12)print(a)pd.Timestamp(year=2017, month=1, day=1, hour=12)
to_timestamp--时区对象转换为
- freq : str or DateOffset
Target frequency. Default is 'D' if self.freq is week or
longer and 'S' otherwise. - how : str, default 'S' (start)
One of 'S', 'E'. Can be aliased as case insensitive
'Start', 'Finish', 'Begin', 'End'.
p = pd.Period('2012Q4', freq='Q-JAN')print(p)p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60print(p4pm)p4pm.to_timestamp()
属性
value属性-Unix纪元(1970-1-1)至今的纳米数量UTC时间戳数值
stamp = pd.Timestamp('2011-03-12 04:00')stamp_utc = stamp.tz_localize('utc')atamp_an=stamp_utc.tz_convert('America/New_York')
print(stamp.value)print(stamp_utc.value)print(atamp_an.value)
tz属性--查询时区
print(stamp.tz)print(stamp_utc.tz)print(atamp_an.tz)
运算
atamp_an+2*Hour()
DatetimeIndex对象
频率与日期偏置
基础时间序列频率(freq参数)
- 时间:H/h 每小时;T或minute/min 每分钟;S 每秒;L或ms 每豪秒(1/1000);U 每微秒(1/1000,000) - 日:D 每天,B 每工作日; - 周:W-MON/TUE...每周几,WOM-1MON/2MON 每月第几周的周几 - 月:M 月底日,BM 月底工作日;MS 月初日,BMS 月初工作日; - 季度:季度末所在月底——BQ/Q-JAN/FEB(表示年份结束的月份);季度末所在月初——QS-,BQS- - 年:年度末所在月底——A-/BA-;AS-/BAS-
- 表示月份结束的年份: JAN.1 FEB.2 MAR.3 APR.4 MAY.5 JUN.6 JUL.7 AUG.8 SEP.9 OCT.10 NOV.11 DEC.12
- 要点: 是否为工作日,月底还是月初,表示年份结束的月份
日期偏置(offset)--Day(), Hour(), Minute(), Monthend()
- Hour(n) 每n小时,n为倍数--字符串形式:'H'或'4H' - Day(), Hour(), Minute(), Monthend() - 通过加法进行联合:Hour(2)+Minute(30)--'1h30min'
- 默认的采样个数为1
offset模块中的方法
pd.tseries.offsets.BDaypd.tseries.offsets.BMonthBeginpd.tseries.offsets.BMonthEndpd.tseries.offsets.BQuarterBeginpd.tseries.offsets.BQuarterEndpd.tseries.offsets.BYearBeginpd.tseries.offsets.BYearEndpd.tseries.offsets.BaseOffsetpd.tseries.offsets.BusinessDaypd.tseries.offsets.BusinessHourpd.tseries.offsets.BusinessMonthBeginpd.tseries.offsets.BusinessMonthEndpd.tseries.offsets.CBMonthBeginpd.tseries.offsets.CBMonthEndpd.tseries.offsets.CDaypd.tseries.offsets.CustomBusinessDaypd.tseries.offsets.CustomBusinessHourpd.tseries.offsets.CustomBusinessMonthBeginpd.tseries.offsets.CustomBusinessMonthEndpd.tseries.offsets.DateOffsetpd.tseries.offsets.Daypd.tseries.offsets.Easterpd.tseries.offsets.FY5253pd.tseries.offsets.FY5253Quarterpd.tseries.offsets.Hourpd.tseries.offsets.LastWeekOfMonthpd.tseries.offsets.Micropd.tseries.offsets.Millipd.tseries.offsets.Minutepd.tseries.offsets.MonthBeginpd.tseries.offsets.MonthEndpd.tseries.offsets.Nanopd.tseries.offsets.QuarterBeginpd.tseries.offsets.QuarterEndpd.tseries.offsets.Secondpd.tseries.offsets.SemiMonthBeginpd.tseries.offsets.SemiMonthEndpd.tseries.offsets.Tickpd.tseries.offsets.Weekpd.tseries.offsets.WeekOfMonthpd.tseries.offsets.YearBeginpd.tseries.offsets.YearEnd
- 可通过Period对象之间的差的返回结果进行推断
from pandas.tseries.offsets import Hour, Minutehour = Hour()hour
four_hours = Hour(4)four_hours
pd.date_range("2000-01-01", "2000-01-03 23:59", freq="4h")
Hour(2) + Minute(30)
pd.date_range("2000-01-01", periods=10, freq="1h30min")
from pandas.tseries.offsets import Day, MonthEndnow = datetime(2011, 11, 17)now + 3 * Day()
a = MonthEnd()print(a)now + MonthEnd(2)
日期偏置增量--DateOffset
- years- months- weeks- days- hours- minutes- seconds- microseconds- nanoseconds
a = pd.tseries.offsets.DateOffset(days=10, hours=2)a
datetime.now() + a
创建DatetimeIndex对象
其他对象转换--to_datetime(
arg: 'DatetimeScalarOrArrayConvertible',errors: 'str' = 'raise',dayfirst: 'bool' = False,yearfirst: 'bool' = False,utc: 'bool | None' = None,format: 'str | None' = None, - strftime方式解析exact: 'bool' = True, 准确的形式匹配unit: 'str | None' = None, - 频率(freq)-日期时间单位infer_datetime_format: 'bool' = False,origin='unix',cache: 'bool' = True,
) -> 'DatetimeIndex | Series | DatetimeScalar | NaTType | None'
datestrs = ["2011-07-06 12:00:00", "2011-08-06 00:00:00"]pd.to_datetime(datestrs)
idx = pd.to_datetime(datestrs + [None])idx
date_range--固定频率的时间序列
start=None,end=None,periods=None, - 产生的时间个数freq=None, - 采样频率(默认D)tz=None, - 时区(默认本地)normalize: 'bool' = False, - 时间为[00:00:00]name: 'Hashable' = None, - TimeIndex对象的名称closed=None, - {None, 'left', 'right'}区间开闭合**kwargs,
-> 'DatetimeIndex'
- 区间为[左右闭合],右边是否包括看间隔的取值
a=pd.date_range("2001-01-01", periods=4, freq="M",tz='UTC')a
创建DattaFrame或Series对象时创建
datetime对象组成的列表
from datetime import datetimedates = [ 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
ts.index
ts.index.dtype
时区处理
- 世界协调时间或UTC # 相当于本初子午线(即经度0度)上的平均太阳时
- LMT # 本地时间
- 时区 # 被表示为UTC的偏置
tz属性--查询时区
a=pd.date_range("2001-01-01", periods=4, freq="M",tz='UTC')print(a)a.tz
时区本地化与转换
rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')ts = pd.Series(np.random.randn(len(rng)), index=rng)ts
tz_localize--时区本地化(添加时区)
tz,axis=0,level=None,copy: 'bool_t' = True,ambiguous='raise',nonexistent: 'str' = 'raise',
- 只有原时间序列无时区时有效
ts_utc=ts.tz_localize('UTC')ts_utc.index
z_convert--特定时区转换
(tz, axis=0, level=None, copy: bool_t=True) -> FrameOrSeries
- 原时间序列必须含有特定时区
ts_utc.tz_convert('Asia/Shanghai')
不同时区间的操作
- 不同时区最后同一为UTC时区
- 相同时区间的操作不改变时区
rng = pd.date_range('3/7/2012 9:30', periods=10, freq='B')ts = pd.Series(np.random.randn(len(rng)), index=rng)tsts1 = ts[:7].tz_localize('Europe/London')ts2 = ts1[2:].tz_convert('Europe/Moscow')result = ts1 + ts2result.index
result1 = ts1 + ts1result1.index
时间区间
Period对象
创建Period对象--Period
value=None,freq=None,ordinal=None,year=None,month=None,quarter=None,day=None,hour=None,minute=None,second=None,
- freq需与前面数值对应
- 当value为字符串格式日期时,freq可省,但月份无法解析需加上freq
pd.Period()
p=pd.Period(2007,freq='A-DEC')p
m=pd.Period(year=2007,month=4,freq='M')m
a=pd.Period('2005')print(a)a=pd.Period('200512')print(a)a=pd.Period('200512',freq='M')print(a)a=pd.Period('20051224')print(a)pd.Period('3Q2005')
运算--与数值 + | -; 与区间对象之间
- freq指定运算的单位
- 区间对象之间的差返回日期偏置
p+2
m-5
pd.Period('2021')-p
pd.tseries.offsets.YearEnd(14)+p
PeriodIndex对象
创建PeriodIndex对象
PeriodIndex--创建时间区间索引对象
data=None,ordinal=None,freq=None,dtype: 'Dtype | None' = None,copy: 'bool' = False,name: 'Hashable' = None,
values = ['2001Q3', '2002Q2', '2003Q1']index = pd.PeriodIndex(values, freq='Q-DEC')index
data = pd.read_csv('/Users/zhengdale/Documents/python/data/examples/macrodata.csv')data.head(5)
index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC')indexdata.index = indexdata.head()
period_range--创建有规则的时间区间索引对象
start=None,end=None,periods: 'int | None' = None,freq=None,name=None,
rng = pd.period_range('2000-01-01', '2000-06-30', freq='M')rng
to_period--时间戳转换而来
(freq=None, copy=True)
- freq # 默认为原对象的频率
rng = pd.date_range('2000-01-01', periods=3, freq='Y')ts = pd.Series(np.random.randn(3), index=rng)tspts = ts.to_period()pts
rng = pd.date_range('1/29/2000', periods=6, freq='D')ts2 = pd.Series(np.random.randn(6), index=rng)ts2ts2.to_period('M')
改变区间频率--asfreq
freq : strhow : {'E', 'S', 'end', 'start'}, default 'end'Start or end of the timespan.
- 不改变数量(与resample的区别)
p=pd.Period('2007')p.asfreq('M',how='start')
p=pd.Period('20070403')p.asfreq('M')
rng = pd.period_range('2006', '2009', freq='A-DEC')ts = pd.Series(np.random.randn(len(rng)), index=rng)tsts.asfreq('M', how='start')
ts.resample('M').mean()
时间序列索引的运算
时间采样频率的改变--resample
rule,axis=0,closed: 'str | None' = None, - {right,left-默认} # 区间闭合, 除月季年(默认right)label: 'str | None' = None, - {'right', 'left'} # 箱体边缘标签, 除月季年(默认right)convention: 'str' = 'start', - {'start', 'end', 's', 'e'} # 只对PeriodIndex有效,表示是否包含kind: 'str | None' = None, - {'timestamp', 'period'} # 返回的时间序列类型loffset=None, - (timedelta) # 调整labelbase: 'int | None' = None, - 默认0 # on=None,(str) - 作用与哪一列level=None, - 作用与哪一索引层级origin: 'str | TimestampConvertibleTypes' = 'start_day', - {'epoch'-1970-01-01, 'start'-时间序列的第一个值, 'start_day'-时间序列的第一天零点, 'end'-时间序列最后一个值, 'end_day'-时间序列最后一天的零点}offset: 'TimedeltaConvertibleTypes | None' = None, - 日期偏置 # 添加到origin的timedelta
) -> 'Resampler'
- 适用于Timeindex和PeriodIndex
a = pd.date_range("2000", periods=4, freq="M")b = pd.Series(range(4), index=a)b
b.resample("D")
ts = pd.Series( np.random.randn(20), index=pd.date_range("1/15/2000", periods=20, freq="4d"))ts.resample("M").mean()
日期移位
利用频率进行日期移位--shift
(periods=1, freq=None, axis=0, fill_value=None)
periods # 移位的频率数
不改变时间序列的数量与时间索引之间的间隔
freq没有给定时,不改变索引标签,只改变数据位置
freq给出时,只改变索引标签,不改变数据位置
针对时间序列
df = pd.DataFrame( { "Col1": [10, 20, 15, 30, 45], "Col2": [13, 23, 18, 33, 48], "Col3": [17, 27, 22, 37, 52], }, index=pd.date_range("2020-01-01", "2020-01-05"),)df
df.shift(2, "D")
df.shift(1, "2D")
df.shift(-2, "2D")
df.shift(-2)
利用日期偏置进行移位--rollforward | rollback
- 针对的是时间戳(Timestamp)
offset = MonthEnd()offset.rollforward(datetime.now())
offset.rollback(datetime.now())
ts = pd.Series( np.random.randn(20), index=pd.date_range("1/15/2000", periods=20, freq="4d"))ts
ts.groupby(MonthEnd().rollback).mean()
ts.groupby(lambda x: MonthEnd().rollback(x)).mean()
时间序列索引检索
Timestamp对象检索
stamp = ts.index[1]print(type(stamp), stamp)ts[stamp]
字符串格式日期检索
ts["1/10/2011"]ts["20110110"]
检索
[日期区间]检索--年 | 年-月 | 具体区间
longer_ts = pd.Series( np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))longer_tslonger_ts["2001"]
ts["1/10/2011"]ts["20110110"]
longer_ts = pd.Series( np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))longer_tslonger_ts["2001"]
longer_ts["2001-05"]
ts[datetime(2011, 1, 7) :]
ts["1/6/2011":"1/11/2011"]
truncate--截断时间序列
(before=None, after=None, axis=None, copy: 'bool_t' = True) -> 'FrameOrSeries'
- before/after 针对截断而言
ts.truncate(after="1/9/2011")
loc--索引标签检索
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.loc["5-2001"]
移动窗口函数
rolling--固定窗口大小
window: 'int | timedelta | BaseOffset | BaseIndexer', # 窗口大小--窗口包含的观测数量(时间序列可用offset)min_periods: 'int | None' = None, # 最少需要有值的观测点数center: 'bool_t' = False, # 是否使用窗口的中间值作为label(只在Window为int使用)--False:当前观测点为移动窗口的最后一个观测点; True: 当前观测点为移动窗口的中心点win_type: 'str | None' = None, # 观测点的权重(默认一样)on: 'str | None' = None, # 用来指定哪一列axis: 'Axis' = 0,closed: 'str | None' = None, # 定义区间的开闭合(默认right)method: 'str' = 'single', # str {'single', 'table'} 针对列还是整个表格
- 返回: Rolling [window=250,center=False,axis=0,method=single]对象
- 如为时间偏置,起必须保证窗口大小一致
close_px_all = pd.read_csv('/Users/zhengdale/Documents/python/data/examples/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()
close_px.AAPL.rolling(250)
close_px.rolling('7D').mean()
plt.figure()appl_std250 = close_px.AAPL.rolling(250, min_periods=10).std()appl_std250[5:12]appl_std250.plot()
expanding--累积窗口大小的移动窗口函数
min_periods: 'int' = 1,center: 'bool_t | None' = None,axis: 'Axis' = 0,method: 'str' = 'single',
expanding_mean = appl_std250.expanding().mean()plt.figure()expanding_mean.plot()
plt.figure()close_px.rolling(60).mean().plot(logy=True)
close_px.rolling('20D').mean()
aapl_px.ewm——指数加权函数
com: 'Optional[float]' = None,span: 'Optional[float]' = None,halflife: 'Optional[Union[float, TimedeltaConvertibleTypes]]' = None,alpha: 'Optional[float]' = None,min_periods: 'int' = 0,adjust: 'bool_t' = True,ignore_na: 'bool_t' = False,axis: 'Axis' = 0,times: 'Optional[Union[str, np.ndarray, FrameOrSeries]]' = None,
[图片上传失败...(image-9d341a-1632046981052)]
plt.figure()
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
plt.figure()
spx_px = close_px_all['SPX']spx_rets = spx_px.pct_change()returns = close_px.pct_change()returns
corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets)corr.plot()
plt.figure()
corr = returns.rolling(125, min_periods=100).corr(spx_rets)corr.plot()
User-Defined Moving Window Functions
plt.figure()
from scipy.stats import percentileofscorescore_at_2percent = lambda x: percentileofscore(x, 0.02)result = returns.AAPL.rolling(250).apply(score_at_2percent)result.plot()