Py学习  »  Python

利用Python进行数据分析(十七)之时区时期处理

BrainZou • 5 年前 • 591 次点击  

利用Python进行数据分析(十七)之时区时期处理

微信公众号:BrainZou
欢迎关注,一起学习。
回复“资料”,有本人收集的各种Python,Java,Android,小程序,后端,算法等等近1T的资料免费分享给你。

时区处理

在Python中,时区信息来自第三方库pytz,pandas包装了pytz的功能,使用方法如下:

import pytz
#时区名
pytz.common_timezones[-5:]
out:['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']
#时区对象
tz = pytz.timezone('US/Eastern')
tz
out:<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>

pandas方法中既可以接收时区名也可以接收对象,但是建议只用时区名。

本地化和转换

rng = pd.date_range('3/9/2012 9:30',periods = 6,freq='D')
ts = Series(np.random.randn(len(rng)),index=rng)
print(ts.index.tz)
out:None

可以看到默认的生成后,tz字段是None。生成日期范围时自然可以加上指定的时区集如tz='UTC'。
从单纯(None)到本地化的转换通过tz_localize方法处理的:

ts.tz_localize('UTC').index
out:DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00',
'2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00',
'2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'],
dtype='datetime64[ns, UTC]', freq='D')

本地化后,就可以使用tz_convert转换到其他的时区了:

ts.tz_localize('UTC').tz_convert('US/Eastern')
out2012-03-09 04:30:00-05:00 -0.197766
2012-03-10 04:30 :00-05:00 -0.257315
2012-03-11 05:30:00-04:00 -0.402924
2012-03-12 05:30:00-04:00 1.146012
2012-03-13 05:30:00-04:00 0.415374
2012-03-14 05:30:00-04:00 0.405810
Freq: D, dtype: float64

可以看到上面时间是跨越了美国东部的夏令时转变期。可以将其本地化到EST,然后转换为UTC或柏林时间。
tz_localize和tz_convert也是DatetimeIndex的实例方法,即你也可以:

ts.index.tz_localize('Asia/Shanghai')

操作时区意识型Timestamp对象

即与之前的时间序列和日期范围差不多,Timestamp对象也能从单纯型本地化,再转换到另一个时区:

stamp = pd.Timestamp('2011-03-12 04:00')
stamp_utc = stamp.tz_localize('utc')
stamp_utc.tz_convert('US/Eastern')
out:Timestamp('2011-03-11 23:00:00-0500', tz='US/Eastern')

同理创建Timestamp时,可以传入时区信息。
时区意识型Timestamp对象(即有时区信息后)在内部保存了一个UTC的时间戳值。这个UTC值在转换过程中,是不会改变的。

stamp_utc.value
out1299902400000000000
stamp_utc.tz_convert('US/Eastern').value
out1299902400000000000

当使用pandas的DateOffset对象执行时间算术运算时,运算过程会自动关注是否存在夏令时转变期:

#夏令时转变前30分钟
from pandas.tseries.offsets import Hour
stamp = pd.Timestamp('2012-03-12 01:30',tz='US/Eastern')
stamp
out:Timestamp('2012-03-12 01:30:00-0400', tz='US/Eastern')
stamp +Hour()
out:Timestamp('2012-03-12 02:30:00-0400', tz='US/Eastern')
#夏令时转变前90分钟
stamp = pd.Timestamp('2012-11-04 00:30',tz = 'US/Eastern')
stamp
out:Timestamp('2012-11-04 00:30:00-0400', tz='US/Eastern')
stamp+2*Hour()
out:Timestamp('2012-11-04 01:30:00-0500', tz='US/Eastern')

不同时区之间的运算

当两个不同时间序列的时区不同,将他们合并到一起时,最终的结果会是UTC。因为时间戳是以UTC存储的。可以理解为时区显示只是对UTC存储的时间戳格式化处理下。

rng = pd.date_range('3/7/2012 9:30',periods=10,freq='B')
ts = Series(np.random.randn(len(rng)),index=rng)
ts
out
2012-03-07 09:30:00 1.064517
2012-03-08 09:30:00 -0.183066
2012-03-09 09:30:00 -1.051956
2012-03-12 09:30:00 -1.256536
2012-03-13 09:30:00 1.831029
2012-03-14 09:30 :00 -0.232838
2012-03-15 09:30:00 -0.915990
2012-03-16 09:30:00 -0.196933
2012-03-19 09:30:00 0.364130
2012-03-20 09:30:00 -0.818402
Freq: B, dtype: float64
ts1=ts[:7].tz_localize('Europe/London')
ts2=ts1[2:].tz_convert('Europe/Moscow')
result=ts1+ts2
result.index
out:DatetimeIndex(['2012-03-07 09:30:00+00:00', '2012-03-08 09:30:00+00:00',
'2012-03-09 09:30:00+00:00', '2012-03-12 09:30:00+00:00',
'2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00',
'2012-03-15 09:30:00+00:00'],
dtype='datetime64[ns, UTC]', freq='B')

