美文网首页Python
python时间序列(1)

python时间序列(1)

作者: 弦好想断 | 来源:发表于2020-05-10 17:12 被阅读0次

    timedelta表示两个datetime对象之间的时间 差:

    In [14]: delta = datetime(2011, 1, 7) - datetime(2008, 6, 24, 8, 15) 
    In [15]: delta 
    Out[15]: datetime.timedelta(926, 56700) 
    In [16]: delta.days 
    Out[16]: 926 
    In [17]: delta.seconds 
    Out[17]: 56700
    

    给datetime对象加上(或减去)一个或多个timedelta,这样会产生一个新对 象:

    In [18]: from datetime import timedelta 
    In [19]: start = datetime(2011, 1, 7) 
    In [20]: start + timedelta(12) 
    Out[20]: datetime.datetime(2011, 1, 19, 0, 0) 
    In [21]: start - 2 * timedelta(12) 
    Out[21]: datetime.datetime(2010, 12, 14, 0, 0)
    

    利用str或strftime方法(传入一个格式化字符串),datetime对象和pandas的 Timestamp对象可以被格式化为字符串:

    In [22]: stamp = datetime(2011, 1, 3) 
    In [23]: str(stamp) 
    Out[23]: '2011-01-03 00:00:00' 
    In [24]: stamp.strftime('%Y-%m-%d') 
    Out[24]: '2011-01-03'
    

    datetime.strptime可以用这些格式化编码将字符串转换为日期:

    In [25]: value = '2011-01-03' 
    In [26]: datetime.strptime(value, '%Y-%m-%d') 
    Out[26]: datetime.datetime(2011, 1, 3, 0, 0) 
    In [27]: datestrs = ['7/6/2011', '8/6/2011'] 
    In [28]: [datetime.strptime(x, '%m/%d/%Y') for x in datestrs] 
    Out[28]: [datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]
    

    datetime.strptime是通过已知格式进行日期解析的最佳方式。但是每次都要编写格 式定义是很麻烦的事情,尤其是对于一些常见的日期格式。这种情况下,你可以用 dateutil这个第三方包中的parser.parse方法(pandas中已经自动安装好了):

    In [29]: from dateutil.parser import parse 
    In [30]: parse('2011-01-03') 
    Out[30]: datetime.datetime(2011, 1, 3, 0, 0)
    

    dateutil可以解析几乎所有人类能够理解的日期表示形式:

    In [31]: parse('Jan 31, 1997 10:45 PM') 
    Out[31]: datetime.datetime(1997, 1, 31, 22, 45)
    

    注意:dateutil.parser是一个实用但不完美的工具。比如说,它会把一些原本不 是日期的字符串认作是日期(比如"42"会被解析为2042年的今天)。

    在国际通用的格式中,日出现在月的前面很普遍,传入dayfirst=True即可解决这个 问题:

    In [32]: parse('6/12/2011', dayfirst=True) 
    Out[32]: datetime.datetime(2011, 12, 6, 0, 0)
    

    to_datetime方法可以解析多种不同的日期表示形式。不管这些日期是DataFrame的轴索引还是列

    In [33]: datestrs = ['2011-07-06 12:00:00', '2011-08-06 00:00:00 ']
    In [34]: pd.to_datetime(datestrs) 
    Out[34]: DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00 :00'], dtype='dat etime64[ns]', freq=None)
    

    它还可以处理缺失值(None、空字符串等):

    In [35]: idx = pd.to_datetime(datestrs + [None]) 
    In [36]: idx 
    Out[36]: DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00 :00', 'NaT'], dty pe='datetime64[ns]', freq=None) 
    In [37]: idx[2] Out[37]: NaT 
    In [38]: pd.isnull(idx) 
    Out[38]: array([False, False, True], dtype=bool)
    

    NaT(Not a Time)是pandas中时间戳数据的null值。


    带有重复索引的时间序列

    通过检查索引的is_unique属性,我们就可以知道它是不是唯一的:

    In [66]: dup_ts.index.is_unique 
    Out[66]: False
    

    对这个时间序列进行索引,要么产生标量值,要么产生切片,具体要看所选的时间 点是否重复。

    假设你想要对具有非唯一时间戳的数据进行聚合。一个办法是使用groupby,并传 入level=0:

    dup_ts.groupby(level=0)
    

    生成日期范围

    默认情况下,date_range会产生按天计算的时间点。如果只传入起始或结束日期, 那就还得传入一个表示一段时间的数字:

    pd.date_range(start='2012-04-01', periods=20)
    pd.date_range(end='2012-06-01', periods=20)
    

    如果你想生成一个由每月最 后一个工作日组成的日期索引,可以传入"BM"频率(表示business end of month, 表11-4是频率列表),这样就只会包含时间间隔内(或刚好在边界上的)符合频率 要求的日期。

    In [78]: pd.date_range('2000-01-01', '2000-12-01', freq='BM') 
    Out[78]: DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-0 4-28', '2000-05-31', '2000-06-30', '2000-07-31', '2000-0 8-31', '2000-09-29', '2000-10-31', '2000-11-30'], dtype='datetime64[ns]', freq='BM')
    

    表11-4 基本的时间序列频率(不完整)

    有时,虽然起始和结束日期带有时间信息,但你希望产生一组被规范化 (normalize)到午夜的时间戳。normalize选项即可实现该功能:

    In [80]: pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True) 
    Out[80]: DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-0 5-05', '2012-05-06'], dtype='datetime64[ns]', freq='D')
    

    频率和日期偏移量

    pandas中的频率是由一个基础频率(base frequency)和一个倍数组成的。基础频 率通常以一个字符串别名表示,比如"M"表示每月,"H"表示每小时。对于每个基础 频率,都有一个被称为日期偏移量(date offset)的对象与之对应。例如,按小时 计算的频率可以用Hour类表示:

    In [81]: from pandas.tseries.offsets import Hour, Minute 
    In [82]: hour = Hour() 
    In [83]: hour 
    Out[83]: <Hour>
    

    在基础频率前面放上一个整数即可创建倍数:

    pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')
    

    大部分偏移量对象都可通过加法进行连接:

    In [87]: Hour(2) + Minute(30) 
    Out[87]: <150 * Minutes>
    

    同理,你也可以传入频率字符串(如"2h30min"),这种字符串可以被高效地解析 为等效的表达式:

     pd.date_range('2000-01-01', periods=10, freq='1h30min')
    

    有些频率所描述的时间点并不是均匀分隔的。例如,"M"(日历月末)和"BM"(每 月最后一个工作日)就取决于每月的天数,对于后者,还要考虑月末是不是周末。 由于没有更好的术语,我将这些称为锚点偏移量(anchored offset)。
    表11-4列出了pandas中的频率代码和日期偏移量类。

    表11-4 时间序列的基础频率

    WOM日期

    WOM(Week Of Month)是一种非常实用的频率类,它以WOM开头。它使你能获 得诸如“每月第3个星期五”之类的日期:

     pd.date_range('2012-01-01', '2012-09-01', freq='WOM-3FRI')
    

    移动(超前和滞后)数据

    移动(shifting)指的是沿着时间轴将数据前移或后移。Series和DataFrame都有一 个shift方法用于执行单纯的前移或后移操作,保持索引不变:

    In [91]: ts = pd.Series(np.random.randn(4),
          index=pd.date_range('1/1/2000', periods=4 , freq='M')) 
    In [92]: ts 
    Out[92]: 
    2000-01-31 -0.066748 
    2000-02-29 0.838639 
    2000-03-31 -0.117388 
    2000-04-30 -0.517795 
    Freq: M, dtype: float64 
    In [93]: ts.shift(2) #这是后移
    Out[93]: 
    2000-01-31 NaN 
    2000-02-29 NaN 
    2000-03-31 -0.066748 
    2000-04-30 0.838639 
    Freq: M, dtype: float64 
    In [94]: ts.shift(-2) #这是前移
    Out[94]: 
    2000-01-31 -0.117388 
    2000-02-29 -0.517795 
    2000-03-31 NaN 
    2000-04-30 NaN 
    Freq: M, dtype: float64
    

    当我们这样进行移动时,就会在时间序列的前面或后面产生缺失数据。

    shift通常用于计算一个时间序列或多个时间序列(如DataFrame的列)中的百分比 变化。可以这样表达:

    ts / ts.shift(1) - 1
    

    由于单纯的移位操作不会修改索引,所以部分数据会被丢弃。因此,如果频率已 知,则可以将其传给shift以便实现对时间戳进行位移而不是对数据进行简单位移:

    In [95]: ts.shift(2, freq='M') 
    Out[95]: 
    2000-03-31 -0.066748 
    2000-04-30 0.838639 
    2000-05-31 -0.117388 
    2000-06-30 -0.517795 
    Freq: M, dtype: float64
    

    这里还可以使用其他频率,于是你就能非常灵活地对数据进行超前和滞后处理了:

    In [96]: ts.shift(3, freq='D') 
    Out[96]: 
    2000-02-03 -0.066748 
    2000-03-03 0.838639 
    2000-04-03 -0.117388 
    2000-05-03 -0.517795 
    dtype: float64
    In [97]: ts.shift(1, freq='90T') 
    Out[97]: 
    2000-01-31 01:30:00 -0.066748 
    2000-02-29 01:30:00 0.838639 
    2000-03-31 01:30:00 -0.117388 
    2000-04-30 01:30:00 -0.517795 
    Freq: M, dtype: float64
    

    通过偏移量对日期进行位移

    pandas的日期偏移量还可以用在datetime或Timestamp对象上:

    In [98]: from pandas.tseries.offsets import Day, MonthEnd 
    In [99]: now = datetime(2011, 11, 17) 
    In [100]: now + 3 * Day() 
    Out[100]: Timestamp('2011-11-20 00:00:00')
    

    如果加的是锚点偏移量(比如MonthEnd),第一次增量会将原日期向前滚动到符 合频率规则的下一个日期:

    In [101]: now + MonthEnd() 
    Out[101]: Timestamp('2011-11-30 00:00:00') 
    In [102]: now + MonthEnd(2) 
    Out[102]: Timestamp('2011-12-31 00:00:00')
    

    通过锚点偏移量的rollforward和rollback方法,可明确地将日期向前或向后“滚动”:

    In [103]: offset = MonthEnd() 
    In [104]: offset.rollforward(now) 
    Out[104]: Timestamp('2011-11-30 00:00:00') 
    In [105]: offset.rollback(now) 
    Out[105]: Timestamp('2011-10-31 00:00:00')
    

    日期偏移量还有一个巧妙的用法,即结合groupby使用这两个“滚动”方法:

    In [106]: ts = pd.Series(np.random.randn(20),index=pd.date_range('1/15/2000', 
                          period s=20, freq='4d')) 
    In [107]: ts 
    Out[107]: 
    2000-01-15 -0.116696 
    2000-01-19 2.389645 
    2000-01-23 -0.932454 
    2000-01-27 -0.229331 
    2000-01-31 -1.140330 
    2000-02-04 0.439920 
    2000-02-08 -0.823758 
    2000-02-12 -0.520930 
    2000-02-16 0.350282 
    2000-02-20 0.204395 
    2000-02-24 0.133445 
    2000-02-28 0.327905 
    2000-03-03 0.072153 
    2000-03-07 0.131678 
    2000-03-11 -1.297459 
    2000-03-15 0.997747 
    2000-03-19 0.870955 
    2000-03-23 -0.991253 
    2000-03-27 0.151699 
    2000-03-31 1.266151 
    Freq: 4D, dtype: float64 
    In [108]: ts.groupby(offset.rollforward).mean() 
    Out[108]: 
    2000-01-31 -0.005833 
    2000-02-29 0.015894 
    2000-03-31 0.150209 
    dtype: float64
    

    更简单、更快速地实现该功能的办法是使用resample:

    In [109]: ts.resample('M').mean() Out[109]: 2000-01-31 -0.005833 2000-02-29 0.015894 2000-03-31 0.150209 Freq: M, dtype: float64
    

    相关文章

      网友评论

        本文标题:python时间序列(1)

        本文链接:https://www.haomeiwen.com/subject/lvqxghtx.html