美文网首页我爱编程
《利用Python进行数据分析》第10章 时区处理笔记

《利用Python进行数据分析》第10章 时区处理笔记

作者: 龍猫君 | 来源:发表于2018-01-01 20:31 被阅读0次

    时区处理

    在Python中,时区信息来自第三方库pytz,它使Python可以使用Olson数据库(汇编了世界时区信息)。

    有关pytz库的更多信息,请查阅其文档,时区名可以在文档中找到,也可以通过交互的方式查看

    from pandas import Series,DataFrame
    import pandas as pd
    import numpy as np
    import pytz
    
    pytz.common_timezones[-5:]
    
    ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']
    

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

    tz=pytz.timezone('US/Eastern')
    tz
    
    <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>
    

    pandas中的方法既可以接受时区名也可以接受这种对象。建议只用时区名

    本地化和转换

    默认情况下,pandas中的时间序列是单纯的(naive)时区

    rng=pd.date_range('3/9/2017 10:30',periods=6,freq='D')
    ts=Series(np.random.randn(len(rng)),index=rng)
    ts
    
    2017-03-09 10:30:00   -0.010633
    2017-03-10 10:30:00   -1.026320
    2017-03-11 10:30:00    0.001829
    2017-03-12 10:30:00   -0.221503
    2017-03-13 10:30:00   -1.658208
    2017-03-14 10:30:00    0.559757
    Freq: D, dtype: float64
    
    print(ts.index.tz)  #其索引的tz字段为None
    
    None
    

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

    pd.date_range('10/1/2017 10:30',periods=10,freq='D',tz='UTC')
    
    DatetimeIndex(['2017-10-01 10:30:00+00:00', '2017-10-02 10:30:00+00:00',
                   '2017-10-03 10:30:00+00:00', '2017-10-04 10:30:00+00:00',
                   '2017-10-05 10:30:00+00:00', '2017-10-06 10:30:00+00:00',
                   '2017-10-07 10:30:00+00:00', '2017-10-08 10:30:00+00:00',
                   '2017-10-09 10:30:00+00:00', '2017-10-10 10:30:00+00:00'],
                  dtype='datetime64[ns, UTC]', freq='D')
    

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

    ts_utc=ts.tz_localize('UTC')
    ts_utc
    
    2017-03-09 10:30:00+00:00   -0.010633
    2017-03-10 10:30:00+00:00   -1.026320
    2017-03-11 10:30:00+00:00    0.001829
    2017-03-12 10:30:00+00:00   -0.221503
    2017-03-13 10:30:00+00:00   -1.658208
    2017-03-14 10:30:00+00:00    0.559757
    Freq: D, dtype: float64
    

    一旦时间序列被本地化到某个特定时区,就可以用tz_convert将其转换到别的时区了

    ts_utc.tz_convert('US/Eastern')
    
    2017-03-09 05:30:00-05:00   -0.010633
    2017-03-10 05:30:00-05:00   -1.026320
    2017-03-11 05:30:00-05:00    0.001829
    2017-03-12 06:30:00-04:00   -0.221503
    2017-03-13 06:30:00-04:00   -1.658208
    2017-03-14 06:30:00-04:00    0.559757
    Freq: D, dtype: float64
    

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

    ts_eastern=ts_utc.tz_convert('US/Eastern')
    ts_eastern.tz_convert('UTC')
    
    2017-03-09 10:30:00+00:00   -0.010633
    2017-03-10 10:30:00+00:00   -1.026320
    2017-03-11 10:30:00+00:00    0.001829
    2017-03-12 10:30:00+00:00   -0.221503
    2017-03-13 10:30:00+00:00   -1.658208
    2017-03-14 10:30:00+00:00    0.559757
    Freq: D, dtype: float64
    
    ts_eastern.tz_convert('Europe/Berlin')
    
    2017-03-09 11:30:00+01:00   -0.010633
    2017-03-10 11:30:00+01:00   -1.026320
    2017-03-11 11:30:00+01:00    0.001829
    2017-03-12 11:30:00+01:00   -0.221503
    2017-03-13 11:30:00+01:00   -1.658208
    2017-03-14 11:30:00+01:00    0.559757
    Freq: D, dtype: float64
    

    tz_localize和tz_convert也是DatetimeIndex的实例方法

    ts.index.tz_localize('Asia/Shanghai')
    
    DatetimeIndex(['2017-03-09 10:30:00+08:00', '2017-03-10 10:30:00+08:00',
                   '2017-03-11 10:30:00+08:00', '2017-03-12 10:30:00+08:00',
                   '2017-03-13 10:30:00+08:00', '2017-03-14 10:30:00+08:00'],
                  dtype='datetime64[ns, Asia/Shanghai]', freq='D')
    

    警告: 对单纯时间戳的本地化操作还会检查夏令时转变期附近容易混淆或不存在的时间。

    操作时区意识型Timestamp对象

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

    stamp=pd.Timestamp('2017-06-12 06:00')
    stamp_utc=stamp.tz_localize('utc')
    stamp_utc
    
    Timestamp('2017-06-12 06:00:00+0000', tz='UTC')
    
    stamp_utc.tz_convert('US/Eastern')
    
    Timestamp('2017-06-12 02:00:00-0400', tz='US/Eastern')
    

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

    stamp_moscow=pd.Timestamp('2017-06-29 06:30',tz='Europe/Moscow')
    stamp_moscow
    
    Timestamp('2017-06-29 06:30:00+0300', tz='Europe/Moscow')
    

    时区意识型Timestamp对象在内部保存了一个UTC时间戳值(自UNIX纪元(1970年1月1日)算起的纳秒数)。这个UTC值在时区转换过程中是不会发生变化的

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

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

    from pandas.tseries.offsets import Hour
    stamp=pd.Timestamp('2017-06-29 06:30',tz='US/Eastern')
    stamp  
    
    Timestamp('2017-06-29 06:30:00-0400', tz='US/Eastern')
    
    stamp+Hour()  # 夏令时转变前30分钟
    
    Timestamp('2017-06-29 07:30:00-0400', tz='US/Eastern')
    
    stamp=pd.Timestamp('2017-12-05 00:30',tz='US/Eastern')
    stamp
    
    Timestamp('2017-12-05 00:30:00-0500', tz='US/Eastern')
    
    stamp+2*Hour()  # 夏令时转变前90分钟
    
    Timestamp('2017-12-05 02:30:00-0500', tz='US/Eastern')
    

    不同时区之间的运算

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

    rng=pd.date_range('3/9/2017 10:30',periods=10,freq='B')
    ts=Series(np.random.randn(len(rng)),index=rng)
    ts
    
    2017-03-09 10:30:00   -0.221934
    2017-03-10 10:30:00   -0.026261
    2017-03-13 10:30:00   -0.582364
    2017-03-14 10:30:00   -1.488370
    2017-03-15 10:30:00   -0.766432
    2017-03-16 10:30:00   -0.114979
    2017-03-17 10:30:00   -0.708361
    2017-03-20 10:30:00   -0.745198
    2017-03-21 10:30:00    0.896473
    2017-03-22 10:30:00    0.505825
    Freq: B, dtype: float64
    
    ts1=ts[:7].tz_localize('Europe/London')
    ts1
    
    2017-03-09 10:30:00+00:00   -0.221934
    2017-03-10 10:30:00+00:00   -0.026261
    2017-03-13 10:30:00+00:00   -0.582364
    2017-03-14 10:30:00+00:00   -1.488370
    2017-03-15 10:30:00+00:00   -0.766432
    2017-03-16 10:30:00+00:00   -0.114979
    2017-03-17 10:30:00+00:00   -0.708361
    Freq: B, dtype: float64
    
    ts2=ts[2:].tz_localize('Europe/London')
    ts2
    
    2017-03-13 10:30:00+00:00   -0.582364
    2017-03-14 10:30:00+00:00   -1.488370
    2017-03-15 10:30:00+00:00   -0.766432
    2017-03-16 10:30:00+00:00   -0.114979
    2017-03-17 10:30:00+00:00   -0.708361
    2017-03-20 10:30:00+00:00   -0.745198
    2017-03-21 10:30:00+00:00    0.896473
    2017-03-22 10:30:00+00:00    0.505825
    Freq: B, dtype: float64
    
    result=ts1+ts2
    result.index
    
    DatetimeIndex(['2017-03-09 10:30:00+00:00', '2017-03-10 10:30:00+00:00',
                   '2017-03-13 10:30:00+00:00', '2017-03-14 10:30:00+00:00',
                   '2017-03-15 10:30:00+00:00', '2017-03-16 10:30:00+00:00',
                   '2017-03-17 10:30:00+00:00', '2017-03-20 10:30:00+00:00',
                   '2017-03-21 10:30:00+00:00', '2017-03-22 10:30:00+00:00'],
                  dtype='datetime64[ns, Europe/London]', freq='B')
    

    时期及其算术运算

    时期(period)表示的是时间区间,比如数日、数月、数季、数年等。

    Period类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数,以及表10-4中的频率。

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

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

    p+7
    
    Period('2017', 'A-DEC')
    
    p-6
    
    Period('2004', 'A-DEC')
    

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

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

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

    rng=pd.period_range('2/1/2017','12/25/2017',freq='M')
    rng
    
    PeriodIndex(['2017-02', '2017-03', '2017-04', '2017-05', '2017-06', '2017-07',
                 '2017-08', '2017-09', '2017-10', '2017-11', '2017-12'],
                dtype='period[M]', freq='M')
    

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

    Series(np.random.randn(11),index=rng)
    
    2017-02   -0.319098
    2017-03   -0.151707
    2017-04    0.848815
    2017-05    1.755160
    2017-06   -2.718766
    2017-07    0.921045
    2017-08   -0.287053
    2017-09   -0.720153
    2017-10    0.827423
    2017-11   -1.147326
    2017-12    0.480532
    Freq: M, dtype: float64
    

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

    values=['2010Q3','2013Q2','2016Q1']
    index=pd.PeriodIndex(values,freq='Q-DEC')
    index
    
    PeriodIndex(['2010Q3', '2013Q2', '2016Q1'], dtype='period[Q-DEC]', freq='Q-DEC')
    

    时期的频率转换

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

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

    可以将Period('2017','A-DEC')看做一个被划分为多个月度时期的时间段中的游标。图10-1对此进行了说明。对于一个不以12月结束的财政年度,月度子时期的归属情况就不一样了

    p=pd.Period('2017',freq='A-JUN')
    p.asfreq('M','start')
    
    Period('2016-07', 'M')
    
    p.asfreq('M','end')
    
    Period('2017-06', 'M')
    

    在将高频率转换为低频率时,超时期(superperiod)是由子时期(subperiod)所属的位置决定的。例如,在A-JUN频率中,月份“2017年8月”实际上是属于周期“2018年”的

    p=pd.Period('2017-08','M')
    p.asfreq('A-JUN')
    
    Period('2018', 'A-JUN')
    

    PeriodIndex或TimeSeries的频率转换方式也是这样

    rng=pd.period_range('2010','2018',freq='A-DEC')
    ts=Series(np.random.randn(len(rng)),index=rng)
    ts
    
    2010   -0.433900
    2011   -0.494450
    2012    0.668362
    2013   -0.728913
    2014   -0.062562
    2015    0.764723
    2016   -1.962189
    2017   -2.107805
    2018    2.432714
    Freq: A-DEC, dtype: float64
    
    图10-1:Period频率转换示例

    按季度计算的时期频率

    季度型数据在会计、金融等领域中很常见。许多季度型数据都会涉及“财年末”的概念,通常是一年12个月中某月的最后一个日历日或工作日。就这一点来说,时期"2012Q4"根据财年末的不同会有不同的含义。pandas支持12种可能的季度型频率,即Q-JAN到Q-DEC

    p=pd.Period('2012Q4',freq='Q-JAN')
    p
    
    Period('2012Q4', 'Q-JAN')
    

    在以1月结束的财年中,2012Q4是从11月到1月(将其转换为日型频率就明白了)。图10-2对此进行了说明

    p.asfreq('D','start')
    
    Period('2011-11-01', 'D')
    
    p.asfreq('D','end')
    
    Period('2012-01-31', 'D')
    

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

    p4pm=(p.asfreq('B','e')-1).asfreq('T','s')+16*60
    p4pm
    
    Period('2012-01-30 16:00', 'T')
    
    p4pm.to_timestamp()
    
    Timestamp('2012-01-30 16:00:00')
    
    图10-2:不同季度型频率之间的转换

    eriod_range还可用于生成季度型范围。季度型范围的算术运算也跟上面是一样的

    rng=pd.period_range('2011Q3','2012Q4',freq='Q-JAN')
    ts=Series(np.arange(len(rng)),index=rng)
    ts
    
    2011Q3    0
    2011Q4    1
    2012Q1    2
    2012Q2    3
    2012Q3    4
    2012Q4    5
    Freq: Q-JAN, dtype: int32
    
    new_rng=(rng.asfreq('B','e')-1).asfreq('T','s')+16*60
    new_rng
    
    PeriodIndex(['2010-10-28 16:00', '2011-01-28 16:00', '2011-04-28 16:00',
                 '2011-07-28 16:00', '2011-10-28 16:00', '2012-01-30 16:00'],
                dtype='period[T]', freq='T')
    
    ts.index=new_rng.to_timestamp()
    ts
    
    2010-10-28 16:00:00    0
    2011-01-28 16:00:00    1
    2011-04-28 16:00:00    2
    2011-07-28 16:00:00    3
    2011-10-28 16:00:00    4
    2012-01-30 16:00:00    5
    dtype: int32
    

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

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

    rng=pd.date_range('1/1/2017',periods=3,freq='M')
    rng
    
    DatetimeIndex(['2017-01-31', '2017-02-28', '2017-03-31'], dtype='datetime64[ns]', freq='M')
    
    ts=Series(np.random.randn(3),index=rng)
    ts
    
    2017-01-31   -0.126709
    2017-02-28    0.477945
    2017-03-31   -1.665440
    Freq: M, dtype: float64
    

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

    rng=pd.date_range('1/29/2010',periods=6,freq='D')
    ts2=Series(np.random.randn(6),index=rng)
    ts2.to_period('M')
    
    2010-01    0.453939
    2010-01   -0.116637
    2010-01    0.211619
    2010-02    1.552368
    2010-02    0.583840
    2010-02    0.219376
    Freq: M, dtype: float64
    

    要转换为时间戳,使用to_timestamp即可

    pts=ts.to_period()
    pts
    
    2017-01   -0.126709
    2017-02    0.477945
    2017-03   -1.665440
    Freq: M, dtype: float64
    

    通过数组创建PeriodIndex

    固定频率的数据集通常会将时间信息分开存放在多个列中。例如,在下面这个宏观经济数据集中,年度和季度就分别存放在不同的列中

    data=pd.read_csv('pydata_book/ch08//macrodata.csv')
    data[:8]
    
    data.year
    
    0      1959.0
    1      1959.0
    2      1959.0
    3      1959.0
            ...  
    199    2008.0
    200    2009.0
    201    2009.0
    202    2009.0
    Name: year, Length: 203, dtype: float64
    
    data.quarter
    
    0      1.0
    1      2.0
    2      3.0
    3      4.0
          ... 
    199    4.0
    200    1.0
    201    2.0
    202    3.0
    Name: quarter, Length: 203, dtype: float64
    

    将这两个数组以及一个频率传入PeriodIndex,就可以将它们合并成DataFrame的一个索引

    index=pd.PeriodIndex(year=data.year,quarter=data.quarter,freq='Q-DEC')
    index
    
    PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',
                 '1960Q3', '1960Q4', '1961Q1', '1961Q2',
                 ...
                 '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',
                 '2008Q4', '2009Q1', '2009Q2', '2009Q3'],
                dtype='period[Q-DEC]', length=203, freq='Q-DEC')
    
    data.index=index
    data.infl
    
    1959Q1    0.00
    1959Q2    2.34
    1959Q3    2.74
    1959Q4    0.27
    1960Q1    2.31
    1960Q2    0.14
    1960Q3    2.70
              ... 
    
    2008Q2    8.53
    2008Q3   -3.16
    2008Q4   -8.79
    2009Q1    0.94
    2009Q2    3.37
    2009Q3    3.56
    Freq: Q-DEC, Name: infl, Length: 203, dtype: float64
    

    重采样及频率转换

    重采样(resampling)指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样(downsampling),而将低频率数据转换到高频率则称为升采样(upsampling)。并不是所有的重采样都能被划分到这两个大类中。例如,将W-WED(每周三)转换为W-FRI既不是降采样也不是升采样。

    pandas对象都带有一个resample方法,它是各种频率转换工作的主力函数

    rng=pd.date_range('1/1/2017',periods=100,freq='D')
    ts=Series(np.random.randn(len(rng)),index=rng)
    ts.resample('M',how='mean')
    
    e:\python\lib\site-packages\ipykernel_launcher.py:3: FutureWarning: how in .resample() is deprecated
    the new syntax is .resample(...).mean()
      This is separate from the ipykernel package so we can avoid doing imports until
    
    2017-01-31    0.256096
    2017-02-28    0.206771
    2017-03-31   -0.103452
    2017-04-30   -0.105697
    Freq: M, dtype: float64
    
    ts.resample('M').mean()
    
    2017-01-31    0.256096
    2017-02-28    0.206771
    2017-03-31   -0.103452
    2017-04-30   -0.105697
    Freq: M, dtype: float64
    
    ts.resample('M',kind='period').mean()
    
    2017-01    0.256096
    2017-02    0.206771
    2017-03   -0.103452
    2017-04   -0.105697
    Freq: M, dtype: float64
    

    resample是一个灵活高效的方法,可用于处理非常大的时间序列。

    降采样

    将数据聚合到规整的低频率是一件非常普通的时间序列处理任务。待聚合的数据不必拥有固定的频率,期望的频率会自动定义聚合的面元边界,这些面元用于将时间序列拆分为多个片段。例如,要转换到月度频率('M'或'BM'),数据需要被划分到多个单月时间段中。各时间段都是半开放的。一个数据点只能属于一个时间段,所有时间段的并集必须能组成整个时间帧。在用resample对数据进行降采样时,需要考虑两样东西:
    ·各区间哪边是闭合的。

    如何标记各个聚合面元,用区间的开头还是末尾。

    首先,我们来看一些“1分钟”数据

    rng=pd.date_range('1/1/2017',periods=12,freq='T')
    ts=Series(np.arange(12),index=rng)
    ts
    
    2017-01-01 00:00:00     0
    2017-01-01 00:01:00     1
    2017-01-01 00:02:00     2
    2017-01-01 00:03:00     3
    2017-01-01 00:04:00     4
    2017-01-01 00:05:00     5
    2017-01-01 00:06:00     6
    2017-01-01 00:07:00     7
    2017-01-01 00:08:00     8
    2017-01-01 00:09:00     9
    2017-01-01 00:10:00    10
    2017-01-01 00:11:00    11
    Freq: T, dtype: int32
    

    如果你想要通过求和的方式将这些数据聚合到“5分钟”块中

    注意:这里与书本的代码结果不同。

    ts.resample('5min').sum()
    
    2017-01-01 00:00:00    10
    2017-01-01 00:05:00    35
    2017-01-01 00:10:00    21
    Freq: 5T, dtype: int32
    

    传入的频率将会以“5分钟”的增量定义面元边界。默认情况下,面元的右边界是包含的,因此00:00到00:05的区间中是包含00:05的注1。传入closed='left'会让区间以左边界闭合

    这里可能版本不同,上面的那个与书上结果不同的。

    ts.resample('5min',closed='left').sum()
    
    2017-01-01 00:00:00    10
    2017-01-01 00:05:00    35
    2017-01-01 00:10:00    21
    Freq: 5T, dtype: int32
    
    ts.resample('5min',closed='left',label='left').sum()
    
    2017-01-01 00:00:00    10
    2017-01-01 00:05:00    35
    2017-01-01 00:10:00    21
    Freq: 5T, dtype: int32
    

    最终的时间序列是以各面元右边界的时间戳进行标记的。传入label='left'即可用面元的左边界对其进行标记

    图10-3说明了“1分钟”数据被转换为“5分钟”数据的处理过程。


    图10-3:各种closed、label约定的“5分钟”重采样演示

    比如从右边界减去一秒以便更容易明白该时间戳到底表示的是哪个区间。只需通过loffset设置一个字符串或日期偏移量即可实现这个目的

    ts.resample('5min',loffset='-1s').sum()
    
    2016-12-31 23:59:59    10
    2017-01-01 00:04:59    35
    2017-01-01 00:09:59    21
    Freq: 5T, dtype: int32
    

    也可以通过调用结果对象的shift方法来实现该目的,这样就不需要设置loffset了

    OHLC重采样

    金融领域中有一种无所不在的时间序列聚合方式,即计算各面元的四个值:第一个值(open,开盘)、最后一个值(close,收盘)、最大值(high,最高)以及最小值(low,最低)。

    传入how='ohlc'即可得到一个含有这四种聚合值的DataFrame。整个过程很高效,只需一次扫描即可计算出结果

    ts.resample('5min').ohlc()
    

    通过groupby进行重采样

    另一种降采样的办法是使用pandas的groupby功能。例如,你打算根据月份或星期几进行分组,只需传入一个能够访问时间序列的索引上的这些字段的函数即可

    rng=pd.date_range('1/1/2017',periods=100,freq='D')
    ts=Series(np.arange(100),index=rng)
    ts.groupby(lambda x: x.month).mean()
    
    2017-01-01    0
    2017-01-02    1
    2017-01-03    2
    2017-01-04    3
    2017-01-05    4
    2017-01-06    5
    Freq: D, dtype: int32
    
    ts.groupby(lambda x: x.weekday).mean()
    
    0    50.0
    1    47.5
    2    48.5
    3    49.5
    4    50.5
    5    51.5
    6    49.0
    dtype: float64
    

    升采样和插值

    在将数据从低频率转换到高频率时,就不需要聚合了

    frame=DataFrame(np.random.randn(2,4),
                      index=pd.date_range('1/1/2017',periods=2,freq='W-WED'),
                      columns=['Colorado','Texas','New York','Ohio'])
    frame[:5]
    

    将其重采样到日频率,默认会引入缺失值(与书上结果不同)

    df_daily=frame.resample('D')
    df_daily
    
    DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]
    

    假设你想要用前面的周型值填充“非星期三”。resampling的填充和插值方式跟fillna和reindex的一样

    frame.resample('D',fill_method='ffill')
    
    e:\python\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: fill_method is deprecated to .resample()
    the new syntax is .resample(...).ffill()
      """Entry point for launching an IPython kernel.
    

    这里也可以只填充指定的时期数(目的是限制前面的观测值的持续使用距离)

    frame.resample('D').ffill(limit=2)
    

    注意,新的日期索引完全没必要跟旧的相交

    frame.resample('W-THU').ffill()
    

    通过时期进行重采样

    对那些使用时期索引的数据进行重采样是件非常简单的事情

    frame=DataFrame(np.random.randn(12,4),
                    index=pd.period_range('1-2017','12-2017',freq='M'),
                    columns=['Colorado','Texas','New York','Ohio'])
    frame[:5]
    
    annual_frame=frame.resample('A-DEC').mean()
    annual_frame
    

    升采样要稍微麻烦一些,因为你必须决定在新频率中各区间的哪端用于放置原来的值,就像asfreq方法那样。convention参数默认为'end',可设置为'start'

    annual_frame.resample('Q-DEC').ffill() # Q-DEC: 季度型(每年以12月结束)
    
    annual_frame.resample('Q-DEC',convention='start').ffill()
    

    由于时期指的是时间区间,所以升采样和降采样的规则就比较严格:

    1.在降采样中,目标频率必须是源频率的子时期(subperiod)。

    2.在升采样中,目标频率必须是源频率的超时期(superperiod)。

    如果不满足这些条件,就会引发异常。这主要影响的是按季、年、周计算的频率。例如,由Q-MAR定义的时间区间只能升采样为A-MAR、A-JUN、A-SEP、A-DEC等

    annual_frame.resample('Q-MAR').ffill()
    

    在本章节有些函数舍弃了,比如:resample() is deprecated,the new syntax is .resample(...).mean()。这里使用的是Python3以上的版本练习的。

    相关文章

      网友评论

        本文标题:《利用Python进行数据分析》第10章 时区处理笔记

        本文链接:https://www.haomeiwen.com/subject/zqmigxtx.html