时期及其算术运算

时期表示的是时间区间,比如数日,数月,数季,数年等。Period类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数,以及频率。

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

这个Period对象表示的是从2007年1月1日到2007年12月31日之间的整段时间。只需对Period对象加上或减去一个整数即可达到根据其频率进行位移的效果:

p+5
out:Period('2012', 'A-DEC')

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

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

period_range函数可用于创建规则的时期范围:

rng = pd.period_range('1/1/2000','6/30/2000',freq='M')
rng
out:PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M')

PeriodIndex类保存了一组Period,它可以在任何pandas数据结构中被用作轴索引:

Series(np.random.randn(6),index=rng)
out
2000-01 1.016713
2000-02 -0.348144
2000-03 0.725960
2000-04 -0.670895
2000-05 0.671717
2000-06 -0.501145
Freq: M, dtype: float64

PeriodIndex类的构造函数还允许直接使用一组字符串:

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

时期的频率转换

Period和PeriodIndex对象都可以通过其asfreq方法被转换成别的频率。假设我们有一个年度时期,希望将其转换为当年年初或年末的一个月度时期。该任务非常简单:

p=pd.Period('2007',freq='A-DEC')
p.asfreq('M',how='start')
out:Period('2007-01', 'M')
p.asfreq('M',how='end')
out:Period('2007-12', 'M')

你可以将Period(2007‘,‘A-DEC‘)看做一个被划分为多个月度时期的时间段中的游标。对于一个不以12月结束的财政年度,月度子时期的归属情况就不一样了:




    
p=pd.Period('2007',freq='A-JUN')
p.asfreq('M',how='start')
out:Period('2006-07', 'M')
p.asfreq('M',how='end')
out:Period('2007-06', 'M')
Period频率
Period频率

解释一下,可能会不理解。A-DEC的意思是以DEC这个月12月为这年的结尾。所以2007 A-JUN即把Jun(6月)作为2007年结尾,所以他的开始就是2006-7了。那下面这个应该就也很好理解了:

p = pd.Period('2007-08','M')
p.asfreq('A-JUN')
Period('2008', 'A-JUN')
#2007年8月在xxxx年以6月结束的年份之间。

PeriodIndex或TimeSeries的频率转换方式也是如此。

按季度计算的时期频率

许多会计、金融领域常用季度型来统计。

按季度统计
按季度统计

还是那句话:DEC的意思是以DEC这个月12月为这年的结尾。就很好理解了。

p = pd.Period('2012Q4',freq='Q-JAN')
p.asfreq('D',how='start')
out:Period('2011-11-01', 'D')
p.asfreq('D',how='end')
out:Period('2012-01-31', 'D')

因此,Period之间的算术运算会非常简单。例如,要获取该季度倒数第二个工作日下午4点的时间戳,你可以这样:

p4pm=(p.asfreq('B','e')-1).asfreq('T','s')


    
+16*60
p4pm
out:Period('2012-01-30 16:00', 'T')
p4pm.to_timestamp()
out:Timestamp('2012-01-30 16:00:00')

period_range还可以用于生成季度型范围。季度型范围的运算跟上面一样。

将Timestamp转换为Period(及其反向过程)

通过使用to_period方法,可以将由时间戳索引的Series和DataFrame对象转换为以时期索引:

rng=pd. date_range('1/1/2000', periods=3, freq='M') 
ts = Series(np.random.randn(3),index=rng)
pts = ts.to_period()
ts
out:
2000-01-31 -0.660238
2000-02-29 -0.847080
2000-03-31 -1.287235
Freq: M, dtype: float64
pts
out:
2000-01 -0.660238
2000-02 -0.847080
2000-03 -1.287235
Freq: M, dtype: float64

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

rng=pd.date_range('1/29/2000',periods=6,freq='D')
ts2=Series(np.random.randn(6),index=rng)
ts2.to_period('M')
out:
2000-01 -0.154971
2000-01 0.879136
2000-01 -0.813320
2000-02 1.014186
2000-02 -1.519461
2000-02 0.569898
Freq: M, dtype: float64

通过数组创建PeriodIndex

固定频率的数据集通常会将时间信息分开存放在多个列中。
将两个数组以及一个频率传入PeriodIndex,就可以将它们合并成DataFrame的一个索引:

year = [1959,1959,1959,2008,2009]
quarter = [1,2,3,4,3]
index=pd.PeriodIndex(year=year,quarter=quarter,freq='Q-DEC')
index
out:
PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '2008Q4', '2009Q3'], dtype='period[Q-DEC]' , freq='Q-DEC')

今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/p5ojynAZAD
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/11550
 
591 次点击