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

利用python进行数据分析-时间序列2

2016-08-06 21:11 846 查看
1.带有重复索引的时间序列

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

结果为:

2000-01-01    0

2000-01-02    1

2000-01-02    2

2000-01-02    3

2000-01-03    4

dtype: int32

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

print dup_ts.index.is_unique

结果为:

False

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

print dup_ts['1/3/2000']  #不重复

print dup_ts['1/2/2000']  #重复

结果为:

4

2000-01-02    1

2000-01-02    2

2000-01-02    3

dtype: int32

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

grouped=dup_ts.groupby(level=0)

print grouped.mean()

print grouped.count()

结果为:

2000-01-01    0

2000-01-02    2

2000-01-03    4

dtype: int32

2000-01-01    1

2000-01-02    3

2000-01-03    1

dtype: int64

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

dates=[datetime.datetime(2011,1,2),datetime.datetime(2011,1,5),

       datetime.datetime(2011,1,7),datetime.datetime(2011,1,8),

       datetime.datetime(2011,1,10),datetime.datetime(2011,1,12)]

ts=Series(np.random.randn(6),index=dates)

print ts

print ts.resample('D')

结果为:

2011-01-02    1.068995

2011-01-05    0.564281

2011-01-07    1.910822

2011-01-08   -0.339067

2011-01-10   -1.671388

2011-01-12   -0.679710

dtype: float64

2011-01-02    1.068995

2011-01-03         NaN

2011-01-04         NaN

2011-01-05    0.564281

2011-01-06         NaN

2011-01-07    1.910822

2011-01-08   -0.339067

2011-01-09         NaN

2011-01-10   -1.671388

2011-01-11         NaN

2011-01-12   -0.679710

Freq: D, dtype: float64

3.生成日期范围

index=pd.date_range('4/1/2012','6/1/2012')

print index

结果为:

DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04',

               '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08',

               '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12',

               '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16',

               '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20',

               '2012-04-21', '2012-04-22', '2012-04-23', '2012-04-24',

               '2012-04-25', '2012-04-26', '2012-04-27', '2012-04-28',

               '2012-04-29', '2012-04-30', '2012-05-01', '2012-05-02',

               '2012-05-03', '2012-05-04', '2012-05-05', '2012-05-06',

               '2012-05-07', '2012-05-08', '2012-05-09', '2012-05-10',

               '2012-05-11', '2012-05-12', '2012-05-13', '2012-05-14',

               '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18',

               '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22',

               '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26',

               '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30',

               '2012-05-31', '2012-06-01'],

              dtype='datetime64[ns]', freq='D')

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

print pd.date_range(start='4/1/2012',periods=20)

print pd.date_range(end='6/1/2012',periods=20)

结果为:

DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04',

               '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08',

               '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12',

               '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16',

               '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'],

              dtype='datetime64[ns]', freq='D')

DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16',

               '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20',

               '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24',

               '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28',

               '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'],

              dtype='datetime64[ns]', freq='D')

起始和结束日期定义了日期索引的严格边界。如果你想生成一个由每月最后一个工作日组成的日期索引,可以传入“BM”频率,这样只会包含时间间隔内符合频率要求的日期

print pd.date_range('1/1/2000','12/1/2000',freq='BM')

结果为:

DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28',

               '2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',

               '2000-09-29', '2000-10-31', '2000-11-30'],

              dtype='datetime64[ns]', freq='BM')

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

print pd.date_range('5/2/2012 12:56:31',periods=5,normalize=True)

结果为:

DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05',

               '2012-05-06'],

              dtype='datetime64[ns]', freq='D')

4.频率和日期偏移量

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

from pandas.tseries.offsets import Hour,Minute

hour=Hour()

print hour

结果为:

<Hour>

传入一个整数即可定义偏移量的倍数

four_hours=Hour(4)

print four_hours

结果为:

<4 * Hours>

一般来说,无需显示创建这样的对象,只需使用诸如“H”或“4H”这样的字符串别名即可。在基础频率前面放上一个整数即可创建倍数

