一、时序中的基本对象

几个概念:

  • 时间戳(Date times)的概念:在 pandas 中称为 Timestamp 。同时,一系列的时间戳可以组成 DatetimeIndex ,而将它放到 Series 中后, Series 的类型就变为了 datetime64[ns] ,如果有涉及时区则为 datetime64[ns, tz] ,其中tz是timezone的简写。
  • 时间差(Time deltas)的概念:两个 Timestamp 做差就得到了时间差,pandas中利用 Timedelta 来表示。类似的,一系列的时间差就组成了 TimedeltaIndex , 而将它放到 Series 中后, Series 的类型就变为了 timedelta64[ns]
  • 时间段(Time spans)的概念:在 pandas 利用 Period 来表示。类似的,一系列的时间段就组成了 PeriodIndex , 而将它放到 Series 中后, Series 的类型就变为了 Period
  • 日期偏置(Date offsets)的概念:pandas 中没有为一列时间偏置专门设计存储类型,一般来说我们只需要对一批时间特征做一个统一的特殊日期偏置。
概念 单元素类型 数组类型 pandas数据类型
Date times Timestamp DatetimeIndex datetime64[ns]
Time deltas Timedelta TimedeltaIndex timedelta64[ns]
Time spans Period PeriodIndex period[freq]
Date offsets DateOffset None None

二、时间戳

2.1 Timestamp的构造与属性

单个时间戳的生成利用 pd.Timestamp 实现,一般而言的常见日期格式都能被成功地转换:

pd.Timestamp('2020/1/1')
>>> Timestamp('2020-01-01 00:00:00')
ts = pd.Timestamp('2020-1-1 08:10:30')
ts
>>> Timestamp('2020-01-01 08:10:30')

通过 year, month, day, hour, minute, second 可以获取具体的数值:

ts.year
>>> 2020
ts.month
>>> 1
ts.day
>>> 1
ts.hour
>>> 8
ts.minute
>>> 10
ts.second
>>> 30

pandas 中,时间戳的最小精度为纳秒 ns ,由于使用了64位存储,可以表示的时间范围大约可以如下计算:
TimeRange=264109×60×60×24×365≈585(Years)\rm Time\,Range = \frac{2^{64}}{10^9\times 60\times 60\times 24\times 365} \approx 585 (Years)TimeRange=109×60×60×24×365264​≈585(Years)

通过 pd.Timestamp.maxpd.Timestamp.min 可以获取时间戳表示的范围,可以看到确实表示的区间年数大小正如上述计算结果:

pd.Timestamp.max
>>> Timestamp('2262-04-11 23:47:16.854775807')
pd.Timestamp.min
>>> Timestamp('1677-09-21 00:12:43.145225')pd.Timestamp.max.year - pd.Timestamp.min.year
>>> 585

2.2 Datetime序列的生成

一组时间戳可以组成时间序列,可以用 to_datetimedate_range 来生成。其中, to_datetime 能够把一列时间戳格式的对象转换成为 datetime64[ns] 类型的时间序列:

pd.to_datetime(['2020-1-1', '2020-1-3', '2020-1-6'])
>>> DatetimeIndex(['2020-01-01', '2020-01-03', '2020-01-06'], dtype='datetime64[ns]', freq=None)
df = pd.read_csv('data/learn_pandas.csv')
s = pd.to_datetime(df.Test_Date)
s.head()
0   2019-10-05
1   2019-09-04
2   2019-09-12
3   2020-01-03
4   2019-11-06
Name: Test_Date, dtype: datetime64[ns]

在极少数情况,时间戳的格式不满足转换时,可以强制使用 format 进行匹配:

temp = pd.to_datetime(['2020\\1\\1','2020\\1\\3'],format='%Y\\%m\\%d')
temp
>>> DatetimeIndex(['2020-01-01', '2020-01-03'], dtype='datetime64[ns]', freq=None)

注意上面由于传入的是列表,而非 pandas 内部的 Series ,因此返回的是 DatetimeIndex ,如果想要转为 datetime64[ns] 的序列,需要显式用 Series 转化:

pd.Series(temp).head()0   2020-01-01
1   2020-01-03
dtype: datetime64[ns]

还存在一种把表的多列时间属性拼接转为时间序列的 to_datetime 操作,此时的列名必须和以下给定的时间关键词列名一致:

df_date_cols = pd.DataFrame({'year': [2020, 2020],'month': [1, 1],'day': [1, 2],'hour': [10, 20],'minute': [30, 50],'second': [20, 40]})
pd.to_datetime(df_date_cols)0   2020-01-01 10:30:20
1   2020-01-02 20:50:40
dtype: datetime64[ns]

