Python 第三方模块 数据分析 Pandas模块 时间对象与时间序列

本文深入探讨了Pandas中关于日期和时间的数据类型,包括时间戳的Null值表示`pd.NaT`、时间戳的创建与转换、时间序列的创建与使用。此外,还讲解了时间序列的重采样、频率转换、时区处理以及日期的移动。着重介绍了如何使用`resample()`进行降采样和升采样,以及`shift()`方法来移动数据。同时,文章还涵盖了日期的固定频率、基础频率、锚点偏移量等概念,以及WOM日期的处理。
摘要由CSDN通过智能技术生成

一.日期和时间数据类型
1.相关模块:

参见 Python.内置模块.时间 部分

2.时间戳的Null值:

Pandas中用pd.NaT(Not a Time)表示时间戳数据的Null值:
>>> pd.NaT
NaT
>>> pd.to_datetime(['2011-07-06 12:00:00','2011-08-06 00:00:00',None,pd.NaT,"NaT",np.nan,""])
DatetimeIndex(['2011-07-06 12:00:00', '2011-08-06 00:00:00', 'NaT', 'NaT',
               'NaT', 'NaT', 'NaT'],
              dtype='datetime64[ns]', freq=None)

二.时间戳及以时间戳为索引的时间序列
1.时间戳
(1)概念:

参见 Python.内置模块.时间..1 部分

(2)创建:

pd.Timestamp([ts_input=None,freq=None,tz=None,unit=None,year=None,month=None,day=None,hour=0,minute=0,second=0,microsecond=0,nanosecond=0,tzinfo=None,fold=None])
  #参数说明:
  	ts_input:指定时间点;为datetime-like/str/num
  	freq:指定频率;str/DateOffset
  	tz:指定时区;str/pytz.timezone/dateutil.tz.tzfile/None
  	year,month,day,hour,minute,second,microsecond,nanosecond:分别指定年//////毫秒/纳秒;int

#实例:
>>> pd.Timestamp(ts_input="2001/01/01")
Timestamp('2001-01-01 00:00:00')

(3)函数:

转换为时期:<t>.to_period([freq=None,copy=True])
  #参数说明:
    t:指定时间戳;为pandas._libs.tslibs.timestamps.Timestamp
    freq:指定频率;str,默认为<t>的频率

#实例:
>>> pd.date_range('2000-01-01',periods=3,freq='M').to_period()
PeriodIndex(['2000-01', '2000-02', '2000-03'], dtype='period[M]', freq='M')
>>> pd.date_range('2000-01-01',periods=3,freq='M').to_period("D")
PeriodIndex(['2000-01-31', '2000-02-29', '2000-03-31'], dtype='period[D]', freq='D')

######################################################################################################################

格式化日期时间:<t>.apply(lambda x:datetime.datetime.strftime(x,"<format>"))
  #参数说明:
    format:指定输出格式;str

#实例:
>>> import datetime
>>> dts=pd.Series(["2020-02-22 14:01:23.451000","2020-02-20 16:40:56.190000"])
>>> dtst=pd.to_datetime(dts)
>>> dtst
0   2020-02-22 14:01:23.451
1   2020-02-20 16:40:56.190
dtype: datetime64[ns]
>>> dtst.apply(lambda x:datetime.datetime.strftime(x,"%Y-%m-%d"))
0    2020-02-22
1    2020-02-20
dtype: object

######################################################################################################################

获取秒:<t>.dt.second
获取分:<t>.dt.minute
获取时:<t>.dt.hour
获取日:<t>.dt.day
获取星期几:<t>.dt.weekday
获取月:<t>.dt.month
获取年:<t>.dt.year

#实例:接上
>>> dtst.dt.second
0    23
1    56
dtype: int64
>>> dtst.dt.minute
0     1
1    40
dtype: int64
>>> dtst.dt.hour
0    14
1    16
dtype: int64
>>> dtst.dt.day
0    22
1    20
dtype: int64
>>> dtst.dt.weekday
0    5
1    3
dtype: int64
>>> dtst.dt.month
0    2
1    2
dtype: int64
>>> dtst.dt.year
0    2020
1    2020
dtype: int64

2.时间序列
(1)概念:

"时间序列"(Time Series)1种重要的结构化数据形式.在多个时间点观测到的任何数据都可以形成一段时间序列.最简单常用的时间序列是以时间
戳为索引的Series/DataFrame.下面以Series为例,DataFrame与之相同

(2)创建:

这样的Series的index为DatetimeIndex,index中的每个元素均为Timestamp:
>>> 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=pd.Series(np.random.randn(6),index=dates)
>>> ts
2011-01-02   -0.547157
2011-01-05    0.097721
2011-01-07   -0.535814
2011-01-08    0.294756
2011-01-10   -0.276985
2011-01-12    0.212698
dtype: float64
>>> ts.index
DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08',
               '2011-01-10', '2011-01-12'],
              dtype='datetime64[ns]', freq=None)
>>> ts.index.dtype
dtype('<M8[ns]')
>>> ts.index[0]
Timestamp('2011-01-02 00:00:00')

(3)使用:

可以使用时间戳str/datetime.datetime/int进行索引/切片:
>>> ts[0]
-0.5471567700646004
>>> ts[ts.index[0]]
-0.5471567700646004
>>> ts["2011-01-02"]
-0.5471567700646004
>>> ts["20110102"]
-0.5471567700646004
>>> ts["20110103":]#时间戳不需要存在于该时间序列中
2011-01-05    0.097721
2011-01-07   -0.535814
2011-01-08    0.294756
2011-01-10   -0.276985
2011-01-12    0.212698
dtype: float64
>>> ts["2011/01/02"]
-0.5471567700646004
>>> ts["01/02.2011"]
-0.5471567700646004
>>> ts["01/02/2011"]
-0.5471567700646004
>>> ts["01.02.2011"]
-0.5471567700646004
>>> ts[datetime.datetime(2011,1,2)]
-0.5471567700646004
还可以用只指定年或年月的字符串进行索引/切片
>>> ts["2011"]
2011-01-02   -0.547157
2011-01-05    0.097721
2011-01-07   -0.535814
2011-01-08    0.294756
2011-01-10   -0.276985
2011-01-12    0.212698
dtype: float64
>>> ts["2011-01"]
2011-01-02   -0.547157
2011-01-05    0.097721
2011-01-07   -0.535814
2011-01-08    0.294756
2011-01-10   -0.276985
2011-01-12    0.212698
dtype: float64
>>> ts["2011":]
2011-01-02   -0.547157
2011-01-05    0.097721
2011-01-07   -0.535814
2011-01-08    0.294756
2011-01-10   -0.276985
2011-01-12    0.212698
dtype: float64
通过切片产生的是视图,因此对通过切片得到的Series的修改也会反映在原Series上:
>>> ts2=ts["2011/01/10":]
>>> ts2[0]=1111111111111111111111
>>> ts
2011-01-02   -5.471568e-01
2011-01-05    9.772118e-02
2011-01-07   -5.358138e-01
2011-01-08    2.947563e-01
2011-01-10    1.111111e+21
2011-01-12    2.126976e-01
dtype: float64
如果2个时间序列的时区不同,则合并的结果是UTC:
>>> ts1=ts.tz_localize('Europe/London')
>>> ts2=ts1.tz_convert('Europe/Moscow')
>>> (ts1+ts2).index
DatetimeIndex(['2011-01-02 00:00:00+00:00', '2011-01-05 00:00:00+00:00',
               '2011-01-07 00:00:00+00:00', '2011-01-08 00:00:00+00:00',
               '2011-01-10 00:00:00+00:00', '2011-01-12 00:00:00+00:00'],
              dtype='datetime64[ns, UTC]', freq=None)

(4)带有重复索引的时间序列:

>>> dates=pd.DatetimeIndex(['1/1/2000','1/2/2000','1/2/2000','1/2/2000','1/3/2000'])
>>> ts=pd.Series(np.arange(5),index=dates)
>>> ts.index.is_unique
False
索引时可能得到标量值或Series:
>>> ts["20000102"]
2000-01-02    1
2000-01-02    2
2000-01-02    3
dtype: int32
>>> ts["20000103"]
4
可以通过<S>.groupby()进行聚合:
>>> ts=ts.groupby(level=0)
>>> ts.mean()
2000-01-01    0
2000-01-02    2
2000-01-03    4
dtype: int32

(5)填充缺失值:

通过ffill插值来填充缺失值:<ts>.ffill([axis=None,inplace=False,limit=None,downcast=None])

#实例:
>>> ts=pd.Series(np.random.randn(5),index=pd.date_range('1/1/2000',periods=5,freq='M'))
>>> ts[1:4]=None
>>> ts.ffill()
2000-01-31    1.171863
2000-02-29    1.171863
2000-03-31    1.171863
2000-04-30    1.171863
2000-05-31    0.502951
Freq: M, dtype: float64
>>> ts.ffill(limit=2)
2000-01-31    1.171863
2000-02-29    1.171863
2000-03-31    1.171863
2000-04-30         NaN
2000-05-31    0.502951
Freq: M, dtype: float64

三.日期的频率及移动
1.固定频率的时间序列:

Pandas中的原生时间序列是不规则的,或者说没有固定的频率.但实际业务中常需要按固定的频率进行分析,而这会在时间序列中引入缺失值.因此需要
将原生时间序列转换为具有固定频率的时间序列.通过<ts>.resample()来实现(详情参见 5 部分):
>>> ts=pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2000',periods=1000))
>>> ts
2000-01-01    0.014314
2000-01-02   -0.795310
2000-01-03    2.187410
2000-01-04    0.333970
2000-01-05    0.860134
                ...
2002-09-22    1.099824
2002-09-23    1.134697
2002-09-24    0.965782
2002-09-25   -1.523675
2002-09-26   -1.877816
Freq: D, Length: 1000, dtype: float64
>>> tsr=ts.resample('D')#转换成频率为1/day的时间序列
>>> i=0
>>> for j in tsr:
...     if not i:
...         print(j)
...         i+=1
...
(Timestamp('2000-01-01 00:00:00', freq='D'), 2000-01-01    0.014314
Freq: D, dtype: float64)

2.基础频率:

Pandas中的频率由1个基础频率(Base Frequency)1个乘数组成.基础频率通常用1个不区分大小写的str别名表示,"M"表示每月/"H"表示每小
时.每个基础频率都与1个称为"日期偏移量"(Date Offset)的对象相对应,"H"型频率可用pandas.tseries.offsets.Hour对象表示:
>>> from pandas.tseries.offsets import Hour,Minute,MonthEnd
>>> import datetime
>>> hour=Hour()
>>> hour
<Hour>
在创建日期偏移量对象时传入1int即可定义乘数:
>>> four_hours=Hour(4)
>>> four_hours
<4 * Hours>
一般来说无需显式创建这样的对象,只需使用"H"/"4H"这样的别名即可.在基础频率的别名前加上1int即可定义乘数:
>>> pd.date_range('2000-01-01','2000-01-03 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')
也可以使用不同的别名和乘数进行组合:
>>> pd.date_range('2000-01-01','2000-01-01 11:00',freq='2h10t')
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 02:10:00',
               '2000-01-01 04:20:00', '2000-01-01 06:30:00',
               '2000-01-01 08:40:00', '2000-01-01 10:50:00'],
              dtype='datetime64[ns]', freq='130T')
日期偏移量对象可进行加法运算,也可和时间戳对象/日期时间对象进行加法:
>>> Hour(2)+Minute(30)
<150 * Minutes>
>>> offset=MonthEnd()
>>> now=datetime.datetime(2021,1,30)
>>> offset+now
Timestamp('2021-01-31 00:00:00')
时间戳对象/日期时间对象可减去日期偏移量对象:
>>> now-offset
Timestamp('2020-12-31 00:00:00')
>>> (now-offset)-offset
Timestamp('2020-11-30 00:00:00')
使用日期偏移量对象的rollback()/rollforward()方法可控制日期滚动的方向:
>>> offset.rollback(now)#向前滚动到每月的最后1天
Timestamp('2020-12-31 00:00:00')
>>> offset.rollforward(now)#向后滚动到每月的最后1天
Timestamp('2021-01-31 00:00:00')
有些基础频率对象所描述的时间点并不是均匀分隔的,称为"锚点偏移量"(Anchored Offset),"M"/"BM"

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.WOM日期:

"WOM日期"(Week Of Month)1种非常实用的频率类.它以WOM开头,使用户能获得诸如"每月第3个星期五"这样的日期:
>>> w=pd.date_range('2012-01-01','2012-09-01',freq='WOM-3FRI')
>>> list(w)
[Timestamp('2012-01-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-02-17 00:00:00', freq='WOM-3FRI'), Timestamp('2012-03-16 00:00:00', freq='WOM-3FRI'), Timestamp('2012-04-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-05-18 00:00:00', freq='WOM-3FRI'), Timestamp('2012-06-15 00:00:00', freq='WOM-3FRI'), Timestamp('2012-07-20 00:00:00', freq='WOM-3FRI'), Timestamp('2012-08-17 00:00:00', freq='WOM-3FRI')]

4.日期的移动:

将数据沿时间轴移动<ts>.shift([periods=1,freq=None,axis=0,fill_value=None])
  #参数说明:
  	periods:指定移动几个周期;int
  	  #周期由freq决定,默认移动到其他索引处
  	freq:指定数据的频率;str/DateOffset/tseries.offsets/timedelta
  	  #指定频率后可以连同索引一起移动,而不是只移动数据

#实例:
>>> ts=pd.Series(np.random.randn(4),index=pd.date_range('1/1/2000',periods=4,freq='M'))
>>> ts
2000-01-31   -0.657145
2000-02-29    0.213665
2000-03-31    0.888562
2000-04-30    0.323581
Freq: M, dtype: float64
>>> ts.shift()
2000-01-31         NaN
2000-02-29   -0.657145
2000-03-31    0.213665
2000-04-30    0.888562
Freq: M, dtype: float64
>>> ts.shift(-1,fill_value=9999)
2000-01-31       0.213665
2000-02-29       0.888562
2000-03-31       0.323581
2000-04-30    9999.000000
Freq: M, dtype: float64
>>> ts.shift(1,freq="M")
2000-02-29   -0.657145
2000-03-31    0.213665
2000-04-30    0.888562
2000-05-31    0.323581
Freq: M, dtype: float64
>>> ts.shift(1,freq="D")
2000-02-01   -0.657145
2000-03-01    0.213665
2000-04-01    0.888562
2000-05-01    0.323581
dtype: float64

5.重采样
(1)概念:

"重采样"(Resampling)是指将时间序列从1个频率转换到另1个频率的过程.将高频数据聚合到低频称为"降采样"(Downsampling),而将低频数据转
换到高频则称为"升采样"(Upsampling).并非所有重采样都能被划分到这2类中,例如将W-WED转换为W-FRI既非降采样也非升采样

注意:时期对象也可重采样,但要求更严格:
①在降采样中,目标频率必须是原频率的"子时期"(Subperiod)
②在升采样中,目标频率必须是原频率的"超时期"(Superperiod)

(2)实现:

进行重采样:<ts>.resample(<rule>[,axis=0,closed=None,label=None,convention="start",kind=None,loffset=None,base=None,on=None,level=None,origin="start_day",offset=None])
  #返回pandas.core.resample.DatetimeIndexResampler
  #注意:升采样时会产生缺失值,需要使用其他方法进行填充
  #参数说明:
  	rule:指定目标转换(转换后的频率);str(见下图)/DateOffset/Timedelta
  	closed:指定区间的哪侧是闭合的;'right'/'left'
  	  #对频率'M'/'A'/'Q'/'BM'/'BA'/'BQ'/'W',默认为'right';对其他频率,默认为'right'
  	label:指定使用区间的哪侧作为标签;'right'/'left'
  	  #对频率'M'/'A'/'Q'/'BM'/'BA'/'BQ'/'W',默认为'right';对其他频率,默认为'right'
  	convention:指定升采样时原值放在哪侧;'start'/'s''end'/'e'
  	loffset:指定1个标签的时间偏移量;为timedelta
  	  #标签会在原标签的基础上进行偏移,以便于明白时间戳表示的是哪个区间;强烈不建议使用

#实例:接上
>>> ts=pd.Series(np.random.randn(20),index=pd.date_range('1/1/2000',periods=20,freq='M'))
>>> list(ts.resample("D"))
[(Timestamp('2000-01-31 00:00:00', freq='D'), 2000-01-31   -1.091545
Freq: M, dtype: float64)...(Timestamp('2001-08-31 00:00:00', freq='D'), 2001-08-31    1.705509
Freq: M, dtype: float64)]
>>> list(ts.resample("A-JAN"))
[(Timestamp('2000-01-31 00:00:00', freq='A-JAN'), 2000-01-31   -1.091545
Freq: M, dtype: float64)...(Timestamp('2002-01-31 00:00:00', freq='A-JAN'), 2001-02-28   -0.414356
2001-03-31    0.606156
2001-04-30    0.634820
2001-05-31   -0.044379
2001-06-30    0.891806
2001-07-31   -1.628353
2001-08-31    1.705509
Freq: M, dtype: float64)]
>>> list(ts.resample("A-JAN",label="left"))
[(Timestamp('1999-01-31 00:00:00', freq='A-JAN'), 2000-01-31   -1.091545
Freq: M, dtype: float64)...(Timestamp('2001-01-31 00:00:00', freq='A-JAN'), 2001-02-28   -0.414356
2001-03-31    0.606156
2001-04-30    0.634820
2001-05-31   -0.044379
2001-06-30    0.891806
2001-07-31   -1.628353
2001-08-31    1.705509
Freq: M, dtype: float64)]
>>> list(ts.resample("A-JAN",closed="left"))
[(Timestamp('2001-01-31 00:00:00', freq='A-JAN'), 2000-01-31   -1.091545
2000-02-29    0.549390
2000-03-31    1.590489
2000-04-30   -1.307500
2000-05-31   -1.616338
2000-06-30   -0.059134
2000-07-31    0.520718
2000-08-31    0.074347
2000-09-30    0.702702
2000-10-31    0.067281
2000-11-30   -1.099831
2000-12-31    0.382498
Freq: M, dtype: float64), (Timestamp('2002-01-31 00:00:00', freq='A-JAN'), 2001-01-31   -1.197313
2001-02-28   -0.414356
2001-03-31    0.606156
2001-04-30    0.634820
2001-05-31   -0.044379
2001-06-30    0.891806
2001-07-31   -1.628353
2001-08-31    1.705509
Freq: M, dtype: float64)]