print pd.date_range('1/1/2000','1/3/2000 23:59',freq='4h')

结果为:

DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00',

               '2000-01-01 08:00:00', '2000-01-01 12:00:00',

               '2000-01-01 16:00:00', '2000-01-01 20:00:00',

               '2000-01-02 00:00:00', '2000-01-02 04:00:00',

               '2000-01-02 08:00:00', '2000-01-02 12:00:00',

               '2000-01-02 16:00:00', '2000-01-02 20:00:00',

               '2000-01-03 00:00:00', '2000-01-03 04:00:00',

               '2000-01-03 08:00:00', '2000-01-03 12:00:00',

               '2000-01-03 16:00:00', '2000-01-03 20:00:00'],

              dtype='datetime64[ns]', freq='4H')

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

print Hour(2)+Minute(30)

结果为:

<150 * Minutes>

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

print pd.date_range('1/1/2000',periods=10,freq='1h30min')

结果为:

<150 * Minutes>

DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00',

               '2000-01-01 03:00:00', '2000-01-01 04:30:00',

               '2000-01-01 06:00:00', '2000-01-01 07:30:00',

               '2000-01-01 09:00:00', '2000-01-01 10:30:00',

               '2000-01-01 12:00:00', '2000-01-01 13:30:00'],

              dtype='datetime64[ns]', freq='90T')

有些频率所描述的时间点并不是均匀分隔的。例如,“M”(日历月末)和“BM”(每月最后一个工作日)就取决于每月的天数。由于没有更好的术语,我将这些称为锚点偏移量







5.WOM日期

WOM能获得诸如“每月第3个星期五”之类的日期

rng=pd.date_range('1/1/2012','9/1/2012',freq='WOM-3FRI')

print list(rng)

结果为:

[Timestamp('2012-01-20 00:00:00', offset='WOM-3FRI'), Timestamp('2012-02-17 00:00:00', offset='WOM-3FRI'), Timestamp('2012-03-16 00:00:00', offset='WOM-3FRI'), Timestamp('2012-04-20 00:00:00', offset='WOM-3FRI'), Timestamp('2012-05-18
00:00:00', offset='WOM-3FRI'), Timestamp('2012-06-15 00:00:00', offset='WOM-3FRI'), Timestamp('2012-07-20 00:00:00', offset='WOM-3FRI'), Timestamp('2012-08-17 00:00:00', offset='WOM-3FRI')]

6.移动(超前和滞后)数据

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

ts=Series(np.random.randn(4),index=pd.date_range('1/1/2000',periods=4,freq='M'))

print ts

print ts.shift(2)

print ts.shift(-2)

结果为:

2000-01-31   -0.389670

2000-02-29    0.541153

2000-03-31    0.998715

2000-04-30   -0.800795

Freq: M, dtype: float64

2000-01-31         NaN

2000-02-29         NaN

2000-03-31   -0.389670

2000-04-30    0.541153

Freq: M, dtype: float64

2000-01-31    0.998715

2000-02-29   -0.800795

2000-03-31         NaN

2000-04-30         NaN

Freq: M, dtype: float64

shift通常用于计算一个时间序列或多个时间序列中的百分比变化,可以这样表达:ts/ts.shift(1)-1

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

print ts.shift(2,freq='M')

结果为:

2000-03-31   -0.355693

2000-04-30    0.708167

2000-05-31    0.870448

2000-06-30   -0.804584

Freq: M, dtype: float64

这里还可以使用其他频率

print ts.shift(3,freq='D')

print ts.shift(1,freq='3D')

print ts.shift(1,freq='90T')

结果为:

2000-02-03   -1.045612

2000-03-03    2.034699

2000-04-03   -0.189753

2000-05-03   -0.314928

dtype: float64

2000-02-03   -1.045612

2000-03-03    2.034699

2000-04-03   -0.189753

2000-05-03   -0.314928

dtype: float64

2000-01-31 01:30:00   -1.045612

2000-02-29 01:30:00    2.034699

2000-03-31 01:30:00   -0.189753

2000-04-30 01:30:00   -0.314928

Freq: M, dtype: float64

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

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

from pandas.tseries.offsets import Day,MonthEnd

now=datetime.datetime(2011,11,17)

print now+3*Day()

结果为:

2011-11-20 00:00:00

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

print now+MonthEnd()

print now+MonthEnd(2)

结果为:

2011-11-30 00:00:00

2011-12-31 00:00:00

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

offset=MonthEnd()

print offset.rollforward(now)

print offset.rollback(now)

结果为:

2011-11-30 00:00:00

2011-10-31 00:00:00

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

ts=Series(np.random.randn(20),index=pd.date_range('1/15/2000',periods=20,freq='4d'))

print ts.groupby(offset.rollforward).mean()

结果为:

2000-01-31   -0.024235

2000-02-29   -0.182988

2000-03-31   -0.458176

dtype: float64

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

print ts.resample('M',how='mean')

结果为:

2000-01-31   -0.076951

2000-02-29   -0.093232

2000-03-31   -0.390766

Freq: M, dtype: float64

8.时区处理

时区名可以在文档中找到,也可以通过交互的方式查看

import pytz

print pytz.common_timezones[-5:]

结果为:

['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']

要从pytz中获取时区对象,使用pytz.timezone即可

tz=pytz.timezone('US/Eastern')

print tz

结果为:

US/Eastern

9.本地化和转换

默认情况下,pandas中的时间序列是单纯的时区。看看下面这个时间序列

rng=pd.date_range('3/9/2012 9:30',periods=6,freq='D')

ts=Series(np.random.rand(len(rng)),index=rng)

其索引的tz字段为None

print ts.index.tz

结果为:

None

在生成日期范围的时候还可以加上一个时区集

print pd.date_range('3/9/2012 9:30',periods=10,freq='D',tz='UTC')

结果为:

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',

               '2012-03-15 09:30:00+00:00', '2012-03-16 09:30:00+00:00',

               '2012-03-17 09:30:00+00:00', '2012-03-18 09:30:00+00:00'],

              dtype='datetime64[ns, UTC]', freq='D')