date_range 是一种生成连续间隔时间的一种方法,其重要的参数为 start, end, freq, periods ,它们分别表示开始时间,结束时间,时间间隔,时间戳个数。其中,四个中的三个参数决定了,那么剩下的一个就随之确定了。这里要注意,开始或结束日期如果作为端点则它会被包含:

pd.date_range('2020-1-1','2020-1-21', freq='10D') # 包含
>>> DatetimeIndex(['2020-01-01', '2020-01-11', '2020-01-21'], dtype='datetime64[ns]', freq='10D')pd.date_range('2020-1-1','2020-2-28', freq='10D') #不包含结束时间DatetimeIndex(['2020-01-01', '2020-01-11', '2020-01-21', '2020-01-31','2020-02-10', '2020-02-20'],dtype='datetime64[ns]', freq='10D')
pd.date_range('2020-1-1', '2020-2-28', periods=6) # 由于结束日期无法取到,freq不为10天
DatetimeIndex(['2020-01-01 00:00:00', '2020-01-12 14:24:00','2020-01-24 04:48:00', '2020-02-04 19:12:00','2020-02-16 09:36:00', '2020-02-28 00:00:00'],dtype='datetime64[ns]', freq=None)

练一练

Timestamp 上定义了一个 value 属性,其返回的整数值代表了从1970年1月1日零点到给定时间戳相差的纳秒数,请利用这个属性构造一个随机生成给定日期区间内日期序列的函数。

def rand_date

最后,要介绍一种改变序列采样频率的方法 asfreq ,它能够根据给定的 freq 对序列进行类似于 reindex 的操作:

s = pd.Series(np.random.rand(5),index=pd.to_datetime(['2020-1-%d'%i for i in range(1,10,2)]))
s2020-01-01    0.629827
2020-01-03    0.191077
2020-01-05    0.149454
2020-01-07    0.302080
2020-01-09    0.819131
dtype: float64
s.asfreq('12H').head()2020-01-01 00:00:00    0.629827
2020-01-01 12:00:00         NaN
2020-01-02 00:00:00         NaN
2020-01-02 12:00:00         NaN
2020-01-03 00:00:00    0.191077
Freq: 12H, dtype: float64

前面提到了 datetime64[ns] 本质上可以理解为一个大整数,对于一个该类型的序列,可以使用 max, min, mean ,来取得最大时间戳、最小时间戳和“平均”时间戳。

s1 = pd.date_range('2020-1-1', '2020-2-28', periods=6)
s1.max()
>>> Timestamp('2020-02-28 00:00:00')
s1.min()
>>> Timestamp('2020-01-01 00:00:00')
s1.mean()
>>> Timestamp('2020-01-30 00:00:00')

2.3 dt对象

如同 category, string 的序列上定义了 cat, str 来完成分类数据和文本数据的操作,在时序类型的序列上定义了 dt 对象来完成许多时间序列的相关操作。这里对于 datetime64[ns] 类型而言,可以大致分为三类操作:取出时间相关的属性、判断时间戳是否满足条件、取整操作。

取出时间相关的属性

常用属性包括 date, time, year, month, day, hour, minute, second, microsecond, nanosecond, dayofweek, dayofyear, weekofyear, daysinmonth, quarter ,其中 daysinmonth, quarter 分别表示这月有几天和季度。

s = pd.Series(pd.date_range('2020-1-1','2020-1-3', freq='D'))
s.dt.date0    2020-01-01
1    2020-01-02
2    2020-01-03
dtype: objects.dt.time0    00:00:00
1    00:00:00
2    00:00:00
dtype: objects.dt.year0    2020
1    2020
2    2020
dtype: int64
s.dt.daysinmonth0    31
1    31
2    31
dtype: int64

在这些属性中,经常使用的是 dayofweek ,它返回了周中的星期情况,周一为0、周二为1,以此类推:

s.dt.dayofweek0    2
1    3
2    4
dtype: int64

可以通过 month_name, day_name 返回英文的月名和星期名,注意它们是方法而不是属性:

s.dt.month_name()0    January
1    January
2    January
dtype: object
s.dt.day_name()0    Wednesday
1     Thursday
2       Friday
dtype: object

判断时间戳是否满足条件

判断操作主要用于测试是否为月/季/年的第一天或者最后一天:

s.dt.is_year_start # 还可选 is_quarter/month_start0     True
1    False
2    False
dtype: bool
s.dt.is_month_start0     True
1    False
2    False
dtype: bool
s.dt.is_year_end # 还可选 is_quarter/month_end0    False
1    False
2    False
dtype: bool

