本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
「欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边,抽奖详情见活动文章」
简介
时间应该是在数据处理中经常会用到的一种数据类型,除了Numpy中datetime64 和 timedelta64 这两种数据类型之外,pandas 还整合了其他python库比如 scikits.timeseries
中的功能。
时间分类
pandas中有四种时间类型:
- Date times : 日期和时间,可以带时区。和标准库中的
datetime.datetime
类似。 - Time deltas: 绝对持续时间,和 标准库中的
datetime.timedelta
类似。 - Time spans: 由时间点及其关联的频率定义的时间跨度。
- Date offsets:基于日历计算的时间 和 dateutil.relativedelta.relativedelta 类似。
我们用一张表来表示:
类型 | 标量class | 数组class | pandas数据类型 | 主要创建方法 |
---|---|---|---|---|
Date times | Timestamp |
DatetimeIndex |
datetime64[ns] or datetime64[ns, tz] |
to_datetime or date_range |
Time deltas | Timedelta |
TimedeltaIndex |
timedelta64[ns] |
to_timedelta or timedelta_range |
Time spans | Period |
PeriodIndex |
period[freq] |
Period or period_range |
Date offsets | DateOffset |
None |
None |
DateOffset |
看一个使用的例子:
1 | css复制代码In [19]: pd.Series(range(3), index=pd.date_range("2000", freq="D", periods=3)) |
看一下上面数据类型的空值:
1 | ini复制代码In [24]: pd.Timestamp(pd.NaT) |
Timestamp
Timestamp 是最基础的时间类型,我们可以这样创建:
1 | css复制代码In [28]: pd.Timestamp(datetime.datetime(2012, 5, 1)) |
DatetimeIndex
Timestamp 作为index会自动被转换为DatetimeIndex:
1 | ini复制代码In [33]: dates = [ |
date_range 和 bdate_range
还可以使用 date_range 来创建DatetimeIndex:
1 | css复制代码In [74]: start = datetime.datetime(2011, 1, 1) |
date_range
是日历范围,bdate_range
是工作日范围:
1 | css复制代码In [78]: index = pd.bdate_range(start, end) |
两个方法都可以带上 start
, end
, 和 periods
参数。
1 | ini复制代码In [84]: pd.bdate_range(end=end, periods=20) |
origin
使用 origin
参数,可以修改 DatetimeIndex
的起点:
1 | ini复制代码In [67]: pd.to_datetime([1, 2, 3], unit="D", origin=pd.Timestamp("1960-01-01")) |
默认情况下 origin='unix'
, 也就是起点是 1970-01-01 00:00:00
.
1 | ini复制代码In [68]: pd.to_datetime([1, 2, 3], unit="D") |
格式化
使用format参数可以对时间进行格式化:
1 | perl复制代码In [51]: pd.to_datetime("2010/11/12", format="%Y/%m/%d") |
Period
Period 表示的是一个时间跨度,通常和freq一起使用:
1 | css复制代码In [31]: pd.Period("2011-01") |
Period可以直接进行运算:
1 | less复制代码In [345]: p = pd.Period("2012", freq="A-DEC") |
注意,Period只有具有相同的freq才能进行算数运算。包括 offsets 和 timedelta
1 | less复制代码In [352]: p = pd.Period("2014-07-01 09:00", freq="H") |
Period作为index可以自动被转换为PeriodIndex:
1 | ini复制代码In [38]: periods = [pd.Period("2012-01"), pd.Period("2012-02"), pd.Period("2012-03")] |
可以通过 pd.period_range 方法来创建 PeriodIndex:
1 | css复制代码In [359]: prng = pd.period_range("1/1/2011", "1/1/2012", freq="M") |
还可以通过PeriodIndex直接创建:
1 | css复制代码In [361]: pd.PeriodIndex(["2011-1", "2011-2", "2011-3"], freq="M") |
DateOffset
DateOffset表示的是频率对象。它和Timedelta很类似,表示的是一个持续时间,但是有特殊的日历规则。比如Timedelta一天肯定是24小时,而在 DateOffset中根据夏令时的不同,一天可能会有23,24或者25小时。
1 | ini复制代码# This particular day contains a day light savings time transition |
DateOffsets 和Frequency 运算是先关的,看一下可用的Date Offset 和它相关联的 Frequency:
Date Offset | Frequency String | 描述 |
---|---|---|
DateOffset |
None | 通用的offset 类 |
BDay or BusinessDay |
'B' |
工作日 |
CDay or CustomBusinessDay |
'C' |
自定义的工作日 |
Week |
'W' |
一周 |
WeekOfMonth |
'WOM' |
每个月的第几周的第几天 |
LastWeekOfMonth |
'LWOM' |
每个月最后一周的第几天 |
MonthEnd |
'M' |
日历月末 |
MonthBegin | 'MS' |
日历月初 |
BMonthEnd or BusinessMonthEnd |
'BM' |
营业月底 |
BMonthBegin or BusinessMonthBegin |
'BMS' |
营业月初 |
CBMonthEnd or CustomBusinessMonthEnd |
'CBM' |
自定义营业月底 |
CBMonthBegin or CustomBusinessMonthBegin |
'CBMS' |
自定义营业月初 |
SemiMonthEnd |
'SM' |
日历月末的第15天 |
SemiMonthBegin |
'SMS' |
日历月初的第15天 |
QuarterEnd |
'Q' |
日历季末 |
QuarterBegin |
'QS' |
日历季初 |
BQuarterEnd |
'BQ |
工作季末 |
BQuarterBegin |
'BQS' |
工作季初 |
FY5253Quarter |
'REQ' |
零售季( 52-53 week) |
YearEnd |
'A' |
日历年末 |
YearBegin |
'AS' or 'BYS' |
日历年初 |
BYearEnd |
'BA' |
营业年末 |
BYearBegin |
'BAS' |
营业年初 |
FY5253 |
'RE' |
零售年 (aka 52-53 week) |
Easter |
None | 复活节假期 |
BusinessHour |
'BH' |
business hour |
CustomBusinessHour |
'CBH' |
custom business hour |
Day |
'D' |
一天的绝对时间 |
Hour |
'H' |
一小时 |
Minute |
'T' or 'min' |
一分钟 |
Second |
'S' |
一秒钟 |
Milli |
'L' or 'ms' |
一微妙 |
Micro |
'U' or 'us' |
一毫秒 |
Nano |
'N' |
一纳秒 |
DateOffset还有两个方法 rollforward()
和 rollback()
可以将时间进行移动:
1 | ini复制代码In [153]: ts = pd.Timestamp("2018-01-06 00:00:00") |
上面的操作会自动保存小时,分钟等信息,如果想要设置为 00:00:00 , 可以调用normalize() 方法:
1 | css复制代码In [158]: ts = pd.Timestamp("2014-01-01 09:00") |
作为index
时间可以作为index,并且作为index的时候会有一些很方便的特性。
可以直接使用时间来获取相应的数据:
1 | less复制代码In [99]: ts["1/31/2011"] |
获取全年的数据:
1 | yaml复制代码In [102]: ts["2011"] |
获取某个月的数据:
1 | less复制代码In [103]: ts["2011-6"] |
DF可以接受时间作为loc的参数:
1 | yaml复制代码In [105]: dft |
时间切片:
1 | yaml复制代码In [107]: dft["2013-1":"2013-2"] |
切片和完全匹配
考虑下面的一个精度为分的Series对象:
1 | css复制代码In [120]: series_minute = pd.Series( |
时间精度小于分的话,返回的是一个Series对象:
1 | less复制代码In [122]: series_minute["2011-12-31 23"] |
时间精度大于分的话,返回的是一个常量:
1 | less复制代码In [123]: series_minute["2011-12-31 23:59"] |
同样的,如果精度为秒的话,小于秒会返回一个对象,等于秒会返回常量值。
时间序列的操作
Shifting
使用shift方法可以让 time series 进行相应的移动:
1 | ini复制代码In [275]: ts = pd.Series(range(len(rng)), index=rng) |
通过指定 freq , 可以设置shift的方式:
1 | ini复制代码In [278]: ts.shift(5, freq="D") |
频率转换
时间序列可以通过调用 asfreq 的方法转换其频率:
1 | yaml复制代码In [281]: dr = pd.date_range("1/1/2010", periods=3, freq=3 * pd.offsets.BDay()) |
asfreq还可以指定修改频率过后的填充方法:
1 | yaml复制代码In [285]: ts.asfreq(pd.offsets.BDay(), method="pad") |
Resampling 重新取样
给定的时间序列可以通过调用resample方法来重新取样:
1 | css复制代码In [286]: rng = pd.date_range("1/1/2012", periods=100, freq="S") |
resample 可以接受各类统计方法,比如: sum
, mean
, std
, sem
, max
, min
, median
, first
, last
, ohlc
。
1 | css复制代码In [289]: ts.resample("5Min").mean() |
本文已收录于 www.flydean.com/15-python-p…
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
本文转载自: 掘金