zoukankan      html  css  js  c++  java
  • 《利用python进行数据分析》读书笔记--第十章 时间序列(一)

    时间序列是很重要的。时间序列(time series)数据是一种重要的结构化数据格式。时间序列的意义取决于具体的应用场景,主要有以下几种:

    • 时间戳(timestamp),特定的时刻
    • 固定时期(period),如2015年全年
    • 时间间隔(interval),由起始和结束时间戳表示。就是说,时期可以是时间间隔的特例。
    • 实验或过程时间,每个时间点都是相对于特定起始时间的一个度量。例如,自从放入烤箱时起,每秒钟饼干的直径。

    pandas提供了一组标准的时间序列处理工具和数据算法。因此可以高效处理非常大的时间序列,轻松进行切片/切块、聚合、对定期/不定期的时间序列进行重采样等。也就是说,大部分都对金融和经济数据尤为有用,当然也可以用它们来分析服务器日志数据。

    1、日期和时间数据类型及工具

    Python标准库中包含用于日期(date)、时间(time)数据的数据类型。而且还有日历方面的功能。主要会用到datetime、time、calendar模块。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from datetime import datetime
    
    now = datetime.now()
    #datetime以毫秒形式储存时间
    print now,now.year,now.month,now.day,now.microsecond,'
    '
    #print datetime(2015,12,17,20,00,01,555555) #设置一个时间
    #datetime.timedelta表示两个datetime对象之间的时间差
    #换句话说,datetime格式可以相相减
    delta = datetime(2011,1,7) - datetime(2008,6,24,8,15)
    print delta
    #把注意下面是days And seconds
    print dt.timedelta(926,56700)
    print delta.days
    print delta.seconds
    #下面是错误的
    #print delta.minutes
    start = datetime(2011,1,7)
    #参数分别为days,seconds,microseconds(微秒),milliseconds(毫秒),minutes,hours,weeks,除了微秒小数自动四舍五入之外,其他的都能自动转换为其他度量
    print start + dt.timedelta(1,20,0.5,5,10,10,0)
    >>>
    2015-12-17 20:24:21.829000 2015 12 17 829000 

    926 days, 15:45:00
    926 days, 15:45:00
    926
    56700
    2011-01-08 10:10:20.005001
    [Finished in 0.6s]

    datetime中的数据类型有:

    image

    • 字符串和datetime的相互转换

    利用str或者strftime方法(传入一个格式化字符串),datetime对象和pandas中timestamp对象就可以转换为字符串:

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from datetime import datetime
    from dateutil.parser import parse
    
    stamp = datetime(2011,1,3)
    print str(stamp),'
    '
    #看一下下面的字符,很有意思,自己不小心打错了,运行仍然是正确的
    print stamp.strftime('&Y-%m-%d')
    print stamp.strftime('%Y-%m-%d'),'
    '
    value = '2011-01-03'
    print datetime.strptime(value,'%Y-%m-%d') #注意这是datetime函数的函数,不是模块的函数
    datestrs = ['7/6/2011','8/6/2011']
    print [datetime.strptime(x,'%m/%d/%Y') for x in datestrs]
    #上面将字符串转化为最常用的格式,但是米次都自己写出来有点麻烦,可以用dateutil这个第三方包中的parser.parse方法
    print parse('2011-01-03')
    #dateutil可以几乎解析所有能够理解的日期表示形式(很可惜中文不行)
    #这个应该是很实用的
    print parse('2011/01/03')
    print parse('Jan 31,1997 10:45 PM')
    #国际通用格式中,日出现在月的前面,传入dayfirst = True即可
    print parse('6/12/2011',dayfirst = True),'
    '
    #pandas通常是用于处理成组日期的,不管这些日期是DataFrame的行还是列。
    print pd.to_datetime(datestrs),'
    '
    idx = pd.to_datetime(datestrs + [None])
    print idx
    print idx[2] #这里应该是NaT(Not a Time)
    print pd.isnull(idx)
    #parse是一个不完美的工具,比如下面
    print parse('42')
    >>>
    2011-01-03 00:00:00 

    &Y-01-03
    2011-01-03

    2011-01-03 00:00:00
    [datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]
    2011-01-03 00:00:00
    2011-01-03 00:00:00
    1997-01-31 22:45:00
    2011-12-06 00:00:00

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2011-07-06 00:00:00, 2011-08-06 00:00:00]
    Length: 2, Freq: None, Timezone: None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2011-07-06 00:00:00, ..., NaT]
    Length: 3, Freq: None, Timezone: None
    0001-255-255 00:00:00
    [False False  True]
    2042-12-17 00:00:00
    [Finished in 0.6s]

    下面是日期的一些格式:

    image

    image

    datetime对象还有一些特定于当前环境(位于不同国家或使用不同语言系统)的格式化选项。估计用的少?

    image

    2、时间序列基础

    pandas最基本的时间序列类型就是以时间戳(通常用Python字符串或datatime对象表示)为索引的Series。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    
    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)]
    #print dates
    ts = Series(np.random.randn(6),index = dates)
    print ts,'
    '
    #这些datetime对象实际上是被放在一个DatetimeIndex中的。现在,变量ts就成为了TimeSeries了。
    print type(ts)
    print ts.index,'
    '
    #没必要显示使用TimeSeries的构造函数。当创建一个带有DatetimeIndex的Series时,pandas就会知道该对象是一个时间序列
    print ts + ts[::2]
    #pandas用NumPy的datetime64数据类型以纳秒形式存储时间戳:
    print ts.index.dtype
    #DatetimeIndex中的各个标量值是pandas的Timestamp
    stamp = ts.index[0]
    print stamp
    #只要有需要,TimeStamp可以随时自动转换为datetime对象。此外,还可以存储频率信息,且知道如何执行时区转换以及其他操作
    >>>
    2011-01-02   -1.267108
    2011-01-05   -0.450098
    2011-01-07    0.784850
    2011-01-08    0.024722
    2011-01-10    0.638663
    2011-01-12    0.246022

    <class 'pandas.core.series.TimeSeries'>
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2011-01-02 00:00:00, ..., 2011-01-12 00:00:00]
    Length: 6, Freq: None, Timezone: None

    2011-01-02   -2.534216
    2011-01-05         NaN
    2011-01-07    1.569701
    2011-01-08         NaN
    2011-01-10    1.277326
    2011-01-12         NaN
    datetime64[ns]
    2011-01-02 00:00:00
    [Finished in 0.7s]

    索引、选取、子集构造

    TimeSeries是Series的一个子类,所以在索引以及数据选取方面跟Series一样。

    stamp = ts.index[2]
    print ts[stamp],'
    '
    #还有更方便的用法,传入可以被解释为日期的字符串
    print ts['1/10/2011']
    print ts['20110110'],'
    '
    #对于较长的时间序列,只需传入“年”或“年月”即可轻松选取数据切片
    long_ts = Series(np.random.randn(1000),
        index = pd.date_range('1/1/2000',periods = 1000))
    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    
    print long_ts,'
    '
    print long_ts['2001'],'
    '
    print long_ts['2001-05'],'
    '
    #通过日期进行切片的方式只对规则Series有效:
    print ts[datetime(2011,1,7):],'
    '
    #由于大部分时间序列数据都是按照时间先后排序的,因此你可以用不存在于该时间序列中的时间戳对其进行切片(即范围查询)
    #就是说,本来1/6/2011不在index中,却可以用来当作范围
    print ts['1/6/2011':'1/11/2011'],'
    ' #这里可以传入字符串日期、datetime或者Timestamp
    
    print 'This is time and localtime'
    print "time.time(): %f " %  time.time()
    print time.localtime( time.time() )
    print time.asctime( time.localtime(time.time()) )
    ltime=time.localtime(int(time.time()))   #time.time()不能直接运用strftime进行转换
    print time.strftime("%Y-%m-%d %H:%M:%S", ltime)
    #time asctime() 函数接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"
    print 'over','
    '
    
    #还有一个等价方法截取两个日期之间的TimeSeries.
    print ts.truncate(after = '1/9/2011'),'
    '
    
    #上面这些对DataFrame也有效
    dates = pd.date_range('1/1/2000',periods = 100,freq = 'W-WED') #这里的freq是按照星期进行增加
    long_df = DataFrame(np.random.randn(100,4),index = dates,columns = ['Colorado','Texas','New York','Ohio'])
    print long_df.ix['2001-05']
    >>>
    0.0751316698811 
    -0.622706612554
    -0.622706612554

    2000-01-01   -1.646726
    2000-01-02    1.531423
    2000-01-03    0.251503
    2000-01-04    0.938951
    2000-01-05    0.647967
    2000-01-06    0.696173
    2000-01-07   -1.372519
    2000-01-08   -1.398277
    2000-01-09   -0.679975
    2000-01-10   -0.801375
    2000-01-11   -0.241165
    2000-01-12   -0.332811
    2000-01-13   -0.337774
    2000-01-14    0.826756
    2000-01-15   -0.279239
    ...
    2002-09-12   -0.097634
    2002-09-13    2.222456
    2002-09-14    0.042517
    2002-09-15    0.266974
    2002-09-16    0.038329
    2002-09-17   -1.524744
    2002-09-18    1.476706
    2002-09-19    0.108336
    2002-09-20    0.016759
    2002-09-21   -0.072676
    2002-09-22   -0.960545
    2002-09-23    0.520699
    2002-09-24   -1.188202
    2002-09-25    1.669166
    2002-09-26   -0.043997
    Freq: D, Length: 1000

    2001-01-01   -0.168866
    2001-01-02   -0.273377
    2001-01-03    0.094258
    2001-01-04   -0.979666
    2001-01-05    0.947706
    2001-01-06    0.666709
    2001-01-07    0.451145
    2001-01-08   -0.301992
    2001-01-09    0.272385
    2001-01-10   -0.255775
    2001-01-11   -0.321916
    2001-01-12    1.894119
    2001-01-13    0.582272
    2001-01-14   -1.102707
    2001-01-15    0.019423
    ...
    2001-12-17   -0.243563
    2001-12-18    1.757564
    2001-12-19   -0.145106
    2001-12-20   -0.579629
    2001-12-21   -0.431069
    2001-12-22    0.480805
    2001-12-23   -0.651905
    2001-12-24    0.702051
    2001-12-25   -0.384549
    2001-12-26   -1.077664
    2001-12-27   -0.972768
    2001-12-28    1.001220
    2001-12-29    0.418016
    2001-12-30    0.567361
    2001-12-31   -0.811610
    Freq: D, Length: 365

    2001-05-01   -0.071521
    2001-05-02    0.402344
    2001-05-03   -0.568929
    2001-05-04    0.227754
    2001-05-05    0.194631
    2001-05-06   -0.407669
    2001-05-07   -1.407606
    2001-05-08   -0.804147
    2001-05-09    0.050445
    2001-05-10   -0.604275
    2001-05-11    0.270760
    2001-05-12    0.000804
    2001-05-13   -0.348938
    2001-05-14   -1.626158
    2001-05-15    0.084629
    2001-05-16   -0.376655
    2001-05-17    1.913789
    2001-05-18    2.497594
    2001-05-19    0.818446
    2001-05-20    0.067115
    2001-05-21   -0.993827
    2001-05-22    0.940616
    2001-05-23   -0.951763
    2001-05-24   -0.806228
    2001-05-25    0.441872
    2001-05-26    0.067010
    2001-05-27   -1.903360
    2001-05-28   -0.400990
    2001-05-29    0.257146
    2001-05-30    0.785503
    2001-05-31   -1.129024
    Freq: D

    2011-01-07    0.075132
    2011-01-08   -0.985630
    2011-01-10   -0.622707
    2011-01-12   -1.356095

    2011-01-07    0.075132
    2011-01-08   -0.985630
    2011-01-10   -0.622707

    This is time and localtime
    time.time(): 1450362054.149000
    time.struct_time(tm_year=2015, tm_mon=12, tm_mday=17, tm_hour=22, tm_min=20, tm_sec=54, tm_wday=3, tm_yday=351, tm_isdst=0)
    Thu Dec 17 22:20:54 2015
    2015-12-17 22:20:54
    over

    2011-01-02   -0.772858
    2011-01-05   -0.908074
    2011-01-07    0.075132
    2011-01-08   -0.985630

                Colorado     Texas  New York      Ohio
    2001-05-02  0.303341  0.026978 -0.036389  0.463034
    2001-05-09 -1.573227 -0.283074 -0.882382 -1.207936
    2001-05-16  1.520804 -0.838297  0.725690  1.240092
    2001-05-23  1.297194 -0.516198 -0.022075 -0.876630
    2001-05-30 -1.629426  1.022547 -0.131823 -0.621269
    [Finished in 0.7s]

    • 带有重复索引的时间序列
    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    
    #注意下面的DatetimeIndex生成方式
    dates = pd.DatetimeIndex(['1/1/2000','1/2/2000','1/2/2000','1/2/2000','1/3/2000'])
    dup_ts = Series(np.arange(5),index = dates)
    print dup_ts,'
    '
    #通过检唯一的测is_unique属性,我们就可以知道它不是
    print dup_ts.index.is_unique,'
    '
    #此时若索引,得到的可能是标量值,也可能是切片
    print dup_ts['1/2/2000'],'
    '
    print dup_ts['1/3/2000']
    #假如你想要对具有非
    #唯一时间戳的数据进行聚合一个办法是使用groupby,并传入level = 0
    grouped = dup_ts.groupby(level = 0)
    print grouped.mean(),'
    '
    print grouped.count()
    >>>
    2000-01-01    0
    2000-01-02    1
    2000-01-02    2
    2000-01-02    3
    2000-01-03    4

    False

    2000-01-02    1
    2000-01-02    2
    2000-01-02    3

    4
    2000-01-01    0
    2000-01-02    2
    2000-01-03    4

    2000-01-01    1
    2000-01-02    3
    2000-01-03    1
    [Finished in 1.3s]

    3、日期的范围、频率以及移动

    有时候需要用相对固定的频率对数据进行分析,比如每月、每天等。幸运的是,pandas有一整套标准时间序列频率以及用于重采样、频率推断、生成固定频率日期范围的工具。

    #定义列表
    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)]
    #print dates
    ts = Series(np.random.randn(6),index = dates)
    #print ts
    #下面进行重采样,得到具有固定时间频率(每天)的时间序列,当让这样的话就会产生缺失值
    print ts.resample('D')#-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    
    #定义列表
    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)]
    #print dates
    ts = Series(np.random.randn(6),index = dates)
    #print ts
    #下面进行重采样,得到具有固定时间频率(每天)的时间序列,当让这样的话就会产生缺失值
    print ts.resample('D') #频率的转换(或重采样)主题较大,后面再说
    >>>
    2011-01-02   -0.956627
    2011-01-03         NaN
    2011-01-04         NaN
    2011-01-05    0.130565
    2011-01-06         NaN
    2011-01-07    0.090270
    2011-01-08    0.753881
    2011-01-09         NaN
    2011-01-10   -0.733514
    2011-01-11         NaN
    2011-01-12   -0.200039
    Freq: D
    [Finished in 1.2s]
    • 生成日期范围
    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    
    #pandas.date_range会生成指定长度的DatetimeIndex
    index = pd.date_range('4/1/2015','6/1/2015')
    print index,'
    '
    #默认情况下,date_range产生按天计算的时间点,当然可以传入开始或结束日期,还得传入一个表示一段时间的数字
    print pd.date_range('1/1/2016',periods = 31),'
    '
    #开始和结束定义了日期索引的严格边界,如果你想要生成一个由每月最后一个工作日组成的日期索引,可以传入‘BM’(business end of month)
    #这样就只会包含时间间隔内(或者放好在时间边界上)符合频率要求的日期:
    print pd.date_range('12/18/2015','1/1/2016',freq = 'BM'),'
    '
    #date_range默认保留起始和结束时间戳信息
    print pd.date_range('5/2/2015 12:12:12',periods = 5)
    #有时,虽然起始和结束带有时间信息,但是可以用normalize = True把它们吧变为00:00:00
    print pd.date_range('5/2/2015 12:12:12',periods = 5,normalize = True)
    >>>
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2015-04-01 00:00:00, ..., 2015-06-01 00:00:00]
    Length: 62, Freq: D, Timezone: None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2016-01-01 00:00:00, ..., 2016-01-31 00:00:00]
    Length: 31, Freq: D, Timezone: None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2015-12-31 00:00:00]
    Length: 1, Freq: BM, Timezone: None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2015-05-02 12:12:12, ..., 2015-05-06 12:12:12]
    Length: 5, Freq: D, Timezone: None
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2015-05-02 00:00:00, ..., 2015-05-06 00:00:00]
    Length: 5, Freq: D, Timezone: None
    [Finished in 1.1s]

    • 频率和日期偏移量

    有些频率所描述的时间点并不是均匀分隔的。例如'M'和'BM'就取决于每月的天数,对于后者,还要考虑月末是不是周末,将这些成为锚点偏移量(anchored offset)。pandas还允许自定义一些日期逻辑,但是暂且不表。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute
    
    #pandas中的频率是由一个基础频率和一个乘数组成的。基础的频率由字符串表示,比如‘M’表示月,‘H’表示小时
    #对于每个基础频率,都有一个被称为日期偏移量(date offset)的对象与之对应。
    hour = Hour()
    print hour #感觉这个形式比较霸气
    #传入整数可以自定义偏移量倍数
    four_hours = Hour(4)
    print four_hours
    #一般而言,并不需要显示创建偏移量,只需创建时间序列时传入'H'或者'4h'即可
    print pd.date_range('1/1/2016','1/2/2016',freq = '4h'),'
    '
    #偏移量可以拼接
    print Hour(1) + Minute(30)
    #传入频率字符串('2h30min'),这种字符串可以被高效地解析为等效的表达式
    print pd.date_range('1/1/2016',periods = 10,freq = '1h30min'),'
    '
    #有些频率所描述的时间点并不是均匀分隔的。例如'M'和'BM'就取决于每月的天数,对于后者,还要考虑月末是不是周末,将这些成为锚点偏移量(anchored offset)
    #WOM(Week Of Month)日期是一个非常常用的频率,以WOM开头,能产生诸如“每月第三个星期五”之类的信息
    rng = pd.date_range('1/1/2016','9/1/2016',freq = 'WOM-3FRI')
    print rng
    >>>
    <1 Hour>
    <4 Hours>
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2016-01-01 00:00:00, ..., 2016-01-02 00:00:00]
    Length: 7, Freq: 4H, Timezone: None

    <90 Minutes>
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2016-01-01 00:00:00, ..., 2016-01-01 13:30:00]
    Length: 10, Freq: 90T, Timezone: None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2016-01-15 00:00:00, ..., 2016-08-19 00:00:00]
    Length: 8, Freq: WOM-3FRI, Timezone: None
    [Finished in 1.1s]

    下面是一些常用的基础频率,很多很详细。

    image
    image

    • 移动(超前和滞后)数据

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

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute
    
    ts = Series(np.random.randn(4),index = pd.date_range('1/1/2016',periods = 4,freq = 'M'))
    print ts
    print ts.shift(2)
    print ts.shift(-2),'
    '
    #可以看到,shift通常用于计算一个时间序列或多个时间序列(如DataFrame列)中的百分比变化。
    print ts / ts.shift(1) - 1
    #单纯的移位操作不会修改索引,所以部分数据会被丢弃,如果频率已知,则可以将其传给shift以实现对时间戳进行位移而不是只对数据移位
    print ts.shift(2,freq = 'M')  #时间戳移动,而数据不动
    #当然也可以自己定义移动的频率
    print ts.shift(3,freq = 'D'),'
    '  #时间的移动不是上下移动,而是将时间列的每个值进行移动
    print ts.shift(1,freq = '3D')
    print ts.shift(1,freq = '90T')
    >>>
    2016-01-31    0.721445
    2016-02-29   -0.568200
    2016-03-31   -0.945288
    2016-04-30    0.198176
    Freq: M
    2016-01-31         NaN
    2016-02-29         NaN
    2016-03-31    0.721445
    2016-04-30   -0.568200
    Freq: M
    2016-01-31   -0.945288
    2016-02-29    0.198176
    2016-03-31         NaN
    2016-04-30         NaN
    Freq: M

    2016-01-31         NaN
    2016-02-29   -1.787585
    2016-03-31    0.663653
    2016-04-30   -1.209646
    Freq: M
    2016-03-31    0.721445
    2016-04-30   -0.568200
    2016-05-31   -0.945288
    2016-06-30    0.198176
    Freq: M
    2016-02-03    0.721445
    2016-03-03   -0.568200
    2016-04-03   -0.945288
    2016-05-03    0.198176

    2016-02-03    0.721445
    2016-03-03   -0.568200
    2016-04-03   -0.945288
    2016-05-03    0.198176
    2016-01-31 01:30:00    0.721445
    2016-02-29 01:30:00   -0.568200
    2016-03-31 01:30:00   -0.945288
    2016-04-30 01:30:00    0.198176
    [Finished in 0.7s]

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

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

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
    
    now = datetime(2011,11,29)
    print type(now)
    print now + Day(3),'
    '
    #如果加的是锚点偏移量,第一次增量会将原日期向前滚动到符合频率规则的下一个日期
    #如果本来就是锚点,那么下一个就是下一个锚点
    print now + MonthEnd(),'
    '
    print now + MonthEnd(2),'
    '
    #通过锚点偏移量的rollforward和rollback方法,可显示地将日期向前或向后“滚动”
    offset = MonthEnd()
    print offset.rollforward(now),'
    '
    print offset.rollback(now),'
    '
    #日期偏移量还有一个巧妙的用法,即结合groupby使用这两个“滚动”方法
    ts = Series(np.random.randn(20),index = pd.date_range('1/15/2000',periods = 20,freq = '4d'))
    print ts,'
    '
    #注意下面的方式,很隐晦
    print ts.groupby(offset.rollforward).mean(),'
    '
    #当然,更简单快速的方式是使用resample
    print ts.resample('M',how = 'mean')
    >>>
    <type 'datetime.datetime'>
    2011-12-02 00:00:00
    2011-11-30 00:00:00 
    2011-12-31 00:00:00 
    2011-11-30 00:00:00 
    2011-10-31 00:00:00 
    2000-01-15   -1.234284
    2000-01-19   -1.078641
    2000-01-23   -0.727257
    2000-01-27   -0.943798
    2000-01-31    0.050586
    2000-02-04    0.019833
    2000-02-08   -1.407244
    2000-02-12   -0.446414
    2000-02-16   -0.521847
    2000-02-20    0.066200
    2000-02-24    1.604580
    2000-02-28   -0.714762
    2000-03-03    1.743459
    2000-03-07    1.675388
    2000-03-11    0.104701
    2000-03-15    0.124533
    2000-03-19   -1.113306
    2000-03-23   -1.442906
    2000-03-27   -0.489818
    2000-03-31    0.344161
    Freq: 4D
    2000-01-31   -0.786679
    2000-02-29   -0.199950
    2000-03-31    0.118276
     
    2000-01-31   -0.786679
    2000-02-29   -0.199950
    2000-03-31    0.118276
    Freq: M
    [Finished in 0.7s]

    4、时区处理

    时间序列最让人不爽的就是对时区的处理。很多人已经用协调世界时(UTC,格林尼治时间接替者,目前是国际标准)来处理时间序列。时区就是以UTC偏移量的形式表示的。

    Python中,时区信息来自第三方库pytz,它可以使Python可以使用Olson数据库。pandas包装了pytz功能。因此不用记忆API,只要记得时区名称即可。时区名可以在文档中找到。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
    import pytz
    
    print pytz.common_timezones[-5:]
    #要从pytz中获取时区对象,使用pytz.timezone即可
    tz = pytz.timezone('US/Eastern')
    print tz #这里的输出已经和课本上不一样,估计是进行了简化,使得更方便了
    >>>
    ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']
    US/Eastern
    [Finished in 0.7s]
    • 本地化和转换

    默认情况下,pandas中的序列是单纯的(naive[too young too simple!navie!])时区。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
    import pytz
    
    rng = pd.date_range('3/9/2012 9:30',periods = 6,freq = 'D')
    ts = Series(np.random.randn(len(rng)),index = rng)
    print ts,'
    '
    print ts.index.tz,'
    '  #默认的时区字段为None
    #在生成日期范围的时候还可以加上一个时区集
    print pd.date_range('3/9/2012',periods = 10,freq = 'D',tz = 'UTC'),'
    '
    #从单纯到本地化的转换是通过tz_localize方法处理的:
    ts_utc = ts.tz_localize('US/Pacific')  #转换为美国太平洋时间
    print ts_utc,'
    '
    print ts_utc.index,'
    '
    #一旦被转换为某个特定时期,就可以用tz_convert将其转换到其他时区了
    print ts_utc.tz_convert('US/Eastern'),'
    '
    #tz_localize和tz_convert是DatetimeIndex的实例方法,可以把一个DatetimeIndex转化为特定时区
    print ts.index.tz_localize('Asia/Shanghai')
    >>>
    2012-03-09 09:30:00    0.079530
    2012-03-10 09:30:00   -0.434450
    2012-03-11 09:30:00    0.360739
    2012-03-12 09:30:00    0.678065
    2012-03-13 09:30:00   -0.705374
    2012-03-14 09:30:00    0.684572
    Freq: D

    None

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2012-03-09 00:00:00, ..., 2012-03-18 00:00:00]
    Length: 10, Freq: D, Timezone: UTC

    2012-03-09 09:30:00-08:00    0.079530
    2012-03-10 09:30:00-08:00   -0.434450
    2012-03-11 09:30:00-07:00    0.360739
    2012-03-12 09:30:00-07:00    0.678065
    2012-03-13 09:30:00-07:00   -0.705374
    2012-03-14 09:30:00-07:00    0.684572
    Freq: D

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2012-03-09 09:30:00, ..., 2012-03-14 09:30:00]
    Length: 6, Freq: D, Timezone: US/Pacific

    2012-03-09 12:30:00-05:00    0.079530
    2012-03-10 12:30:00-05:00   -0.434450
    2012-03-11 12:30:00-04:00    0.360739
    2012-03-12 12:30:00-04:00    0.678065
    2012-03-13 12:30:00-04:00   -0.705374
    2012-03-14 12:30:00-04:00    0.684572
    Freq: D

    <class 'pandas.tseries.index.DatetimeIndex'>
    [2012-03-09 09:30:00, ..., 2012-03-14 09:30:00]
    Length: 6, Freq: D, Timezone: Asia/Shanghai
    [Finished in 0.6s]

    • 操作时区意识型(time zone-aware)Timestamp对象

    跟时间序列和日期序列差不多,Timestamp对象也能被从单纯型(navie)本地化为time zone-aware,并从一个时区转换为另一个时区。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
    import pytz
    
    stamp = pd.Timestamp('2011-03-12 04:00')
    print type(stamp),'
    '
    stamp_utc = stamp.tz_localize('UTC')
    print stamp_utc,'
    '
    print stamp_utc.tz_convert('US/Eastern'),'
    '
    stamp_moscow = pd.Timestamp('2011-03-12 04:00',tz = 'Europe/Moscow')
    print stamp_moscow
    #时区意识型Timestamp对象在内部保存了一个UTC时间戳值(自1970年1月1日起的纳秒数),这个UTC值在时区转换过程中是不会变化的
    print stamp_utc.value
    print stamp_utc.tz_convert('US/Eastern').value,'
    '
    #当使用pandas的DataOffset对象执行运算时,会自动关注“夏时令”…………
    >>>

    <class 'pandas.lib.Timestamp'>

    2011-03-12 04:00:00+00:00

    2011-03-11 23:00:00-05:00

    2011-03-12 04:00:00+03:00
    1299902400000000000
    1299902400000000000
    [Finished in 0.7s]

    • 不同时区之间的运算

    如果时间时间时区不同,那么结果就会是UTC时间,由于时间戳其实是以UTC储存的,索引计算很方便。

    #-*- coding:utf-8 -*-
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import datetime as dt
    from pandas import Series,DataFrame
    from datetime import datetime
    from dateutil.parser import parse
    import time
    from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
    import pytz
    
    rng = pd.date_range('3/7/2012',periods = 10,freq = 'B')
    ts = Series(np.random.randn(len(rng)),index = rng)
    print ts
    ts1 = ts[:7].tz_localize('Europe/London')
    #注意naive是不能直接转换为时区的,必须先转换为localize再进行转换
    ts2 = ts1[2:].tz_convert('Europe/Moscow')
    result = ts1 + ts2
    #转换为UTC
    print result.index
    >>>
    2012-03-07   -0.591417
    2012-03-08    1.009651
    2012-03-09   -1.922004
    2012-03-12    0.246206
    2012-03-13    0.033430
    2012-03-14    0.614911
    2012-03-15    1.944014
    2012-03-16   -2.349846
    2012-03-19    0.425925
    2012-03-20    1.941166
    Freq: B
    <class 'pandas.tseries.index.DatetimeIndex'>
    [2012-03-07 00:00:00, ..., 2012-03-15 00:00:00]
    Length: 7, Freq: B, Timezone: UTC
    [Finished in 0.7s]
  • 相关阅读:
    分布式事务的四种解决方案
    uber-go/guide 的中文翻译
    域名解析-CNAME
    Nginx节点存活状态检查
    Laravel核心解读--中间件(Middleware)
    Mac dyld: Library not loaded: /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib
    前缀树算法实现路由匹配原理解析
    原创-实用salt部署文档(持续更新)
    线上案例-调参-设置滑动窗口提高视频云播放性能
    NGINX日志割切
  • 原文地址:https://www.cnblogs.com/batteryhp/p/5055149.html
Copyright © 2011-2022 走看看