取整操作

取整操作包含 round, ceil, floor ,它们的公共参数为 freq ,常用的包括 H, min, S (小时、分钟、秒),所有可选的 freq 可参考 此处 。

s = pd.Series(pd.date_range('2020-1-1 20:35:00', '2020-1-1 22:35:00', freq='45min'))
s0   2020-01-01 20:35:00
1   2020-01-01 21:20:00
2   2020-01-01 22:05:00
dtype: datetime64[ns]
s.dt.round('1H') # 四舍五入0   2020-01-01 21:00:00
1   2020-01-01 21:00:00
2   2020-01-01 22:00:00
dtype: datetime64[ns]
s.dt.ceil('1H') # 向上取整0   2020-01-01 21:00:00
1   2020-01-01 22:00:00
2   2020-01-01 23:00:00
dtype: datetime64[ns]
s.dt.floor('1H') # 向下取整0   2020-01-01 20:00:00
1   2020-01-01 21:00:00
2   2020-01-01 22:00:00
dtype: datetime64[ns]

2.4 时间戳的切片与索引

一般而言,时间戳序列作为索引使用。如果想要选出某个子时间戳序列,第一类方法是利用 dt 对象和布尔条件联合使用,另一种方式是利用切片,后者常用于连续时间戳。

s = pd.Series(np.random.randint(2,size=366),index=pd.date_range('2020-01-01','2020-12-31'))s.head()2020-01-01    0
2020-01-02    0
2020-01-03    0
2020-01-04    0
2020-01-05    1
Freq: D, dtype: int32
idx = pd.Series(s.index).dt
# Example1:每月的第一天或者最后一天
s[(idx.is_month_start|idx.is_month_end).values].head()2020-01-01    0
2020-01-31    1
2020-02-01    1
2020-02-29    0
2020-03-01    0
dtype: int32
# Example2:双休日
s[idx.dayofweek.isin([5,6]).values].head()2020-01-04    0
2020-01-05    1
2020-01-11    0
2020-01-12    0
2020-01-18    1
dtype: int32
# Example3:取出单日值
s['2020-01-04']
>>> 0s['20200104'] # 自动转换标准格式
>>> 0
# Example4:取出五月
s['2020-05'].head()2020-05-01    1
2020-05-02    0
2020-05-03    0
2020-05-04    0
2020-05-05    1
Freq: D, dtype: int32
# Example5:取出5月初至7月15日
s['2020-05':'2020-7-15'].head()2020-05-01    1
2020-05-02    0
2020-05-03    0
2020-05-04    0
2020-05-05    1
Freq: D, dtype: int32s['2020-05':'2020-7-15'].tail()2020-07-11    0
2020-07-12    1
2020-07-13    1
2020-07-14    0
2020-07-15    0
Freq: D, dtype: int32

三、时间差

3.1 Timedelta的生成

时间差可以理解为两个时间戳的差,这里也可以通过 pd.Timedelta来构造:

pd.Timestamp('20200102 08:00:00')-pd.Timestamp('20200101 07:35:00')
>>> Timedelta('1 days 00:25:00')pd.Timedelta(days=1, minutes=25) # 需要注意加s
>>> Timedelta('1 days 00:25:00')pd.Timedelta('1 days 25 minutes 30 seconds') # 字符串生成
>>> Timedelta('1 days 00:25:30')

生成时间差序列的主要方式是 pd.to_timedelta ,其类型为 timedelta64[ns]

s = pd.to_timedelta(df.Time_Record)
s.head()0   0 days 00:04:34
1   0 days 00:04:20
2   0 days 00:05:22
3   0 days 00:04:08
4   0 days 00:05:22
Name: Time_Record, dtype: timedelta64[ns]

date_range 一样,时间差序列也可以用 timedelta_range 来生成,它们两者具有一致的参数:

pd.timedelta_range('0s', '1000s', freq='6min')
>>> TimedeltaIndex(['0 days 00:00:00', '0 days 00:06:00', '0 days 00:12:00'], dtype='timedelta64[ns]', freq='6T')pd.timedelta_range('0s', '1000s', periods=3)
>>> TimedeltaIndex(['0 days 00:00:00', '0 days 00:08:20', '0 days 00:16:40'], dtype='timedelta64[ns]', freq=None)

对于 Timedelta 序列,同样也定义了 dt 对象,上面主要定义了的属性包括 days, seconds, mircroseconds, nanoseconds ,它们分别返回了对应的时间差特征。需要注意的是,这里的 seconds 不是指单纯的秒,而是对天数取余后剩余的秒数:

s.dt.seconds.head()
0    274
1    260
2    322
3    248
4    322
Name: Time_Record, dtype: int64

如果不想对天数取余而直接对应秒数,可以使用 total_seconds

s.dt.total_seconds().head()
0    274.0
1    260.0
2    322.0
3    248.0
4    322.0
Name: Time_Record, dtype: float64

与时间戳序列类似,取整函数也是可以在 dt 对象上使用的:

pd.to_timedelta(df.Time_Record).dt.round('min').head()
0   0 days 00:05:00
1   0 days 00:04:00
2   0 days 00:05:00
3   0 days 00:04:00
4   0 days 00:05:00
Name: Time_Record, dtype: timedelta64[ns]

3.2 Timedelta的运算

时间差支持的常用运算有三类:与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算:

td1 = pd.Timedelta(days=1)
td2 = pd.Timedelta(days=2)
ts = pd.Timestamp('20200101')
td1 * 2
>>> Timedelta('2 days 00:00:00')
td2 - td1
>>> Timedelta('1 days 00:00:00')
ts + td1
>>> Timestamp('2020-01-02 00:00:00')
ts - td1
>>> Timestamp('2019-12-31 00:00:00')

这些运算都可以移植到时间差的序列上:

td1 = pd.timedelta_range(start='1 days', periods=5)
td2 = pd.timedelta_range(start='12 hours', freq='2H', periods=5)
ts = pd.date_range('20200101', '20200105')
td1 * 5
>>> TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')
td1 * pd.Series(list(range(5))) # 逐个相乘0    0 days
1    2 days
2    6 days
3   12 days
4   20 days
dtype: timedelta64[ns]
td1 - td2
TimedeltaIndex(['0 days 12:00:00', '1 days 10:00:00', '2 days 08:00:00','3 days 06:00:00', '4 days 04:00:00'],dtype='timedelta64[ns]', freq=None)
td1 + pd.Timestamp('20200101')
DatetimeIndex(['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05','2020-01-06'],dtype='datetime64[ns]', freq='D')
td1 + ts # 逐个相加
DatetimeIndex(['2020-01-02', '2020-01-04', '2020-01-06', '2020-01-08','2020-01-10'],dtype='datetime64[ns]', freq=None)

四、日期偏置

4.1 Offset对象

日期偏置是一种和日历相关的特殊时间差

# 求2020年9月第一个周一的日期
pd.Timestamp('20200831') + pd.offsets.WeekOfMonth(week=0,weekday=0)
>>> Timestamp('2020-09-07 00:00:00')# 求2020年9月7日后的第30个工作日是哪一天
pd.Timestamp('20200907') + pd.offsets.BDay(30)
>>> Timestamp('2020-10-19 00:00:00')

从上面的例子中可以看到, Offset 对象在 pd.offsets 中被定义。当使用 + 时获取离其最近的下一个日期,当使用 - 时获取离其最近的上一个日期:

# 求2020年8月第一个周一的日期
pd.Timestamp('20200831') - pd.offsets.WeekOfMonth(week=0,weekday=0)
>>> Timestamp('2020-08-03 00:00:00')# 求2020年9月7日前的第30个工作日是哪一天
pd.Timestamp('20200907') - pd.offsets.BDay(30)
>>> Timestamp('2020-07-27 00:00:00')# 求2020年9月最后一天
pd.Timestamp('20200907') + pd.offsets.MonthEnd()
>>> Timestamp('2020-09-30 00:00:00')

常用的日期偏置如下可以查阅这里的 文档 描述。在文档罗列的 Offset 中,需要介绍一个特殊的 Offset 对象 CDay ,其中的 holidays, weekmask 参数能够分别对自定义的日期和星期进行过滤,前者传入了需要过滤的日期列表,后者传入的是三个字母的星期缩写构成的星期字符串,其作用是只保留字符串中出现的星期:

my_filter = pd.offsets.CDay(n=1,weekmask='Wed Fri',holidays=['20200109'])
dr = pd.date_range('20200108', '20200111')
dr.to_series().dt.dayofweek2020-01-08    2
2020-01-09    3
2020-01-10    4
2020-01-11    5
Freq: D, dtype: int64
[i + my_filter for i in dr][Timestamp('2020-01-10 00:00:00'),Timestamp('2020-01-10 00:00:00'),Timestamp('2020-01-15 00:00:00'),Timestamp('2020-01-15 00:00:00')]

参考文献

https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch10.html#id2

