• pandas处理时间序列(2):DatetimeIndex、索引和选择、含有重复索引的时间序列、日期范围与频率和移位、时间区间和区间算术


    一、时间序列基础

    1. 时间戳索引DatetimeIndex

    生成20个DatetimeIndex

    from datetime import datetime
    dates = pd.date_range(start='2019-04-01',periods=20)
    dates
    

     用这20个索引作为ts的索引

    ts = pd.Series(np.random.randn(20),index=dates)
    ts
    

    不同索引的时间序列之间的算术运算在日期上自动对齐

    ts + ts[::2]
    

    pandas使用numpy的datetime64数据类型在纳秒级的分辨率下存储时间戳

    ts.index.dtype 
    

    DatetimeIndex中的标量值是pandas的Timestamp对象

    stamp =ts.index[0]
    stamp
    

     

    2. 索引、选择

    (1) 索引 

    ts是一个series;stamp是索引为2的时间戳,Timestamp('2019-04-03 00:00:00', freq='D')

    stamp =ts.index[2]
    
    ts[stamp]

    为了方便,可以传递一个能解释为日期的字符串

    (2) 选择

    [1]对于长的时间序列,可以传递一个年份或一个年份和月份来选择数据的切片

    longer_ts = pd.Series(np.random.randn(10),index=pd.date_range('4/1/2019',periods=10))
    longer_ts
    

    选择2019年4月份的所有数据

    longer_ts.loc['2019-4']#可以写成'2019/04',不能写成'201904'
    

     选择2019年的所有数据

    longer_ts['2019'] 
    

    [2]选择一段时间内的数据

    ts[datetime(2019,1,1):]
    

    ts['1/4/2019':'4/10/2019']
    

    truncate也可以实现在两个日期间对Series进行切片

    ts.truncate(after='4/3/2019')
    

    以上操作也都适用于DataFrame

      

    3. 含有重复索引的时间序列

     在某些应用中,可能会有多个数据观察值落在特定的时间戳中。

    dates = pd.DatetimeIndex(['4/1/2019','4/2/2019','4/2/2019','4/2/2019','4/3/2019'])
    
    dup_ts = pd.Series(np.arange(5),index=dates)
    dup_ts
    

    通过检查索引的is_unique属性,我们可以看出索引并不是唯一的。

    dup_ts.index.is_unique
    

    对上面的Series进行索引,结果是标量值还是Series切片取决于是否有时间戳是重复的。

    假设你想要聚合含有非唯一时间戳的数据,一种方式就是使用groupby并传递level=0

     

    二、日期范围、频率和移位

      有些应用中经常需要处理固定频率的场景,例如每日的、每月的或每10分钟,这意味着我们甚至需要在必要的时候向时间序列中引入缺失值。pandas可以帮助我们重新采样、推断频率以及生成固定频率的数据范围。

    1. 生成日期范围pd.date_range()、pd.period_range()

    常用函数:

    • pd.date_range()生成的是DatetimeIndex格式的日期序列;
    • pd.period_range(),生成PeriodIndex的时期日期序列。

    (1)pd.date_range()

    参数:起始时间,结束时间,freq,periods  (四选三)

      开始日期和结束日期严格定义了生成日期索引的边界, 周时间序列,默认以sunday周日作为一周最后一日;若要改成周一作为第一天,freq='W-SAT'

      freq='M'月,'D'天,'W',周,'Y'年。默认情况下,date_range生成的是每日的时间戳,如果只传递一个起始或结尾日期,就必须要传递一个用于生成范围的数字,如 “BM” 代表 bussiness end of month

    #使用date_range生成日期序列
    #如要详细了解该函数,可以使用help(pd.date_range)
    #参数四选三:起始时间,结束时间,freq,periods
    #freq='M'月,'D'天,'W',周,'Y'年
    #生成月时间序列
    dm = pd.date_range('2018/01/01', freq='M', periods=12)
    print(f'生成月时间序列:
    {dm}')
    #算头不算尾
    #生成年时间序列,默认是以12月结尾,freq='Y-DEC'
    dy=pd.date_range('2008-01-01','2019-01-10',freq='Y')
    print(f'生成年时间序列:
    {dy}')
    #生成日时间序列
    dd=pd.date_range('2018-01-01',freq='D',periods=10)
    print(f'生成日时间序列:
    {dd}')
    #生成周时间序列,默认以sunday周日作为一周最后一日
    #如要改成周一作为第一天,freq='W-SAT'
    dw=pd.date_range('2018-01-01',freq='W',periods=10)
    print(f'生成周时间序列:
    {dw}')
    

    画以时间为x轴的图,pandas的DataFrame自动将index列作为x轴
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus']=False
    #画以时间为x轴的图,pandas的DataFrame自动将index列作为x轴
    np.random.seed(2)
    #生成日期序列
    x=pd.date_range('2018/01/01','2019/12/31', freq='d')
    #x=pd.period_range('2018/01/01','2019/12/31', freq='d')
    #标准正态分布时间序列
    y=np.random.standard_normal(len(x))
    #将二者转换为pandas的数据格式
    df=pd.DataFrame(y,columns=['标准正态分布'],index=x)
    df.plot(figsize=(12,6))
    plt.title('模拟标准正态分布随机数')
    
    ax = plt.gca()  
    ax.spines['right'].set_color('none') 
    ax.spines['top'].set_color('none')  
    plt.show()
    

      

    (2)pd.period_range()

    具体period见第五节

    #使用period_range生成日期序列
    #参数四选三:起始时间,结束时间,freq,periods
    #freq='M'月,'D'天,'W',周,'Y'年
    #生成月时期序列
    dpm = pd.period_range('2019/01/01', freq='M', periods=12)
    print(f'生成月时间序列:
    {dpm}')
    #生成年时期序列,默认是以12月结尾,freq='Y-DEC'
    dpy=pd.period_range('2008-01-01','2019-01-10',freq='Y')
    print(f'生成年时间序列:
    {dpy}')
    #生成日时期序列
    dpd=pd.period_range('2018-01-01',freq='D',periods=10)
    print(f'生成日时间序列:
    {dpd}')
    #生成周时期序列,默认以sunday周日作为一周最后一日
    #如要改成周一作为第一天,freq='W-SAT'
    dpw=pd.period_range('2018-01-01',freq='W-SUN',periods=10)
    print(f'生成周时间序列:
    {dpw}')
    

    其他的一些freq频率值,见下图

    有时候会获得包含时间信息的开始日期或结束日期,但是想要生成的是标准化为零点的时间戳。用normalize=True就可以解决

    pd.date_range(start='2019-4-1 12:45:23',periods=5) #不加normalize
    

    pd.date_range(start='2019-4-1 12:45:23',periods=5,normalize=True)
    

    2. 频率和日期偏置

     pandas中的频率是由基础频率和倍数组成的。基础频率通常会有字符串别名,例如'M'代表每月,'H'代表每小时。对于每个基础频率,都有一个对象可以被用于定义日期偏置。例如,每小时的频率可以使用Hour类来表示。

    from pandas.tseries.offsets import Hour,Minute
    hour = Hour()
    hour
    

    four_hours = Hour(4)
    four_hours
    

    pd.date_range(start='2019-4-1',periods=5,freq='4h')
    

    pd.date_range(start='2019-4-1',periods=5,freq='1h30min')
    

    月中某星期的日期week of month  

    例子:每月第三个星期五  

    rng = pd.date_range('2019-4-1','2019-7-5',freq='WOM-3FRI')
    list(rng)
    

    3. 移位(前向和后向)日期

       “移位”是指将日期按时间向前移动或向后移动。Series和DataFrame都有一个shift方法用于进行简单的前向或后向移位,而不改变索引

    (1)shift

    ts = pd.Series(np.random.randn(4),
                  index=pd.date_range('4/1/2019',periods=4,freq='M'))
    ts
    

    ts.shift(2)
    

    ts.shift(-2)
    

    由于简单移位并不改变索引,一些数据会被丢弃。因此,如果频率是已知的,则可以将频率传递给shift来推移时间戳而不是简单的数据:

    ts.shift(2,freq='D')
    

    ts.shift(2,freq='M') #'M'日历月末
    

    ts.shift(2,freq='BM') #'BM'月内最后工作日
    

    (2)使用偏置进行移位日期

    from pandas.tseries.offsets import Day,MonthEnd
    now = datetime.now()
    now
    

    now + 3 * Day()
    

    如果添加锚定偏置量,比如MonthEnd,根据频率规则,第一个增量会将日期“前滚”到下一个日期:

    now + MonthEnd()
    

    now + MonthEnd(2)
    

    锚定偏置可以使用rollforwardrollback分别显示地将日期向前或向后“滚动”;

    offset = MonthEnd()
    offset.rollforward(now)
    

    offset.rollback(now)
    

    将移位方法与groupby一起使用是日期偏置的一种创造性用法:

    ts = pd.Series(np.random.randn(20),index=pd.date_range('4/1/2019',periods=20,freq='4d'))
    ts
    

    ts.groupby(offset.rollforward).mean()
    

    resample可以得到同样的结果

    ts.resample('M').mean()
    

    三、时区处理

    待用到时候再添加  

      

    四、时间区间和区间算术

    1. Period、period_range

    (1)Period

    时间区间Period表示的是时间范围,比如数日、数月、数季、数年等。

    定义一个时间区间Period

    p = pd.Period(2019,freq='A-DEC')
    p
    

    通过加减整数可以实现对Period的移动

    如果两个Period对象拥有相同频率,则它们的差就是它们之间的单位数量

    pd.Period('2018',freq='A-DEC') - p
    

    (2)period_range

    功能:用来生成日期序列
    参数:起始时间,结束时间,freq,periods(四选三)
       freq='M'月,'D'天,'W',周,'Y'年
    #生成月时期序列
    dpm = pd.period_range('2019/01/01', freq='M', periods=12)
    print(f'生成时间序列:
    {dpm}')
    #生成年时期序列,默认是以12月结尾,freq='Y-DEC'
    dpy=pd.period_range('2008-01-01','2019-01-10',freq='Y')
    print(f'生成时间序列:
    {dpy}')
    #生成日时期序列
    dpd=pd.period_range('2018-01-01',freq='D',periods=10)
    print(f'生成时间序列:
    {dpd}')
    #生成周时期序列,默认以sunday周日作为一周最后一日
    #如要改成周一作为第一天,freq='W-SAT'
    dpw=pd.period_range('2018-01-01',freq='W-SUN',periods=10)
    print(f'生成时间序列:
    {dpw}')
    

    (3)PeriodIndex

    PeriodIndex类的构造函数允许直接使用一组字符串表示一段时期

    values = ['2001Q3','2002Q2','2003Q1']
    index = pd.PeriodIndex(values,freq='Q-DEC')
    index
    

    2. 区间频率转换

    时间序列样本转换主要分两种:即
    • 高频数据向低频数据转换;
    • 低频数据向高频数据转换
    应用场景:行情交易数据一般是高频,基本面一般是月度、季度、年度等低频数据,量化分析的时候,常常要将基本面数据和行情交易数据结合起来进行统计回归分析,这时候就要用到样本数据频率的转换了。
    主要函数:df.resample(),df代表pandas的DataFrame格式数据,resample方法的参数参数中,freq表示重采样频率,例如‘M’、‘5min’,Second(15),用于产生聚合值的函数名或数组函数,例如‘mean’、‘ohlc’、np.max等,默认是‘mean’,其他常用的有:‘first’、‘last’、‘median’、‘max’、‘min’axis=0默认是纵轴,横轴设置axis=1

    (1)asfreq转换频率

    PeriodPeriodIndex对象可以通过asfreq方法被转换成别的频率。

    假设有一个年度时期,希望将其转换为当年年初或年末的一个月度时期:

    频率为‘A-DEC’表示一年的开始到结尾的每一条,'start'表示年初,'end'表示年末

    【1】Period

    对于一个不以12月结束的财政年度,月度子时期的归属情况就不一样了:

    【2】PeriodIndex或TimeSeries的频率转换

     举例:频率转换

    #frq='W'代表周
    df=pd.DataFrame(np.random.randn(5,4),
                index=pd.date_range('1/4/2019',periods=5,freq='W'),
                columns=['GZ','BJ','SH','SZ'])
    df
    

    低频数据向高频数据转换【周-日】

    #将上述样本转换为日序列,缺失值使用前值补上
    #如使用后值则用bfill()
    df_daily=df.resample('D').ffill()
    df_daily.head(10)
    

    高频数据向低频数据转化【日-月】

    df_daily1=df.resample('M').ffill()
    df_daily1.head(10)
    

    根据period来重采样

    #根据period来重采样
    df1=pd.DataFrame(np.random.randn(5,4),
                index=pd.period_range('1/1/2017',periods=5,freq='W'),
                columns=['GZ','BJ','SH','SZ'])
    df1.head()
    

    df2=pd.DataFrame(np.random.randn(2,4),
                index=pd.period_range('1-2017','12-2018',freq='A'),
                columns=['GZ','BJ','SH','SZ'])
    df2.head()
    

    3. 季度区间频率

      季度型数据在会计、金融等领域中很常见,许多季度型数据都会涉及“财年末”的概念,通常是一年12个月中某月的最后一个日历日或工作日。就这一点来说,时期“2012Q4”根据财年末的不同会有不同的含义。pandas支持12种可能的季度型频率,即Q-JAN到Q-DEC:

      2012Q4指的是2011年第四个季度,也就是2011.11.01-2012-01.31

      在以1月结束的财年中,2012Q4是从11月到1月(将其转换为日型频率就明白了)

    例如:要获取该季度倒数第二个工作日下午4点的时间戳:

    period_range可以生成季度型范围。季度型范围的算术运算也跟上面是一样的:

    4. 时间戳Timestamp与Period区间的转换

    (1)to_period()

    由于时期指的是非重叠时间区间,因此对于给定的频率,一个给定的时间戳只能属于一个时期。新PeriodIndex的频率默认是从时间戳推断而来的,你也可以指定任何别的频率。结果中语序存在重复时期:

    (2)to_timestamp()

    5. 通过数组创建PeriodIndex

       固定频率的数据集通常会将时间信息分开存放在多个列中。例如:年度和季度就分布存放在不同的列中:

    将这两个数组以及一个频率传入PeriodIndex,就可以将它们合并成DataFrame的一个索引:

    参考文献:

    【1】【手把手教你】Python处理金融数据

    【2】Pandas时间序列:时期(period)及其算术运算

    【3】pandas 快速处理 date_time 日期格式

  • 相关阅读:
    设计模式复习-单例模式
    设计模式复习-组合模式
    设计模式复习-迭代器模式
    设计模式复习-备忘录模式
    PAT 1085 PAT单位排行 (Microsoft_zzt)
    PAT L1-034 点赞
    PAT L1-032 Left-pad
    PAT 甲级 1046 Shortest Distance
    PAT 甲级 1077 Kuchiguse
    PAT 甲级 1027 Colors in Mars
  • 原文地址:https://www.cnblogs.com/nxf-rabbit75/p/10662025.html
Copyright © 2020-2023  润新知