从单纯到本地化的转换是通过tz_localize方法处理的

ts_utc=ts.tz_localize('UTC')

print ts_utc

结果为:

2012-03-09 09:30:00+00:00    0.641279

2012-03-10 09:30:00+00:00    0.275813

2012-03-11 09:30:00+00:00    0.113782

2012-03-12 09:30:00+00:00    0.073940

2012-03-13 09:30:00+00:00    0.087528

2012-03-14 09:30:00+00:00    0.458625

Freq: D, dtype: float64

print ts_utc.index

结果为:

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将其转换到别的时区了

print ts_utc.tz_convert('US/Eastern')

结果为:

2012-03-09 04:30:00-05:00    0.595619

2012-03-10 04:30:00-05:00    0.337900

2012-03-11 05:30:00-04:00    0.552080

2012-03-12 05:30:00-04:00    0.922716

2012-03-13 05:30:00-04:00    0.311070

2012-03-14 05:30:00-04:00    0.682581

Freq: D, dtype: float64

对于上面这种时间序列(它跨越了美国东部时区的夏令时转变期),我们可以将其本地化到EST,然后转换为UTC或柏林时间

ts_eastern=ts.tz_localize('US/Eastern')

print ts_eastern.tz_convert('UTC')

结果为:

2012-03-09 14:30:00+00:00    0.696696

2012-03-10 14:30:00+00:00    0.798250

2012-03-11 13:30:00+00:00    0.237720

2012-03-12 13:30:00+00:00    0.826396

2012-03-13 13:30:00+00:00    0.304436

2012-03-14 13:30:00+00:00    0.162294

Freq: D, dtype: float64

print ts_eastern.tz_convert('Europe/Berlin')

结果为:

2012-03-09 15:30:00+01:00    0.116943

2012-03-10 15:30:00+01:00    0.805555

