《利用python进行数据分析》读书笔记--第十章 时间序列(一)
2015-12-17 19:57
525 查看
时间序列是很重要的。时间序列(timeseries)数据是一种重要的结构化数据格式。时间序列的意义取决于具体的应用场景,主要有以下几种:
时间戳(timestamp),特定的时刻
固定时期(period),如2015年全年
时间间隔(interval),由起始和结束时间戳表示。就是说,时期可以是时间间隔的特例。
实验或过程时间,每个时间点都是相对于特定起始时间的一个度量。例如,自从放入烤箱时起,每秒钟饼干的直径。
pandas提供了一组标准的时间序列处理工具和数据算法。因此可以高效处理非常大的时间序列,轻松进行切片/切块、聚合、对定期/不定期的时间序列进行重采样等。也就是说,大部分都对金融和经济数据尤为有用,当然也可以用它们来分析服务器日志数据。
1、日期和时间数据类型及工具
Python标准库中包含用于日期(date)、时间(time)数据的数据类型。而且还有日历方面的功能。主要会用到datetime、time、calendar模块。
926days,15:45:00
926days,15:45:00
926
56700
2011-01-0810:10:20.005001
[Finishedin0.6s]
datetime中的数据类型有:
字符串和datetime的相互转换
利用str或者strftime方法(传入一个格式化字符串),datetime对象和pandas中timestamp对象就可以转换为字符串:
&Y-01-03
2011-01-03
2011-01-0300:00:00
[datetime.datetime(2011,7,6,0,0),datetime.datetime(2011,8,6,0,0)]
2011-01-0300:00:00
2011-01-0300:00:00
1997-01-3122:45:00
2011-12-0600:00:00
<class'pandas.tseries.index.DatetimeIndex'>
[2011-07-0600:00:00,2011-08-0600:00:00]
Length:2,Freq:None,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2011-07-0600:00:00,...,NaT]
Length:3,Freq:None,Timezone:None
0001-255-25500:00:00
[FalseFalseTrue]
2042-12-1700:00:00
[Finishedin0.6s]
下面是日期的一些格式:
datetime对象还有一些特定于当前环境(位于不同国家或使用不同语言系统)的格式化选项。估计用的少?
2、时间序列基础
pandas最基本的时间序列类型就是以时间戳(通常用Python字符串或datatime对象表示)为索引的Series。
<class'pandas.core.series.TimeSeries'>
<class'pandas.tseries.index.DatetimeIndex'>
[2011-01-0200:00:00,...,2011-01-1200:00:00]
Length:6,Freq:None,Timezone:None
2011-01-02-2.534216
2011-01-05NaN
2011-01-071.569701
2011-01-08NaN
2011-01-101.277326
2011-01-12NaN
datetime64[ns]
2011-01-0200:00:00
[Finishedin0.7s]
索引、选取、子集构造
TimeSeries是Series的一个子类,所以在索引以及数据选取方面跟Series一样。
2000-01-01-1.646726
2000-01-021.531423
2000-01-030.251503
2000-01-040.938951
2000-01-050.647967
2000-01-060.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-140.826756
2000-01-15-0.279239
...
2002-09-12-0.097634
2002-09-132.222456
2002-09-140.042517
2002-09-150.266974
2002-09-160.038329
2002-09-17-1.524744
2002-09-181.476706
2002-09-190.108336
2002-09-200.016759
2002-09-21-0.072676
2002-09-22-0.960545
2002-09-230.520699
2002-09-24-1.188202
2002-09-251.669166
2002-09-26-0.043997
Freq:D,Length:1000
2001-01-01-0.168866
2001-01-02-0.273377
2001-01-030.094258
2001-01-04-0.979666
2001-01-050.947706
2001-01-060.666709
2001-01-070.451145
2001-01-08-0.301992
2001-01-090.272385
2001-01-10-0.255775
2001-01-11-0.321916
2001-01-121.894119
2001-01-130.582272
2001-01-14-1.102707
2001-01-150.019423
...
2001-12-17-0.243563
2001-12-181.757564
2001-12-19-0.145106
2001-12-20-0.579629
2001-12-21-0.431069
2001-12-220.480805
2001-12-23-0.651905
2001-12-240.702051
2001-12-25-0.384549
2001-12-26-1.077664
2001-12-27-0.972768
2001-12-281.001220
2001-12-290.418016
2001-12-300.567361
2001-12-31-0.811610
Freq:D,Length:365
2001-05-01-0.071521
2001-05-020.402344
2001-05-03-0.568929
2001-05-040.227754
2001-05-050.194631
2001-05-06-0.407669
2001-05-07-1.407606
2001-05-08-0.804147
2001-05-090.050445
2001-05-10-0.604275
2001-05-110.270760
2001-05-120.000804
2001-05-13-0.348938
2001-05-14-1.626158
2001-05-150.084629
2001-05-16-0.376655
2001-05-171.913789
2001-05-182.497594
2001-05-190.818446
2001-05-200.067115
2001-05-21-0.993827
2001-05-220.940616
2001-05-23-0.951763
2001-05-24-0.806228
2001-05-250.441872
2001-05-260.067010
2001-05-27-1.903360
2001-05-28-0.400990
2001-05-290.257146
2001-05-300.785503
2001-05-31-1.129024
Freq:D
2011-01-070.075132
2011-01-08-0.985630
2011-01-10-0.622707
2011-01-12-1.356095
2011-01-070.075132
2011-01-08-0.985630
2011-01-10-0.622707
Thisistimeandlocaltime
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)
ThuDec1722:20:542015
2015-12-1722:20:54
over
2011-01-02-0.772858
2011-01-05-0.908074
2011-01-070.075132
2011-01-08-0.985630
ColoradoTexasNewYorkOhio
2001-05-020.3033410.026978-0.0363890.463034
2001-05-09-1.573227-0.283074-0.882382-1.207936
2001-05-161.520804-0.8382970.7256901.240092
2001-05-231.297194-0.516198-0.022075-0.876630
2001-05-30-1.6294261.022547-0.131823-0.621269
[Finishedin0.7s]
带有重复索引的时间序列
False
2000-01-021
2000-01-022
2000-01-023
4
2000-01-010
2000-01-022
2000-01-034
2000-01-011
2000-01-023
2000-01-031
[Finishedin1.3s]
3、日期的范围、频率以及移动
有时候需要用相对固定的频率对数据进行分析,比如每月、每天等。幸运的是,pandas有一整套标准时间序列频率以及用于重采样、频率推断、生成固定频率日期范围的工具。
生成日期范围
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-0100:00:00,...,2016-01-3100:00:00]
Length:31,Freq:D,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-12-3100:00:00]
Length:1,Freq:BM,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-05-0212:12:12,...,2015-05-0612:12:12]
Length:5,Freq:D,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-05-0200:00:00,...,2015-05-0600:00:00]
Length:5,Freq:D,Timezone:None
[Finishedin1.1s]
频率和日期偏移量
有些频率所描述的时间点并不是均匀分隔的。例如'M'和'BM'就取决于每月的天数,对于后者,还要考虑月末是不是周末,将这些成为锚点偏移量(anchoredoffset)。pandas还允许自定义一些日期逻辑,但是暂且不表。
<90Minutes>
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-0100:00:00,...,2016-01-0113:30:00]
Length:10,Freq:90T,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-1500:00:00,...,2016-08-1900:00:00]
Length:8,Freq:WOM-3FRI,Timezone:None
[Finishedin1.1s]
下面是一些常用的基础频率,很多很详细。
移动(超前和滞后)数据
移动(shifting)指的是沿着时间轴将数据前移或后移。Series和DataFrame都有一个shift方法用于执行单纯的前移或后移操作,保持索引不变。
2016-01-31NaN
2016-02-29-1.787585
2016-03-310.663653
2016-04-30-1.209646
Freq:M
2016-03-310.721445
2016-04-30-0.568200
2016-05-31-0.945288
2016-06-300.198176
Freq:M
2016-02-030.721445
2016-03-03-0.568200
2016-04-03-0.945288
2016-05-030.198176
2016-02-030.721445
2016-03-03-0.568200
2016-04-03-0.945288
2016-05-030.198176
2016-01-3101:30:000.721445
2016-02-2901:30:00-0.568200
2016-03-3101:30:00-0.945288
2016-04-3001:30:000.198176
[Finishedin0.7s]
通过偏移量对日期进行位移
pandas的日期偏移量还可以用在datetime或Timestemp对象上。
4、时区处理
时间序列最让人不爽的就是对时区的处理。很多人已经用协调世界时(UTC,格林尼治时间接替者,目前是国际标准)来处理时间序列。时区就是以UTC偏移量的形式表示的。
Python中,时区信息来自第三方库pytz,它可以使Python可以使用Olson数据库。pandas包装了pytz功能。因此不用记忆API,只要记得时区名称即可。时区名可以在文档中找到。
本地化和转换
默认情况下,pandas中的序列是单纯的(naive[tooyoungtoosimple!navie!])时区。
None
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0900:00:00,...,2012-03-1800:00:00]
Length:10,Freq:D,Timezone:UTC
2012-03-0909:30:00-08:000.079530
2012-03-1009:30:00-08:00-0.434450
2012-03-1109:30:00-07:000.360739
2012-03-1209:30:00-07:000.678065
2012-03-1309:30:00-07:00-0.705374
2012-03-1409:30:00-07:000.684572
Freq:D
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0909:30:00,...,2012-03-1409:30:00]
Length:6,Freq:D,Timezone:US/Pacific
2012-03-0912:30:00-05:000.079530
2012-03-1012:30:00-05:00-0.434450
2012-03-1112:30:00-04:000.360739
2012-03-1212:30:00-04:000.678065
2012-03-1312:30:00-04:00-0.705374
2012-03-1412:30:00-04:000.684572
Freq:D
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0909:30:00,...,2012-03-1409:30:00]
Length:6,Freq:D,Timezone:Asia/Shanghai
[Finishedin0.6s]
操作时区意识型(timezone-aware)Timestamp对象
跟时间序列和日期序列差不多,Timestamp对象也能被从单纯型(navie)本地化为timezone-aware,并从一个时区转换为另一个时区。
<class'pandas.lib.Timestamp'>
2011-03-1204:00:00+00:00
2011-03-1123:00:00-05:00
2011-03-1204:00:00+03:00
1299902400000000000
1299902400000000000
[Finishedin0.7s]
不同时区之间的运算
如果时间时间时区不同,那么结果就会是UTC时间,由于时间戳其实是以UTC储存的,索引计算很方便。
时间戳(timestamp),特定的时刻
固定时期(period),如2015年全年
时间间隔(interval),由起始和结束时间戳表示。就是说,时期可以是时间间隔的特例。
实验或过程时间,每个时间点都是相对于特定起始时间的一个度量。例如,自从放入烤箱时起,每秒钟饼干的直径。
pandas提供了一组标准的时间序列处理工具和数据算法。因此可以高效处理非常大的时间序列,轻松进行切片/切块、聚合、对定期/不定期的时间序列进行重采样等。也就是说,大部分都对金融和经济数据尤为有用,当然也可以用它们来分析服务器日志数据。
1、日期和时间数据类型及工具
Python标准库中包含用于日期(date)、时间(time)数据的数据类型。而且还有日历方面的功能。主要会用到datetime、time、calendar模块。
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt fromdatetimeimportdatetime now=datetime.now() #datetime以毫秒形式储存时间 printnow,now.year,now.month,now.day,now.microsecond,'\n' #printdatetime(2015,12,17,20,00,01,555555)#设置一个时间 #datetime.timedelta表示两个datetime对象之间的时间差 #换句话说,datetime格式可以相相减 delta=datetime(2011,1,7)-datetime(2008,6,24,8,15) printdelta #把注意下面是daysAndseconds printdt.timedelta(926,56700) printdelta.days printdelta.seconds #下面是错误的 #printdelta.minutes start=datetime(2011,1,7) #参数分别为days,seconds,microseconds(微秒),milliseconds(毫秒),minutes,hours,weeks,除了微秒小数自动四舍五入之外,其他的都能自动转换为其他度量 printstart+dt.timedelta(1,20,0.5,5,10,10,0)
>>>
2015-12-1720:24:21.82900020151217829000
926days,15:45:00
926days,15:45:00
926
56700
2011-01-0810:10:20.005001
[Finishedin0.6s]
datetime中的数据类型有:
字符串和datetime的相互转换
利用str或者strftime方法(传入一个格式化字符串),datetime对象和pandas中timestamp对象就可以转换为字符串:
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt fromdatetimeimportdatetime fromdateutil.parserimportparse stamp=datetime(2011,1,3) printstr(stamp),'\n' #看一下下面的字符,很有意思,自己不小心打错了,运行仍然是正确的 printstamp.strftime('&Y-%m-%d') printstamp.strftime('%Y-%m-%d'),'\n' value='2011-01-03' printdatetime.strptime(value,'%Y-%m-%d')#注意这是datetime函数的函数,不是模块的函数 datestrs=['7/6/2011','8/6/2011'] print[datetime.strptime(x,'%m/%d/%Y')forxindatestrs] #上面将字符串转化为最常用的格式,但是米次都自己写出来有点麻烦,可以用dateutil这个第三方包中的parser.parse方法 printparse('2011-01-03') #dateutil可以几乎解析所有能够理解的日期表示形式(很可惜中文不行) #这个应该是很实用的 printparse('2011/01/03') printparse('Jan31,199710:45PM') #国际通用格式中,日出现在月的前面,传入dayfirst=True即可 printparse('6/12/2011',dayfirst=True),'\n' #pandas通常是用于处理成组日期的,不管这些日期是DataFrame的行还是列。 printpd.to_datetime(datestrs),'\n' idx=pd.to_datetime(datestrs+[None]) printidx printidx[2]#这里应该是NaT(NotaTime) printpd.isnull(idx) #parse是一个不完美的工具,比如下面 printparse('42')
>>>
2011-01-0300:00:00
&Y-01-03
2011-01-03
2011-01-0300:00:00
[datetime.datetime(2011,7,6,0,0),datetime.datetime(2011,8,6,0,0)]
2011-01-0300:00:00
2011-01-0300:00:00
1997-01-3122:45:00
2011-12-0600:00:00
<class'pandas.tseries.index.DatetimeIndex'>
[2011-07-0600:00:00,2011-08-0600:00:00]
Length:2,Freq:None,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2011-07-0600:00:00,...,NaT]
Length:3,Freq:None,Timezone:None
0001-255-25500:00:00
[FalseFalseTrue]
2042-12-1700:00:00
[Finishedin0.6s]
下面是日期的一些格式:
datetime对象还有一些特定于当前环境(位于不同国家或使用不同语言系统)的格式化选项。估计用的少?
2、时间序列基础
pandas最基本的时间序列类型就是以时间戳(通常用Python字符串或datatime对象表示)为索引的Series。
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse 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)] #printdates ts=Series(np.random.randn(6),index=dates) printts,'\n' #这些datetime对象实际上是被放在一个DatetimeIndex中的。现在,变量ts就成为了TimeSeries了。 printtype(ts) printts.index,'\n' #没必要显示使用TimeSeries的构造函数。当创建一个带有DatetimeIndex的Series时,pandas就会知道该对象是一个时间序列 printts+ts[::2] #pandas用NumPy的datetime64数据类型以纳秒形式存储时间戳: printts.index.dtype #DatetimeIndex中的各个标量值是pandas的Timestamp stamp=ts.index[0] printstamp
#只要有需要,TimeStamp可以随时自动转换为datetime对象。此外,还可以存储频率信息,且知道如何执行时区转换以及其他操作
>>>
2011-01-02-1.267108 2011-01-05-0.450098 2011-01-070.784850 2011-01-080.024722 2011-01-100.638663 2011-01-120.246022
<class'pandas.core.series.TimeSeries'>
<class'pandas.tseries.index.DatetimeIndex'>
[2011-01-0200:00:00,...,2011-01-1200:00:00]
Length:6,Freq:None,Timezone:None
2011-01-02-2.534216
2011-01-05NaN
2011-01-071.569701
2011-01-08NaN
2011-01-101.277326
2011-01-12NaN
datetime64[ns]
2011-01-0200:00:00
[Finishedin0.7s]
索引、选取、子集构造
TimeSeries是Series的一个子类,所以在索引以及数据选取方面跟Series一样。
stamp=ts.index[2] printts[stamp],'\n' #还有更方便的用法,传入可以被解释为日期的字符串 printts['1/10/2011'] printts['20110110'],'\n' #对于较长的时间序列,只需传入“年”或“年月”即可轻松选取数据切片 long_ts=Series(np.random.randn(1000), index=pd.date_range('1/1/2000',periods=1000)) #-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime printlong_ts,'\n' printlong_ts['2001'],'\n' printlong_ts['2001-05'],'\n' #通过日期进行切片的方式只对规则Series有效: printts[datetime(2011,1,7):],'\n' #由于大部分时间序列数据都是按照时间先后排序的,因此你可以用不存在于该时间序列中的时间戳对其进行切片(即范围查询) #就是说,本来1/6/2011不在index中,却可以用来当作范围 printts['1/6/2011':'1/11/2011'],'\n'#这里可以传入字符串日期、datetime或者Timestamp print'Thisistimeandlocaltime' print"time.time():%f"%time.time() printtime.localtime(time.time()) printtime.asctime(time.localtime(time.time())) ltime=time.localtime(int(time.time()))#time.time()不能直接运用strftime进行转换 printtime.strftime("%Y-%m-%d%H:%M:%S",ltime) #timeasctime()函数接受时间元组并返回一个可读的形式为"TueDec1118:07:142008" print'over','\n' #还有一个等价方法截取两个日期之间的TimeSeries. printts.truncate(after='1/9/2011'),'\n' #上面这些对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','NewYork','Ohio']) printlong_df.ix['2001-05']
>>>
0.0751316698811
-0.622706612554 -0.622706612554
2000-01-01-1.646726
2000-01-021.531423
2000-01-030.251503
2000-01-040.938951
2000-01-050.647967
2000-01-060.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-140.826756
2000-01-15-0.279239
...
2002-09-12-0.097634
2002-09-132.222456
2002-09-140.042517
2002-09-150.266974
2002-09-160.038329
2002-09-17-1.524744
2002-09-181.476706
2002-09-190.108336
2002-09-200.016759
2002-09-21-0.072676
2002-09-22-0.960545
2002-09-230.520699
2002-09-24-1.188202
2002-09-251.669166
2002-09-26-0.043997
Freq:D,Length:1000
2001-01-01-0.168866
2001-01-02-0.273377
2001-01-030.094258
2001-01-04-0.979666
2001-01-050.947706
2001-01-060.666709
2001-01-070.451145
2001-01-08-0.301992
2001-01-090.272385
2001-01-10-0.255775
2001-01-11-0.321916
2001-01-121.894119
2001-01-130.582272
2001-01-14-1.102707
2001-01-150.019423
...
2001-12-17-0.243563
2001-12-181.757564
2001-12-19-0.145106
2001-12-20-0.579629
2001-12-21-0.431069
2001-12-220.480805
2001-12-23-0.651905
2001-12-240.702051
2001-12-25-0.384549
2001-12-26-1.077664
2001-12-27-0.972768
2001-12-281.001220
2001-12-290.418016
2001-12-300.567361
2001-12-31-0.811610
Freq:D,Length:365
2001-05-01-0.071521
2001-05-020.402344
2001-05-03-0.568929
2001-05-040.227754
2001-05-050.194631
2001-05-06-0.407669
2001-05-07-1.407606
2001-05-08-0.804147
2001-05-090.050445
2001-05-10-0.604275
2001-05-110.270760
2001-05-120.000804
2001-05-13-0.348938
2001-05-14-1.626158
2001-05-150.084629
2001-05-16-0.376655
2001-05-171.913789
2001-05-182.497594
2001-05-190.818446
2001-05-200.067115
2001-05-21-0.993827
2001-05-220.940616
2001-05-23-0.951763
2001-05-24-0.806228
2001-05-250.441872
2001-05-260.067010
2001-05-27-1.903360
2001-05-28-0.400990
2001-05-290.257146
2001-05-300.785503
2001-05-31-1.129024
Freq:D
2011-01-070.075132
2011-01-08-0.985630
2011-01-10-0.622707
2011-01-12-1.356095
2011-01-070.075132
2011-01-08-0.985630
2011-01-10-0.622707
Thisistimeandlocaltime
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)
ThuDec1722:20:542015
2015-12-1722:20:54
over
2011-01-02-0.772858
2011-01-05-0.908074
2011-01-070.075132
2011-01-08-0.985630
ColoradoTexasNewYorkOhio
2001-05-020.3033410.026978-0.0363890.463034
2001-05-09-1.573227-0.283074-0.882382-1.207936
2001-05-161.520804-0.8382970.7256901.240092
2001-05-231.297194-0.516198-0.022075-0.876630
2001-05-30-1.6294261.022547-0.131823-0.621269
[Finishedin0.7s]
带有重复索引的时间序列
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime #注意下面的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) printdup_ts,'\n' #通过检唯一的测is_unique属性,我们就可以知道它不是 printdup_ts.index.is_unique,'\n' #此时若索引,得到的可能是标量值,也可能是切片 printdup_ts['1/2/2000'],'\n' printdup_ts['1/3/2000'] #假如你想要对具有非 #唯一时间戳的数据进行聚合一个办法是使用groupby,并传入level=0 grouped=dup_ts.groupby(level=0) printgrouped.mean(),'\n' printgrouped.count()
>>>
2000-01-010 2000-01-021 2000-01-022 2000-01-023 2000-01-034
False
2000-01-021
2000-01-022
2000-01-023
4
2000-01-010
2000-01-022
2000-01-034
2000-01-011
2000-01-023
2000-01-031
[Finishedin1.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)] #printdates ts=Series(np.random.randn(6),index=dates) #printts #下面进行重采样,得到具有固定时间频率(每天)的时间序列,当让这样的话就会产生缺失值 printts.resample('D')#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime #定义列表 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)] #printdates ts=Series(np.random.randn(6),index=dates) #printts #下面进行重采样,得到具有固定时间频率(每天)的时间序列,当让这样的话就会产生缺失值 printts.resample('D')#频率的转换(或重采样)主题较大,后面再说
>>>
2011-01-02-0.956627 2011-01-03NaN 2011-01-04NaN 2011-01-050.130565 2011-01-06NaN 2011-01-070.090270 2011-01-080.753881 2011-01-09NaN 2011-01-10-0.733514 2011-01-11NaN 2011-01-12-0.200039 Freq:D [Finishedin1.2s]
生成日期范围
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime #pandas.date_range会生成指定长度的DatetimeIndex index=pd.date_range('4/1/2015','6/1/2015') printindex,'\n' #默认情况下,date_range产生按天计算的时间点,当然可以传入开始或结束日期,还得传入一个表示一段时间的数字 printpd.date_range('1/1/2016',periods=31),'\n' #开始和结束定义了日期索引的严格边界,如果你想要生成一个由每月最后一个工作日组成的日期索引,可以传入‘BM’(businessendofmonth) #这样就只会包含时间间隔内(或者放好在时间边界上)符合频率要求的日期: printpd.date_range('12/18/2015','1/1/2016',freq='BM'),'\n' #date_range默认保留起始和结束时间戳信息 printpd.date_range('5/2/201512:12:12',periods=5) #有时,虽然起始和结束带有时间信息,但是可以用normalize=True把它们吧变为00:00:00 printpd.date_range('5/2/201512:12:12',periods=5,normalize=True)
>>>
<class'pandas.tseries.index.DatetimeIndex'> [2015-04-0100:00:00,...,2015-06-0100:00:00] Length:62,Freq:D,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-0100:00:00,...,2016-01-3100:00:00]
Length:31,Freq:D,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-12-3100:00:00]
Length:1,Freq:BM,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-05-0212:12:12,...,2015-05-0612:12:12]
Length:5,Freq:D,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2015-05-0200:00:00,...,2015-05-0600:00:00]
Length:5,Freq:D,Timezone:None
[Finishedin1.1s]
频率和日期偏移量
有些频率所描述的时间点并不是均匀分隔的。例如'M'和'BM'就取决于每月的天数,对于后者,还要考虑月末是不是周末,将这些成为锚点偏移量(anchoredoffset)。pandas还允许自定义一些日期逻辑,但是暂且不表。
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime frompandas.tseries.offsetsimportHour,Minute #pandas中的频率是由一个基础频率和一个乘数组成的。基础的频率由字符串表示,比如‘M’表示月,‘H’表示小时 #对于每个基础频率,都有一个被称为日期偏移量(dateoffset)的对象与之对应。 hour=Hour() printhour#感觉这个形式比较霸气 #传入整数可以自定义偏移量倍数 four_hours=Hour(4) printfour_hours #一般而言,并不需要显示创建偏移量,只需创建时间序列时传入'H'或者'4h'即可 printpd.date_range('1/1/2016','1/2/2016',freq='4h'),'\n' #偏移量可以拼接 printHour(1)+Minute(30) #传入频率字符串('2h30min'),这种字符串可以被高效地解析为等效的表达式 printpd.date_range('1/1/2016',periods=10,freq='1h30min'),'\n' #有些频率所描述的时间点并不是均匀分隔的。例如'M'和'BM'就取决于每月的天数,对于后者,还要考虑月末是不是周末,将这些成为锚点偏移量(anchoredoffset) #WOM(WeekOfMonth)日期是一个非常常用的频率,以WOM开头,能产生诸如“每月第三个星期五”之类的信息 rng=pd.date_range('1/1/2016','9/1/2016',freq='WOM-3FRI') printrng
>>>
<1Hour> <4Hours> <class'pandas.tseries.index.DatetimeIndex'> [2016-01-0100:00:00,...,2016-01-0200:00:00] Length:7,Freq:4H,Timezone:None
<90Minutes>
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-0100:00:00,...,2016-01-0113:30:00]
Length:10,Freq:90T,Timezone:None
<class'pandas.tseries.index.DatetimeIndex'>
[2016-01-1500:00:00,...,2016-08-1900:00:00]
Length:8,Freq:WOM-3FRI,Timezone:None
[Finishedin1.1s]
下面是一些常用的基础频率,很多很详细。
移动(超前和滞后)数据
移动(shifting)指的是沿着时间轴将数据前移或后移。Series和DataFrame都有一个shift方法用于执行单纯的前移或后移操作,保持索引不变。
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime frompandas.tseries.offsetsimportHour,Minute ts=Series(np.random.randn(4),index=pd.date_range('1/1/2016',periods=4,freq='M')) printts printts.shift(2) printts.shift(-2),'\n' #可以看到,shift通常用于计算一个时间序列或多个时间序列(如DataFrame列)中的百分比变化。 printts/ts.shift(1)-1 #单纯的移位操作不会修改索引,所以部分数据会被丢弃,如果频率已知,则可以将其传给shift以实现对时间戳进行位移而不是只对数据移位 printts.shift(2,freq='M')#时间戳移动,而数据不动 #当然也可以自己定义移动的频率 printts.shift(3,freq='D'),'\n'#时间的移动不是上下移动,而是将时间列的每个值进行移动 printts.shift(1,freq='3D') printts.shift(1,freq='90T')
>>>
2016-01-310.721445 2016-02-29-0.568200 2016-03-31-0.945288 2016-04-300.198176 Freq:M 2016-01-31NaN 2016-02-29NaN 2016-03-310.721445 2016-04-30-0.568200 Freq:M 2016-01-31-0.945288 2016-02-290.198176 2016-03-31NaN 2016-04-30NaN Freq:M
2016-01-31NaN
2016-02-29-1.787585
2016-03-310.663653
2016-04-30-1.209646
Freq:M
2016-03-310.721445
2016-04-30-0.568200
2016-05-31-0.945288
2016-06-300.198176
Freq:M
2016-02-030.721445
2016-03-03-0.568200
2016-04-03-0.945288
2016-05-030.198176
2016-02-030.721445
2016-03-03-0.568200
2016-04-03-0.945288
2016-05-030.198176
2016-01-3101:30:000.721445
2016-02-2901:30:00-0.568200
2016-03-3101:30:00-0.945288
2016-04-3001:30:000.198176
[Finishedin0.7s]
通过偏移量对日期进行位移
pandas的日期偏移量还可以用在datetime或Timestemp对象上。
#-*-coding:utf-8-*- importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importdatetimeasdt frompandasimportSeries,DataFrame fromdatetimeimportdatetime fromdateutil.parserimportparse importtime frompandas.tseries.offsetsimportHour,Minute,Day,MonthEnd now=datetime(2011,11,29) printtype(now) printnow+Day(3),'\n' #如果加的是锚点偏移量,第一次增量会将原日期向前滚动到符合频率规则的下一个日期 #如果本来就是锚点,那么下一个就是下一个锚点 printnow+MonthEnd(),'\n' printnow+MonthEnd(2),'\n' #通过锚点偏移量的rollforward和rollback方法,可显示地将日期向前或向后“滚动” offset=MonthEnd() printoffset.rollforward(now),'\n' printoffset.rollback(now),'\n' #日期偏移量还有一个巧妙的用法,即结合groupby使用这两个“滚动”方法 ts=Series(np.random.randn(20),index=pd.date_range('1/15/2000',periods=20,freq='4d')) printts,'\n' #注意下面的方式,很隐晦 printts.groupby(offset.rollforward).mean(),'\n' #当然,更简单快速的方式是使用resample printts.resample('M',how='mean')
>>>
<type'datetime.datetime'> 2011-12-0200:00:00
2011-11-3000:00:00
2011-12-3100:00:00
2011-11-3000:00:00
2011-10-3100:00:00
2000-01-15-1.234284 2000-01-19-1.078641 2000-01-23-0.727257 2000-01-27-0.943798 2000-01-310.050586 2000-02-040.019833 2000-02-08-1.407244 2000-02-12-0.446414 2000-02-16-0.521847 2000-02-200.066200 2000-02-241.604580 2000-02-28-0.714762 2000-03-031.743459 2000-03-071.675388 2000-03-110.104701 2000-03-150.124533 2000-03-19-1.113306 2000-03-23-1.442906 2000-03-27-0.489818 2000-03-310.344161 Freq:4D
2000-01-31-0.786679 2000-02-29-0.199950 2000-03-310.118276
2000-01-31-0.786679
2000-02-29-0.199950
2000-03-310.118276
Freq:M
[Finishedin0.7s]
4、时区处理
时间序列最让人不爽的就是对时区的处理。很多人已经用协调世界时(UTC,格林尼治时间接替者,目前是国际标准)来处理时间序列。时区就是以UTC偏移量的形式表示的。
Python中,时区信息来自第三方库pytz,它可以使Python可以使用Olson数据库。pandas包装了pytz功能。因此不用记忆API,只要记得时区名称即可。时区名可以在文档中找到。
#-*-coding:utf-8-*-
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
importdatetimeasdt
frompandasimportSeries,DataFrame
fromdatetimeimportdatetime
fromdateutil.parserimportparse
importtime
frompandas.tseries.offsetsimportHour,Minute,Day,MonthEnd
importpytz
printpytz.common_timezones[-5:]
#要从pytz中获取时区对象,使用pytz.timezone即可
tz=pytz.timezone('US/Eastern')
printtz#这里的输出已经和课本上不一样,估计是进行了简化,使得更方便了
>>>
['US/Eastern','US/Hawaii','US/Mountain','US/Pacific','UTC']
US/Eastern
[Finishedin0.7s]
本地化和转换
默认情况下,pandas中的序列是单纯的(naive[tooyoungtoosimple!navie!])时区。
#-*-coding:utf-8-*-
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
importdatetimeasdt
frompandasimportSeries,DataFrame
fromdatetimeimportdatetime
fromdateutil.parserimportparse
importtime
frompandas.tseries.offsetsimportHour,Minute,Day,MonthEnd
importpytz
rng=pd.date_range('3/9/20129:30',periods=6,freq='D')
ts=Series(np.random.randn(len(rng)),index=rng)
printts,'\n'
printts.index.tz,'\n'#默认的时区字段为None
#在生成日期范围的时候还可以加上一个时区集
printpd.date_range('3/9/2012',periods=10,freq='D',tz='UTC'),'\n'
#从单纯到本地化的转换是通过tz_localize方法处理的:
ts_utc=ts.tz_localize('US/Pacific')#转换为美国太平洋时间
printts_utc,'\n'
printts_utc.index,'\n'
#一旦被转换为某个特定时期,就可以用tz_convert将其转换到其他时区了
printts_utc.tz_convert('US/Eastern'),'\n'
#tz_localize和tz_convert是DatetimeIndex的实例方法,可以把一个DatetimeIndex转化为特定时区
printts.index.tz_localize('Asia/Shanghai')
>>>
2012-03-0909:30:000.079530
2012-03-1009:30:00-0.434450
2012-03-1109:30:000.360739
2012-03-1209:30:000.678065
2012-03-1309:30:00-0.705374
2012-03-1409:30:000.684572
Freq:D
None
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0900:00:00,...,2012-03-1800:00:00]
Length:10,Freq:D,Timezone:UTC
2012-03-0909:30:00-08:000.079530
2012-03-1009:30:00-08:00-0.434450
2012-03-1109:30:00-07:000.360739
2012-03-1209:30:00-07:000.678065
2012-03-1309:30:00-07:00-0.705374
2012-03-1409:30:00-07:000.684572
Freq:D
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0909:30:00,...,2012-03-1409:30:00]
Length:6,Freq:D,Timezone:US/Pacific
2012-03-0912:30:00-05:000.079530
2012-03-1012:30:00-05:00-0.434450
2012-03-1112:30:00-04:000.360739
2012-03-1212:30:00-04:000.678065
2012-03-1312:30:00-04:00-0.705374
2012-03-1412:30:00-04:000.684572
Freq:D
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0909:30:00,...,2012-03-1409:30:00]
Length:6,Freq:D,Timezone:Asia/Shanghai
[Finishedin0.6s]
操作时区意识型(timezone-aware)Timestamp对象
跟时间序列和日期序列差不多,Timestamp对象也能被从单纯型(navie)本地化为timezone-aware,并从一个时区转换为另一个时区。
#-*-coding:utf-8-*-
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
importdatetimeasdt
frompandasimportSeries,DataFrame
fromdatetimeimportdatetime
fromdateutil.parserimportparse
importtime
frompandas.tseries.offsetsimportHour,Minute,Day,MonthEnd
importpytz
stamp=pd.Timestamp('2011-03-1204:00')
printtype(stamp),'\n'
stamp_utc=stamp.tz_localize('UTC')
printstamp_utc,'\n'
printstamp_utc.tz_convert('US/Eastern'),'\n'
stamp_moscow=pd.Timestamp('2011-03-1204:00',tz='Europe/Moscow')
printstamp_moscow
#时区意识型Timestamp对象在内部保存了一个UTC时间戳值(自1970年1月1日起的纳秒数),这个UTC值在时区转换过程中是不会变化的
printstamp_utc.value
printstamp_utc.tz_convert('US/Eastern').value,'\n'
#当使用pandas的DataOffset对象执行运算时,会自动关注“夏时令”…………
>>>
<class'pandas.lib.Timestamp'>
2011-03-1204:00:00+00:00
2011-03-1123:00:00-05:00
2011-03-1204:00:00+03:00
1299902400000000000
1299902400000000000
[Finishedin0.7s]
不同时区之间的运算
如果时间时间时区不同,那么结果就会是UTC时间,由于时间戳其实是以UTC储存的,索引计算很方便。
#-*-coding:utf-8-*-
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
importdatetimeasdt
frompandasimportSeries,DataFrame
fromdatetimeimportdatetime
fromdateutil.parserimportparse
importtime
frompandas.tseries.offsetsimportHour,Minute,Day,MonthEnd
importpytz
rng=pd.date_range('3/7/2012',periods=10,freq='B')
ts=Series(np.random.randn(len(rng)),index=rng)
printts
ts1=ts[:7].tz_localize('Europe/London')
#注意naive是不能直接转换为时区的,必须先转换为localize再进行转换
ts2=ts1[2:].tz_convert('Europe/Moscow')
result=ts1+ts2
#转换为UTC
printresult.index
>>>
2012-03-07-0.591417
2012-03-081.009651
2012-03-09-1.922004
2012-03-120.246206
2012-03-130.033430
2012-03-140.614911
2012-03-151.944014
2012-03-16-2.349846
2012-03-190.425925
2012-03-201.941166
Freq:B
<class'pandas.tseries.index.DatetimeIndex'>
[2012-03-0700:00:00,...,2012-03-1500:00:00]
Length:7,Freq:B,Timezone:UTC
[Finishedin0.7s]
相关文章推荐
- python读写Excel
- python的生成器
- Windows下安装Python包(Numpy)的错误
- python 快速排序
- 南通大学自动评教脚本(python)
- Python标准库:迭代器Itertools
- [转载]python中将普通对象作为 字典类(dict) 使用
- Python中的Numpy、SciPy、MatPlotLib安装与配置
- python decorator
- python 连接sql server
- 你可能不知道的 30 个 Python 语言的特点技巧
- python安装scrapy步骤(转载)
- Python基础教程 第6章: 抽象(函数) 学习笔记
- python使用pip安装scrapy失败可能原因
- 零基础入门学习Python(13):字典
- 什么是scipy、numpy、matplotlib?
- 老李分享:Python开发性能测试脚本
- 【Python】Python的IDE——PyCharm的使用
- python发邮件
- Python日期各种处理方式