编程实践(Pandas)Task10相关推荐

  1. python 3d大数据可视化_Python大数据可视化编程实践-绘制图表

    Python 数据可视化编程实践 - 绘制图表 准备工作 打开 Jupyter Notebook ,导入需要的包, 并配置好图片交互和中文显示环 境: import pandas as pd impo ...

  2. 【Spark】实验6 Spark机器学习库MLlib编程实践

    Spark机器学习库MLlib编程实践 一.实验目的 通过实验掌握基本的MLLib编程方法: 掌握用MLLib解决一些常见的数据分析问题,包括数据导入.成分分析和分类和预测等. 二.实验平台 新工科智 ...

  3. 【组队学习】【29期】1. 编程实践(数据可视化)

    1. 编程实践(数据可视化) 航路开辟者:杨剑砺.杨煜.耿远昊.李运佳.居凤霞 领航员:范佳慧 航海士:杨剑砺.伊雪.肖桐.李晴晴.蔡婧旎 基本信息 开源内容:https://github.com/d ...

  4. 【组队学习】【26期】编程实践(Python办公自动化)

    编程实践(Python办公自动化) 论坛版块: http://datawhale.club/c/team-learning/29-category/29 开源内容: https://github.co ...

  5. 【组队学习】【26期】编程实践(Django网站开发)

    编程实践(Django网站开发) 论坛版块: http://datawhale.club/c/team-learning/28-category/28 开源内容: https://github.com ...

  6. 【组队学习】【23期】Datawhale编程实践(区块链)

    编程实践(区块链) 开源内容:https://github.com/datawhalechina/team-learning-program/tree/master/Blockchain 基本信息 贡 ...

  7. [Java 并发] Java并发编程实践 思维导图 - 第一章 简单介绍

    阅读<Java并发编程实践>一书后整理的思维导图.

  8. 《Java并发编程实践》学习笔记之一:基础知识

    <Java并发编程实践>学习笔记之一:基础知识 1.程序与进程 1.1 程序与进程的概念 (1)程序:一组有序的静态指令,是一种静态概念:  (2)进程:是一种活动,它是由一个动作序列组成 ...

  9. 郑捷《机器学习算法原理与编程实践》学习笔记(第七章 预测技术与哲学)7.1 线性系统的预测...

    7.1.1 回归与现代预测 7.1.2 最小二乘法 7.1.3 代码实现 (1)导入数据 def loadDataSet(self,filename): #加载数据集X = [];Y = []fr = ...

  10. 《深入理解大数据:大数据处理与编程实践》一一3.3 HDFS文件存储组织与读写...

    本节书摘来自华章计算机<深入理解大数据:大数据处理与编程实践>一书中的第3章,第3.3节,作者 主 编:黄宜华(南京大学)副主编:苗凯翔(英特尔公司),更多章节内容可以访问云栖社区&quo ...

最新文章

  1. python列表(list)+索引切片+修改+插入+删除+range函数生成整数列表对象
  2. phpstudy集成环境安装redis扩展
  3. hdu3313 最大流找关键点,或者最短路找关键点.
  4. Arduino的光敏传感器和超声波测距传感器测试代码
  5. Seata 是什么?
  6. final,finally,finaliz的区别(Java)
  7. ubuntu1204 dvd 用tweak后界面起不来 swap设置4g足够32位系统软件用
  8. jquery ajax jsonp跨域调用实例代码
  9. prosody相关概念了解。xmpp,jabber,bosh等
  10. Spring学习传送门
  11. java 0点时间_java 获取当前时间与零点的时间差
  12. setBounds(left, top, right, bottom)详解
  13. Linux下 man命令的使用 及 中文man手册的安装
  14. 双路cpu比单路强多少_别傻了!双核和双路服务器根本不一样
  15. 以前收入高,但毫无上进心,40岁一身房贷,被裁后找个小公司,天天担心试用期过不了,焦虑地睡不着!...
  16. 聚合支付与第四方支付平台的本质区别
  17. feign远程调用传参问题
  18. 协同过滤推荐之基于近邻协同过滤(一)
  19. 如何通过SSH隧道连接学校服务器
  20. 机器学习3:——Pandas——3:文件读取和存储

热门文章

  1. 融合通信售前糗事大集锦,你中了几条!
  2. 更新系统后小米note显示无服务器,小米解答MIUI 9系统升级常见问题
  3. 广读精思:外文期刊那些事(上)
  4. 青年PM 倪超:想让程序员多一点点幸福感
  5. 使用Python编写淘宝抢购代码
  6. 探探php模板下载,C3+H5+jQuery仿探探APP手机滑动切换特效
  7. 攻防世界-逆向game
  8. FZU_Problem 2167 大王叫我来巡山呐
  9. 云安全为杀毒软件带来了什么
  10. 红外遥控按键16进制编码