2012-03-11 14:30:00+01:00    0.765655

2012-03-12 14:30:00+01:00    0.762651

2012-03-13 14:30:00+01:00    0.947182

2012-03-14 14:30:00+01:00    0.670358

Freq: D, dtype: float64

tz_localize和tz_convert也是DatatimeIndex的实例方法

结果为:

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

DatetimeIndex(['2012-03-09 09:30:00+08:00', '2012-03-10 09:30:00+08:00',

               '2012-03-11 09:30:00+08:00', '2012-03-12 09:30:00+08:00',

               '2012-03-13 09:30:00+08:00', '2012-03-14 09:30:00+08:00'],

              dtype='datetime64[ns, Asia/Shanghai]', freq='D')

10.操作时区意识型Timestamp对象

跟时间序列和日期范围差不多,Timestamp对象也能从单纯型本地化为时区意识型,并从一个时区转换到另一个时区

stamp=pd.Timestamp('2011-03-12 04:00')

stamp_utc=stamp.tz_localize('utc')

print stamp_utc.tz_convert('US/Eastern')

结果为:

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

在创建Timestamp时,还可以传入一个时区信息

stamp_moscow=pd.Timestamp('2011-03-12 04:00',tz='Europe/Moscow')

print stamp_moscow

结果为:

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

时区意识型Timestamp对象在内部保存了一个UTC时间戳值。这个UTC值在时区转换过程中是不会发生变化的

print stamp_utc.value

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

结果为:

1299902400000000000

1299902400000000000

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

from pandas.tseries.offsets import Hour

#夏令时转变前30分钟

stamp=pd.Timestamp('2012-03-12 01:30',tz='US/Eastern')

print stamp

print stamp+Hour()

#夏令时转变前90分钟

stamp=pd.Timestamp('2012-11-04 00:30',tz='US/Eastern')

print stamp

print stamp+2*Hour()

结果为:

2012-03-12 01:30:00-04:00

2012-03-12 02:30:00-04:00

2012-11-04 00:30:00-04:00

2012-11-04 01:30:00-05:00

11.不同时区之间的运算

如果两个时间序列的时区不同,在将它们合并到一起时,最终结果就会是UTC。由于时间戳其实是你UTC存储的,所以这是一个很简单的运算,并不需要发生任何转换

rng=pd.date_range('3/7/2012 09:30',periods=10,freq='B')

ts=Series(np.random.randn(len(rng)),index=rng)

print ts

结果为:

2012-03-07 09:30:00    1.533603

2012-03-08 09:30:00   -0.224899

2012-03-09 09:30:00    0.542026

2012-03-12 09:30:00   -0.815753

2012-03-13 09:30:00   -1.421795

2012-03-14 09:30:00    0.399534

2012-03-15 09:30:00    0.293016

2012-03-16 09:30:00   -1.612594

2012-03-19 09:30:00    0.072332

2012-03-20 09:30:00    0.313340

Freq: B, dtype: float64

ts1=ts[:7].tz_localize('Europe/London')

ts2=ts1[2:].tz_convert('Europe/Moscow')

result=ts1+ts2

print result.index

结果为:

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')

12.日期及其算术运算

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

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

print p

结果为:

2007

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

print p+5

print p-2

结果为:

2012

2005

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

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

结果为:

7

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

rng=pd.date_range('1/1/2000','6/30/2000',freq='M')

print rng

结果为:

DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-30',

               '2000-05-31', '2000-06-30'],

              dtype='datetime64[ns]', freq='M')

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

print Series(np.random.randn(6),index=rng)

结果为:

2000-01-31   -1.375039

2000-02-29   -0.143529

2000-03-31    2.162475

2000-04-30    2.109093

2000-05-31    0.759747

2000-06-30   -1.994800

Freq: M, dtype: float64

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

values=['2001Q3','2002Q2','2003Q1']

index=pd.PeriodIndex(values,freq='Q-DEC')

print index

结果为:

PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='int64', freq='Q-DEC')
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据分析 python