您的位置:首页 > 编程语言 > Python开发

《利用python进行数据分析》读书笔记--第十章 时间序列(一)

2015-12-17 19:57 525 查看
时间序列是很重要的。时间序列(timeseries)数据是一种重要的结构化数据格式。时间序列的意义取决于具体的应用场景,主要有以下几种:

时间戳(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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: