文章目录

  • 简介
  • 时间分类
  • Timestamp
    • DatetimeIndex
    • date_range 和 bdate_range
    • `origin`
    • 格式化
  • Period
  • DateOffset
  • 作为index
    • 切片和完全匹配
  • 时间序列的操作
    • Shifting
    • 频率转换
  • Resampling 重新取样

简介

时间应该是在数据处理中经常会用到的一种数据类型,除了Numpy中datetime64 和 timedelta64 这两种数据类型之外,pandas 还整合了其他python库比如 scikits.timeseries 中的功能。

时间分类

pandas中有四种时间类型:

  1. Date times : 日期和时间,可以带时区。和标准库中的 datetime.datetime 类似。
  2. Time deltas: 绝对持续时间,和 标准库中的 datetime.timedelta 类似。
  3. Time spans: 由时间点及其关联的频率定义的时间跨度。
  4. 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

看一个使用的例子:

In [19]: pd.Series(range(3), index=pd.date_range("2000", freq="D", periods=3))
Out[19]:
2000-01-01    0
2000-01-02    1
2000-01-03    2
Freq: D, dtype: int64

看一下上面数据类型的空值:

In [24]: pd.Timestamp(pd.NaT)
Out[24]: NaTIn [25]: pd.Timedelta(pd.NaT)
Out[25]: NaTIn [26]: pd.Period(pd.NaT)
Out[26]: NaT# Equality acts as np.nan would
In [27]: pd.NaT == pd.NaT
Out[27]: False

Timestamp

Timestamp 是最基础的时间类型,我们可以这样创建:

In [28]: pd.Timestamp(datetime.datetime(2012, 5, 1))
Out[28]: Timestamp('2012-05-01 00:00:00')In [29]: pd.Timestamp("2012-05-01")
Out[29]: Timestamp('2012-05-01 00:00:00')In [30]: pd.Timestamp(2012, 5, 1)
Out[30]: Timestamp('2012-05-01 00:00:00')

DatetimeIndex

Timestamp 作为index会自动被转换为DatetimeIndex:

In [33]: dates = [....:     pd.Timestamp("2012-05-01"),....:     pd.Timestamp("2012-05-02"),....:     pd.Timestamp("2012-05-03"),....: ]....: In [34]: ts = pd.Series(np.random.randn(3), dates)In [35]: type(ts.index)
Out[35]: pandas.core.indexes.datetimes.DatetimeIndexIn [36]: ts.index
Out[36]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns]', freq=None)In [37]: ts
Out[37]:
2012-05-01    0.469112
2012-05-02   -0.282863
2012-05-03   -1.509059
dtype: float64

date_range 和 bdate_range

还可以使用 date_range 来创建DatetimeIndex:

In [74]: start = datetime.datetime(2011, 1, 1)In [75]: end = datetime.datetime(2012, 1, 1)In [76]: index = pd.date_range(start, end)In [77]: index
Out[77]:
DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05', '2011-01-06', '2011-01-07', '2011-01-08','2011-01-09', '2011-01-10',...'2011-12-23', '2011-12-24', '2011-12-25', '2011-12-26','2011-12-27', '2011-12-28', '2011-12-29', '2011-12-30','2011-12-31', '2012-01-01'],dtype='datetime64[ns]', length=366, freq='D')

date_range 是日历范围,bdate_range 是工作日范围:

In [78]: index = pd.bdate_range(start, end)In [79]: index
Out[79]:
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06','2011-01-07', '2011-01-10', '2011-01-11', '2011-01-12','2011-01-13', '2011-01-14',...'2011-12-19', '2011-12-20', '2011-12-21', '2011-12-22','2011-12-23', '2011-12-26', '2011-12-27', '2011-12-28','2011-12-29', '2011-12-30'],dtype='datetime64[ns]', length=260, freq='B')

两个方法都可以带上 start, end, 和 periods参数。

In [84]: pd.bdate_range(end=end, periods=20)
In [83]: pd.date_range(start, end, freq="W")
In [86]: pd.date_range("2018-01-01", "2018-01-05", periods=5)

origin

使用 origin参数,可以修改 DatetimeIndex 的起点:

In [67]: pd.to_datetime([1, 2, 3], unit="D", origin=pd.Timestamp("1960-01-01"))
Out[67]: DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns]', freq=None)

默认情况下 origin='unix', 也就是起点是 1970-01-01 00:00:00.

In [68]: pd.to_datetime([1, 2, 3], unit="D")
Out[68]: DatetimeIndex(['1970-01-02', '1970-01-03', '1970-01-04'], dtype='datetime64[ns]', freq=None)

格式化

使用format参数可以对时间进行格式化:

In [51]: pd.to_datetime("2010/11/12", format="%Y/%m/%d")
Out[51]: Timestamp('2010-11-12 00:00:00')In [52]: pd.to_datetime("12-11-2010 00:00", format="%d-%m-%Y %H:%M")
Out[52]: Timestamp('2010-11-12 00:00:00')

Period

Period 表示的是一个时间跨度,通常和freq一起使用:

In [31]: pd.Period("2011-01")
Out[31]: Period('2011-01', 'M')In [32]: pd.Period("2012-05", freq="D")
Out[32]: Period('2012-05-01', 'D')

Period可以直接进行运算:

In [345]: p = pd.Period("2012", freq="A-DEC")In [346]: p + 1
Out[346]: Period('2013', 'A-DEC')In [347]: p - 3
Out[347]: Period('2009', 'A-DEC')In [348]: p = pd.Period("2012-01", freq="2M")In [349]: p + 2
Out[349]: Period('2012-05', '2M')In [350]: p - 1
Out[350]: Period('2011-11', '2M')

注意,Period只有具有相同的freq才能进行算数运算。包括 offsets 和 timedelta

In [352]: p = pd.Period("2014-07-01 09:00", freq="H")In [353]: p + pd.offsets.Hour(2)
Out[353]: Period('2014-07-01 11:00', 'H')In [354]: p + datetime.timedelta(minutes=120)
Out[354]: Period('2014-07-01 11:00', 'H')In [355]: p + np.timedelta64(7200, "s")
Out[355]: Period('2014-07-01 11:00', 'H')

Period作为index可以自动被转换为PeriodIndex:

In [38]: periods = [pd.Period("2012-01"), pd.Period("2012-02"), pd.Period("2012-03")]In [39]: ts = pd.Series(np.random.randn(3), periods)In [40]: type(ts.index)
Out[40]: pandas.core.indexes.period.PeriodIndexIn [41]: ts.index
Out[41]: PeriodIndex(['2012-01', '2012-02', '2012-03'], dtype='period[M]', freq='M')In [42]: ts
Out[42]:
2012-01   -1.135632
2012-02    1.212112
2012-03   -0.173215
Freq: M, dtype: float64

可以通过 pd.period_range 方法来创建 PeriodIndex:

In [359]: prng = pd.period_range("1/1/2011", "1/1/2012", freq="M")In [360]: prng
Out[360]:
PeriodIndex(['2011-01', '2011-02', '2011-03', '2011-04', '2011-05', '2011-06','2011-07', '2011-08', '2011-09', '2011-10', '2011-11', '2011-12','2012-01'],dtype='period[M]', freq='M')

还可以通过PeriodIndex直接创建:

In [361]: pd.PeriodIndex(["2011-1", "2011-2", "2011-3"], freq="M")
Out[361]: PeriodIndex(['2011-01', '2011-02', '2011-03'], dtype='period[M]', freq='M')

DateOffset

DateOffset表示的是频率对象。它和Timedelta很类似,表示的是一个持续时间,但是有特殊的日历规则。比如Timedelta一天肯定是24小时,而在 DateOffset中根据夏令时的不同,一天可能会有23,24或者25小时。

# This particular day contains a day light savings time transition
In [144]: ts = pd.Timestamp("2016-10-30 00:00:00", tz="Europe/Helsinki")# Respects absolute time
In [145]: ts + pd.Timedelta(days=1)
Out[145]: Timestamp('2016-10-30 23:00:00+0200', tz='Europe/Helsinki')# Respects calendar time
In [146]: ts + pd.DateOffset(days=1)
Out[146]: Timestamp('2016-10-31 00:00:00+0200', tz='Europe/Helsinki')In [147]: friday = pd.Timestamp("2018-01-05")In [148]: friday.day_name()
Out[148]: 'Friday'# Add 2 business days (Friday --> Tuesday)
In [149]: two_business_days = 2 * pd.offsets.BDay()In [150]: two_business_days.apply(friday)
Out[150]: Timestamp('2018-01-09 00:00:00')In [151]: friday + two_business_days
Out[151]: Timestamp('2018-01-09 00:00:00')In [152]: (friday + two_business_days).day_name()
Out[152]: 'Tuesday'

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() 可以将时间进行移动:

In [153]: ts = pd.Timestamp("2018-01-06 00:00:00")In [154]: ts.day_name()
Out[154]: 'Saturday'# BusinessHour's valid offset dates are Monday through Friday
In [155]: offset = pd.offsets.BusinessHour(start="09:00")# Bring the date to the closest offset date (Monday)
In [156]: offset.rollforward(ts)
Out[156]: Timestamp('2018-01-08 09:00:00')# Date is brought to the closest offset date first and then the hour is added
In [157]: ts + offset
Out[157]: Timestamp('2018-01-08 10:00:00')

上面的操作会自动保存小时,分钟等信息,如果想要设置为 00:00:00 , 可以调用normalize() 方法:

In [158]: ts = pd.Timestamp("2014-01-01 09:00")In [159]: day = pd.offsets.Day()In [160]: day.apply(ts)
Out[160]: Timestamp('2014-01-02 09:00:00')In [161]: day.apply(ts).normalize()
Out[161]: Timestamp('2014-01-02 00:00:00')In [162]: ts = pd.Timestamp("2014-01-01 22:00")In [163]: hour = pd.offsets.Hour()In [164]: hour.apply(ts)
Out[164]: Timestamp('2014-01-01 23:00:00')In [165]: hour.apply(ts).normalize()
Out[165]: Timestamp('2014-01-01 00:00:00')In [166]: hour.apply(pd.Timestamp("2014-01-01 23:30")).normalize()
Out[166]: Timestamp('2014-01-02 00:00:00')

作为index

时间可以作为index,并且作为index的时候会有一些很方便的特性。

可以直接使用时间来获取相应的数据:

In [99]: ts["1/31/2011"]
Out[99]: 0.11920871129693428In [100]: ts[datetime.datetime(2011, 12, 25):]
Out[100]:
2011-12-30    0.56702
Freq: BM, dtype: float64In [101]: ts["10/31/2011":"12/31/2011"]
Out[101]:
2011-10-31    0.271860
2011-11-30   -0.424972
2011-12-30    0.567020
Freq: BM, dtype: float64

获取全年的数据:

In [102]: ts["2011"]
Out[102]:
2011-01-31    0.119209
2011-02-28   -1.044236
2011-03-31   -0.861849
2011-04-29   -2.104569
2011-05-31   -0.494929
2011-06-30    1.071804
2011-07-29    0.721555
2011-08-31   -0.706771
2011-09-30   -1.039575
2011-10-31    0.271860
2011-11-30   -0.424972
2011-12-30    0.567020
Freq: BM, dtype: float64

获取某个月的数据:

In [103]: ts["2011-6"]
Out[103]:
2011-06-30    1.071804
Freq: BM, dtype: float64

DF可以接受时间作为loc的参数:

In [105]: dft
Out[105]: A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-03-11 10:35:00 -0.747967
2013-03-11 10:36:00 -0.034523
2013-03-11 10:37:00 -0.201754
2013-03-11 10:38:00 -1.509067
2013-03-11 10:39:00 -1.693043[100000 rows x 1 columns]In [106]: dft.loc["2013"]
Out[106]: A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-03-11 10:35:00 -0.747967
2013-03-11 10:36:00 -0.034523
2013-03-11 10:37:00 -0.201754
2013-03-11 10:38:00 -1.509067
2013-03-11 10:39:00 -1.693043[100000 rows x 1 columns]

时间切片:

In [107]: dft["2013-1":"2013-2"]
Out[107]: A
2013-01-01 00:00:00  0.276232
2013-01-01 00:01:00 -1.087401
2013-01-01 00:02:00 -0.673690
2013-01-01 00:03:00  0.113648
2013-01-01 00:04:00 -1.478427
...                       ...
2013-02-28 23:55:00  0.850929
2013-02-28 23:56:00  0.976712
2013-02-28 23:57:00 -2.693884
2013-02-28 23:58:00 -1.575535
2013-02-28 23:59:00 -1.573517[84960 rows x 1 columns]

切片和完全匹配

考虑下面的一个精度为分的Series对象:

In [120]: series_minute = pd.Series(.....:     [1, 2, 3],.....:     pd.DatetimeIndex(.....:         ["2011-12-31 23:59:00", "2012-01-01 00:00:00", "2012-01-01 00:02:00"].....:     ),.....: ).....: In [121]: series_minute.index.resolution
Out[121]: 'minute'

时间精度小于分的话,返回的是一个Series对象:

In [122]: series_minute["2011-12-31 23"]
Out[122]:
2011-12-31 23:59:00    1
dtype: int64

时间精度大于分的话,返回的是一个常量:

In [123]: series_minute["2011-12-31 23:59"]
Out[123]: 1In [124]: series_minute["2011-12-31 23:59:00"]
Out[124]: 1

同样的,如果精度为秒的话,小于秒会返回一个对象,等于秒会返回常量值。

时间序列的操作

Shifting

使用shift方法可以让 time series 进行相应的移动:

In [275]: ts = pd.Series(range(len(rng)), index=rng)In [276]: ts = ts[:5]In [277]: ts.shift(1)
Out[277]:
2012-01-01    NaN
2012-01-02    0.0
2012-01-03    1.0
Freq: D, dtype: float64

通过指定 freq , 可以设置shift的方式:

In [278]: ts.shift(5, freq="D")
Out[278]:
2012-01-06    0
2012-01-07    1
2012-01-08    2
Freq: D, dtype: int64In [279]: ts.shift(5, freq=pd.offsets.BDay())
Out[279]:
2012-01-06    0
2012-01-09    1
2012-01-10    2
dtype: int64In [280]: ts.shift(5, freq="BM")
Out[280]:
2012-05-31    0
2012-05-31    1
2012-05-31    2
dtype: int64

频率转换

时间序列可以通过调用 asfreq 的方法转换其频率:

In [281]: dr = pd.date_range("1/1/2010", periods=3, freq=3 * pd.offsets.BDay())In [282]: ts = pd.Series(np.random.randn(3), index=dr)In [283]: ts
Out[283]:
2010-01-01    1.494522
2010-01-06   -0.778425
2010-01-11   -0.253355
Freq: 3B, dtype: float64In [284]: ts.asfreq(pd.offsets.BDay())
Out[284]:
2010-01-01    1.494522
2010-01-04         NaN
2010-01-05         NaN
2010-01-06   -0.778425
2010-01-07         NaN
2010-01-08         NaN
2010-01-11   -0.253355
Freq: B, dtype: float64

asfreq还可以指定修改频率过后的填充方法:

In [285]: ts.asfreq(pd.offsets.BDay(), method="pad")
Out[285]:
2010-01-01    1.494522
2010-01-04    1.494522
2010-01-05    1.494522
2010-01-06   -0.778425
2010-01-07   -0.778425
2010-01-08   -0.778425
2010-01-11   -0.253355
Freq: B, dtype: float64

Resampling 重新取样

给定的时间序列可以通过调用resample方法来重新取样:

In [286]: rng = pd.date_range("1/1/2012", periods=100, freq="S")In [287]: ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)In [288]: ts.resample("5Min").sum()
Out[288]:
2012-01-01    25103
Freq: 5T, dtype: int64

resample 可以接受各类统计方法,比如: sum, mean, std, sem, max, min, median, first, last, ohlc

In [289]: ts.resample("5Min").mean()
Out[289]:
2012-01-01    251.03
Freq: 5T, dtype: float64In [290]: ts.resample("5Min").ohlc()
Out[290]: open  high  low  close
2012-01-01   308   460    9    205In [291]: ts.resample("5Min").max()
Out[291]:
2012-01-01    460
Freq: 5T, dtype: int64

本文已收录于 http://www.flydean.com/15-python-pandas-time/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

Pandas高级教程之:时间处理相关推荐

  1. Pandas高级教程之:plot画图详解

    文章目录 简介 基础画图 其他图像 bar stacked bar barh Histograms box Area Scatter Hexagonal bin Pie 在画图中处理NaN数据 其他作 ...

  2. Pandas高级教程之:处理缺失数据

    文章目录 简介 NaN的例子 整数类型的缺失值 Datetimes 类型的缺失值 None 和 np.nan 的转换 缺失值的计算 使用fillna填充NaN数据 使用dropna删除包含NA的数据 ...

  3. Pandas高级教程之:GroupBy用法

    文章目录 简介 分割数据 多index get_group dropna groups属性 index的层级 group的遍历 聚合操作 通用聚合方法 同时使用多个聚合方法 NamedAgg 不同的列 ...

  4. Pandas高级教程之:统计方法

    文章目录 简介 变动百分百 Covariance协方差 Correlation相关系数 rank等级 简介 数据分析中经常会用到很多统计类的方法,本文将会介绍Pandas中使用到的统计方法. 变动百分 ...

  5. Pandas高级教程之:category数据类型

    文章目录 简介 创建category 使用Series创建 使用DF创建 创建控制 转换为原始类型 categories的操作 获取category的属性 重命名categories 使用**add_ ...

  6. Pandas高级教程之:处理text数据

    文章目录 简介 创建text的DF String 的方法 columns的String操作 分割和替换String String的连接 使用 .str来index extract extractall ...

  7. Pandas高级教程之:自定义选项

    文章目录 简介 常用选项 get/set 选项 经常使用的选项 最大展示行数 超出数据展示 最大列的宽度 显示精度 零转换的门槛 列头的对齐方向 简介 pandas有一个option系统可以控制pan ...

  8. iText7高级教程之html2pdf——7.关于pdfHTML经常问的问题

      本章是一些问题的总结,iText官网罗列了常见的一些问题,让我们能更加了解pdfTML.一下是原文和链接,在这会一一翻译: Over the years, we've received many ...

  9. iText7高级教程之html2pdf——6.在pdfHTML中使用字体

    作者:CuteXiaoKe 微信公众号:CuteXiaoKe   到目前为止,我们还没有花太多的精力来研究将HTML转换为PDF时使用的字体.我们知道Helvetica是iText在没有指定字体时使用 ...

  10. iText7高级教程之html2pdf——1.从Hello HTML开始

    作者:CuteXiaoKe 微信公众号:CuteXiaoKe   在本章,我们通过不同的方法把一个简单的HTML文件转换为PDF文件.HTML文件的内容包含一个"TEST"标题,一 ...

最新文章

  1. HTML中label的两种使用方法
  2. sublime text3使用教程python_Sublime Text 编辑器配置 Python解释器简易教程
  3. 推荐 33 个 IDEA 最牛配置,好用到飞起来!
  4. 「SF图片上传不清晰」解决方案
  5. 出现次数最多的整数-蓝桥杯算法训练
  6. Android 系统服务列表
  7. SQLite语法与Android数据库操作
  8. css基础知识汇总8
  9. 如何使用 OpManager 进行磁盘空间监控?
  10. 赚了20亿美元GandCrab勒索病毒家族的故事
  11. git 强制回滚到某个commit版本
  12. 如何判断自己适不适合学计算机?
  13. python培训班深圳-深圳python人工智能培训班
  14. HALCON图像格式
  15. Yii框架下使用redis做缓存,读写分离
  16. 跨境电商ERP中的自动化 5.平台订单自动打印面单
  17. 69页园区智慧楼宇数字化平台建设方案(智慧办公楼、智慧大楼)
  18. 原子操作 - ARM汇编同步机制实例(一)
  19. 常见的智能推荐算法(总结)
  20. 基于opencv实现人脸猫脸图像检测(python)

热门文章

  1. 百度普通收录正式下线,大量草根站长收录难
  2. Java常用集合框架源码解析合集
  3. 电脑修改服务器时间怎么改,修改服务器时间_如何修改服务器时间 做到同步?...
  4. 常用电子元器件检测方法与经验
  5. uni-app引入极光im
  6. SAE J1939协议读取车辆故障码
  7. 联想拯救者 R720-15ikbn 安装黑苹果 MAC Mojave 10.14.4 efi
  8. matlab使用笔记(一)——matlab语言中if、for语句与C语言中的差别
  9. git可视化工具——GitKraken
  10. bootstrap入门之Code代码显示