(3)OHLC重采样:

>>> ts.resample("A-JAN").ohlc()
                open      high       low     close#分别表示期间中开始/最高/最低/结束时的值
2000-01-31 -1.091545 -1.091545 -1.091545 -1.091545
2001-01-31  0.549390  1.590489 -1.616338 -1.197313
2002-01-31 -0.414356  1.705509 -1.628353  1.705509

四.时区的处理

将无时区时间序列转换到指定时区:<ts>.tz_localize(<tz>[,axis=0,level=None,copy=True,ambiguous="raise",nonexistent="raise"])
  #参数说明:
    ts:指定时间序列;为Series/DataFrame/DatetimeIndex/Timestamp
	tz:指定时区;str/tzinfo

#实例:接 三.4 部分
>>> tsl=ts.tz_localize("UTC")
>>> tsl
2000-01-31 00:00:00+00:00    0.005343
2000-02-29 00:00:00+00:00   -1.224921
2000-03-31 00:00:00+00:00    1.107894
2000-04-30 00:00:00+00:00    0.231661
Freq: M, dtype: float64
>>> tsl.index.tz
<UTC>

######################################################################################################################

将有时区时间序列转换到指定时区:<ts>.tz_convert(<tz>[,axis=0,level=None,copy=True])

#实例:接上
>>> tsl.tz_convert("America/New_York")
2000-01-30 19:00:00-05:00    0.005343
2000-02-28 19:00:00-05:00   -1.224921
2000-03-30 19:00:00-05:00    1.107894
2000-04-29 20:00:00-04:00    0.231661
Freq: M, dtype: float64

六.时期及以时期为索引的时间序列
1.创建:

"时期"(Period)表示的是时间区间,2001/01/01-2001/12/312001-2002,在Pandas中使用Period类表示:
pd.Period([value=None,freq=None,ordinal=None,year=None,month=1,quarter=None,day=1,hour=0,minute=0,second=0])
  #参数说明:
    value:指定时期;为Period/str("4Q2005")
    freq:指定频率;str
    ordinal:int
    year,month,quarter,day,hour,minute,second:分别指定年//季度////#实例:
>>> pd.Period()
NaT
>>> pd.Period(value="2Q2020")
Period('2020Q2', 'Q-DEC')
>>> p=pd.Period(freq="A-DEC",year=2012)#表示整个2012年
>>> p
Period('2012', 'A-DEC')

2.运算:

对Period对象加上或减去1int即可实现根据其频率进行位移:
>>> p+1
Period('2013', 'A-DEC')
>>> p-2
Period('2010', 'A-DEC')
如果2个Period对象拥有相同的频率,则它们的差就是它们相差的单位数量:
>>> p-pd.Period(freq="A-DEC",year=2006)
<6 * YearEnds: month=12>
>>> pd.Period(freq="A-DEC",year=2006)-p
<-6 * YearEnds: month=12>

3.日期索引:

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

4.频率转换:

转换频率:<p>.asfreq([freq=None,how="E"])
  #参数说明:
    p:指定日期对象;为Period/PeriodIndex/Series
    freq:指定频率;str
    how:指定使用原日期结尾还是开头;"E"/"End"/"end"/"Finish"/"finish"(结尾)"S"/"start"/"Start"/"Begin"/"begin"(开头)

#实例:接上
>>> p.asfreq("D")
Period('2012-12-31', 'D')
>>> p.asfreq("D","S")
Period('2012-01-01', 'D')

5.转换为时间戳:

将日期对象转换为时间戳:<p>.to_timestamp([freq=None,how="S"])
  #参数说明:
    p:指定日期对象;为Period/PeriodIndex/Series
    freq:指定频率;str/DateOffset
      #若<p>的频率至少为week,则为"D";否则为"S"
    how:指定使用原日期结尾还是开头;"E"/"End"/"end"/"Finish"/"finish"(结尾)"S"/"start"/"Start"/"Begin"/"begin"(开头)

#实例:接上
>>> p.to_timestamp()
Timestamp('2012-01-01 00:00:00')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值