呆鸟云:“数据分析就像是夜里行军,业务是灯塔,是地图,没灯塔你不知道方向,没地图你不知道该怎么走。技术是你的交通工具,你用11路,还是骑自行车,还是开跑车,交通工具越好,你实现目标的速度越快 。”

实例方法移位与延迟频率转换向前与向后填充转换 Python 日期与时间重采样基础知识上采样稀疏重采样聚合分组迭代

移位与延迟

有时,需要整体向前或向后移动时间序列里的值,这就是移位与延迟。实现这一操作的方法是 shift(),该方法适用于所有 Pandas 对象。

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

shift 方法支持 freq 参数,可以把 DateOffsettimedelta 对象、偏移量别名 作为参数值:

In [275]: ts.shift(5, freq=pd.offsets.BDay())
Out[275]:
2012-01-06    0
2012-01-09    1
2012-01-10    2
Freq: B, dtype: int64In [276]: ts.shift(5, freq='BM')
Out[276]:
2012-05-31    0
2012-05-31    1
2012-05-31    2
Freq: D, dtype: int64

除更改数据与索引的对齐方式外,DataFrameSeries 对象还提供了 tshift() 便捷方法,可以指定偏移量修改索引日期。

In [277]: ts.tshift(5, freq='D')
Out[277]:
2012-01-06    0
2012-01-07    1
2012-01-08    2
Freq: D, dtype: int64

注意,使用 tshift() 时,因为数据没有重对齐,NaN 不会排在前面。

频率转换

改变频率的函数主要是 asfreq()。对于 DatetimeIndex,这就是一个调用 reindex(),并生成 date_range 的便捷打包器。

In [278]: dr = pd.date_range('1/1/2010', periods=3, freq=3 * pd.offsets.BDay())In [279]: ts = pd.Series(np.random.randn(3), index=dr)In [280]: ts
Out[280]:
2010-01-01    1.494522
2010-01-06   -0.778425
2010-01-11   -0.253355
Freq: 3B, dtype: float64In [281]: ts.asfreq(pd.offsets.BDay())
Out[281]:
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 [282]: ts.asfreq(pd.offsets.BDay(), method='pad')
Out[282]:
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

向前与向后填充

asfreqreindex 相关的是 fillna(),有关文档请参阅缺失值。

转换 Python 日期与时间

to_datetime 方法可以把DatetimeIndex 转换为 Python 原生 datetime.datetime 对象数组。

重采样

0.18.0 版修改了 .resample 接口,现在的 .resample 更灵活,更像 groupby。参阅更新文档 ,对比新旧版本操作的区别。

Pandas 有一个虽然简单,但却强大、高效的功能,可在频率转换时执行重采样,如,将秒数据转换为 5 分钟数据,这种操作在金融等领域里的应用非常广泛。

resample() 是基于时间的分组操作,每个组都遵循归纳方法。参阅 Cookbook 示例了解高级应用。

从 0.18.0 版开始,resample() 可以直接用于 DataFrameGroupBy 对象,参阅 groupby 文档。

.resample() 类似于基于时间偏移量的 rolling() 操作,请参阅这里的讨论。

基础知识

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

resample 函数非常灵活,可以指定多种频率转换与重采样参数。

任何支持派送(dispatch)的函数都可用于 resample 返回对象,包括 summeanstdsemmaxminmidmedianfirstlastohlc

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

对于下采样,closed 可以设置为leftright,用于指定关闭哪一端间隔:

In [289]: ts.resample('5Min', closed='right').mean()
Out[289]:
2011-12-31 23:55:00    308.000000
2012-01-01 00:00:00    250.454545
Freq: 5T, dtype: float64In [290]: ts.resample('5Min', closed='left').mean()
Out[290]:
2012-01-01    251.03
Freq: 5T, dtype: float64

labelloffset 等参数用于生成标签。label 指定生成的结果是否要为间隔标注起始时间。loffset 调整输出标签的时间。

In [291]: ts.resample('5Min').mean()  # 默认为 label='left'
Out[291]:
2012-01-01    251.03
Freq: 5T, dtype: float64In [292]: ts.resample('5Min', label='left').mean()
Out[292]:
2012-01-01    251.03
Freq: 5T, dtype: float64In [293]: ts.resample('5Min', label='left', loffset='1s').mean()
Out[293]:
2012-01-01 00:00:01    251.03
dtype: float64

除了 MAQBMBABQW 的默认值是 right 外,其它频率偏移量的 labelclosed 默认值都是 left

这种操作可能会导致时间回溯,即后面的时间会被拉回到前面的时间,如下例的 BusinessDay 频率所示。

In [294]: s = pd.date_range('2000-01-01', '2000-01-05').to_series()In [295]: s.iloc[2] = pd.NaTIn [296]: s.dt.weekday_name
Out[296]:
2000-01-01     Saturday
2000-01-02       Sunday
2000-01-03          NaN
2000-01-04      Tuesday
2000-01-05    Wednesday
Freq: D, dtype: object# 默认为:label='left', closed='left'
In [297]: s.resample('B').last().dt.weekday_name
Out[297]:
1999-12-31       Sunday
2000-01-03          NaN
2000-01-04      Tuesday
2000-01-05    Wednesday
Freq: B, dtype: object

看到了吗?星期日被拉回到了上一个星期五。要想把星期日移至星期一,改用以下代码:

In [298]: s.resample('B', label='right', closed='right').last().dt.weekday_name
Out[298]:
2000-01-03       Sunday
2000-01-04      Tuesday
2000-01-05    Wednesday
Freq: B, dtype: object

axis 参数的值为 01,并可指定 DataFrame 重采样的轴。

kind 参数可以是 timestampperiod,转换为时间戳或时间段形式的索引。resample 默认保留输入的日期时间形式。

重采样 period 数据时(详情见下文),convention 可以设置为 startend。指定低频时间段如何转换为高频时间段。

上采样

上采样可以指定上采样的方式及插入时间间隔的 limit 参数:

# 从秒到每 250 毫秒
In [299]: ts[:2].resample('250L').asfreq()
Out[299]:
2012-01-01 00:00:00.000    308.0
2012-01-01 00:00:00.250      NaN
2012-01-01 00:00:00.500      NaN
2012-01-01 00:00:00.750      NaN
2012-01-01 00:00:01.000    204.0
Freq: 250L, dtype: float64In [300]: ts[:2].resample('250L').ffill()
Out[300]:
2012-01-01 00:00:00.000    308
2012-01-01 00:00:00.250    308
2012-01-01 00:00:00.500    308
2012-01-01 00:00:00.750    308
2012-01-01 00:00:01.000    204
Freq: 250L, dtype: int64In [301]: ts[:2].resample('250L').ffill(limit=2)
Out[301]:
2012-01-01 00:00:00.000    308.0
2012-01-01 00:00:00.250    308.0
2012-01-01 00:00:00.500    308.0
2012-01-01 00:00:00.750      NaN
2012-01-01 00:00:01.000    204.0
Freq: 250L, dtype: float64

稀疏重采样

相对于时间点总量,稀疏时间序列重采样的点要少很多。单纯上采样稀疏系列可能会生成很多中间值。未指定填充值,即 fill_methodNone 时,中间值将填充为 NaN

鉴于 resample 是基于时间的分组,下列这种方法可以有效重采样,只是分组不是都为 NaN

In [302]: rng = pd.date_range('2014-1-1', periods=100, freq='D') + pd.Timedelta('1s')In [303]: ts = pd.Series(range(100), index=rng)

Series 全范围重采样。

In [304]: ts.resample('3T').sum()
Out[304]:
2014-01-01 00:00:00     0
2014-01-01 00:03:00     0
2014-01-01 00:06:00     0
2014-01-01 00:09:00     0
2014-01-01 00:12:00     0..
2014-04-09 23:48:00     0
2014-04-09 23:51:00     0
2014-04-09 23:54:00     0
2014-04-09 23:57:00     0
2014-04-10 00:00:00    99
Freq: 3T, Length: 47521, dtype: int64

对以下包含点的分组重采样:

In [305]: from functools import partialIn [306]: from pandas.tseries.frequencies import to_offsetIn [307]: def round(t, freq):.....:     freq = to_offset(freq).....:     return pd.Timestamp((t.value // freq.delta.value) * freq.delta.value).....: In [308]: ts.groupby(partial(round, freq='3T')).sum()
Out[308]:
2014-01-01     0
2014-01-02     1
2014-01-03     2
2014-01-04     3
2014-01-05     4..
2014-04-06    95
2014-04-07    96
2014-04-08    97
2014-04-09    98
2014-04-10    99
Length: 100, dtype: int64

聚合

类似于聚合 API,Groupby API 及窗口函数 API,Resampler 可以有选择地重采样。

DataFrame 重采样,默认用相同函数操作所有列。

In [309]: df = pd.DataFrame(np.random.randn(1000, 3),.....:                   index=pd.date_range('1/1/2012', freq='S', periods=1000),.....:                   columns=['A', 'B', 'C']).....: In [310]: r = df.resample('3T')In [311]: r.mean()
Out[311]: A         B         C
2012-01-01 00:00:00 -0.033823 -0.121514 -0.081447
2012-01-01 00:03:00  0.056909  0.146731 -0.024320
2012-01-01 00:06:00 -0.058837  0.047046 -0.052021
2012-01-01 00:09:00  0.063123 -0.026158 -0.066533
2012-01-01 00:12:00  0.186340 -0.003144  0.074752
2012-01-01 00:15:00 -0.085954 -0.016287 -0.050046

标准 getitem 操作可以指定的一列或多列。

In [312]: r['A'].mean()
Out[312]:
2012-01-01 00:00:00   -0.033823
2012-01-01 00:03:00    0.056909
2012-01-01 00:06:00   -0.058837
2012-01-01 00:09:00    0.063123
2012-01-01 00:12:00    0.186340
2012-01-01 00:15:00   -0.085954
Freq: 3T, Name: A, dtype: float64In [313]: r[['A', 'B']].mean()
Out[313]: A         B
2012-01-01 00:00:00 -0.033823 -0.121514
2012-01-01 00:03:00  0.056909  0.146731
2012-01-01 00:06:00 -0.058837  0.047046
2012-01-01 00:09:00  0.063123 -0.026158
2012-01-01 00:12:00  0.186340 -0.003144
2012-01-01 00:15:00 -0.085954 -0.016287

聚合还支持函数列表与字典,输出的是 DataFrame

In [314]: r['A'].agg([np.sum, np.mean, np.std])
Out[314]: sum      mean       std
2012-01-01 00:00:00  -6.088060 -0.033823  1.043263
2012-01-01 00:03:00  10.243678  0.056909  1.058534
2012-01-01 00:06:00 -10.590584 -0.058837  0.949264
2012-01-01 00:09:00  11.362228  0.063123  1.028096
2012-01-01 00:12:00  33.541257  0.186340  0.884586
2012-01-01 00:15:00  -8.595393 -0.085954  1.035476

重采样后的 DataFrame,可以为每列指定函数列表,生成结构化索引的聚合结果:

In [315]: r.agg([np.sum, np.mean])
Out[315]: A                    B                    C          sum      mean        sum      mean        sum      mean
2012-01-01 00:00:00  -6.088060 -0.033823 -21.872530 -0.121514 -14.660515 -0.081447
2012-01-01 00:03:00  10.243678  0.056909  26.411633  0.146731  -4.377642 -0.024320
2012-01-01 00:06:00 -10.590584 -0.058837   8.468289  0.047046  -9.363825 -0.052021
2012-01-01 00:09:00  11.362228  0.063123  -4.708526 -0.026158 -11.975895 -0.066533
2012-01-01 00:12:00  33.541257  0.186340  -0.565895 -0.003144  13.455299  0.074752
2012-01-01 00:15:00  -8.595393 -0.085954  -1.628689 -0.016287  -5.004580 -0.050046

把字典传递给 aggregate,可以为 DataFrame 里不同的列应用不同聚合函数。

In [316]: r.agg({'A': np.sum,.....:        'B': lambda x: np.std(x, ddof=1)}).....:
Out[316]: A         B
2012-01-01 00:00:00  -6.088060  1.001294
2012-01-01 00:03:00  10.243678  1.074597
2012-01-01 00:06:00 -10.590584  0.987309
2012-01-01 00:09:00  11.362228  0.944953
2012-01-01 00:12:00  33.541257  1.095025
2012-01-01 00:15:00  -8.595393  1.035312

还可以用字符串代替函数名。为了让字符串有效,必须在重采样对象上操作:

In [317]: r.agg({'A': 'sum', 'B': 'std'})
Out[317]: A         B
2012-01-01 00:00:00  -6.088060  1.001294
2012-01-01 00:03:00  10.243678  1.074597
2012-01-01 00:06:00 -10.590584  0.987309
2012-01-01 00:09:00  11.362228  0.944953
2012-01-01 00:12:00  33.541257  1.095025
2012-01-01 00:15:00  -8.595393  1.035312

甚至还可以为每列单独多个聚合函数。

In [318]: r.agg({'A': ['sum', 'std'], 'B': ['mean', 'std']})
Out[318]: A                   B          sum       std      mean       std
2012-01-01 00:00:00  -6.088060  1.043263 -0.121514  1.001294
2012-01-01 00:03:00  10.243678  1.058534  0.146731  1.074597
2012-01-01 00:06:00 -10.590584  0.949264  0.047046  0.987309
2012-01-01 00:09:00  11.362228  1.028096 -0.026158  0.944953
2012-01-01 00:12:00  33.541257  0.884586 -0.003144  1.095025
2012-01-01 00:15:00  -8.595393  1.035476 -0.016287  1.035312

如果 DataFrame 用的不是 datetime 型索引,则可以基于 datetime 数据列重采样,用关键字 on 控制。

In [319]: df = pd.DataFrame({'date': pd.date_range('2015-01-01', freq='W', periods=5),.....:                    'a': np.arange(5)},.....:                   index=pd.MultiIndex.from_arrays([.....:                       [1, 2, 3, 4, 5],.....:                       pd.date_range('2015-01-01', freq='W', periods=5)],.....:                       names=['v', 'd'])).....: In [320]: df
Out[320]: date  a
v d
1 2015-01-04 2015-01-04  0
2 2015-01-11 2015-01-11  1
3 2015-01-18 2015-01-18  2
4 2015-01-25 2015-01-25  3
5 2015-02-01 2015-02-01  4In [321]: df.resample('M', on='date').sum()
Out[321]: a
date
2015-01-31  6
2015-02-28  4

同样,还可以对 datetime MultiIndex 重采样,通过关键字 level 传递名字与位置。

In [322]: df.resample('M', level='d').sum()
Out[322]: a
d
2015-01-31  6
2015-02-28  4

分组迭代

Resampler对象迭代分组数据的操作非常自然,类似于  itertools.groupby()

In [323]: small = pd.Series(.....:     range(6),.....:     index=pd.to_datetime(['2017-01-01T00:00:00',.....:                           '2017-01-01T00:30:00',.....:                           '2017-01-01T00:31:00',.....:                           '2017-01-01T01:00:00',.....:                           '2017-01-01T03:00:00',.....:                           '2017-01-01T03:05:00']).....: ).....: In [324]: resampled = small.resample('H')In [325]: for name, group in resampled:.....:     print("Group: ", name).....:     print("-" * 27).....:     print(group, end="\n\n").....:
Group:  2017-01-01 00:00:00
---------------------------
2017-01-01 00:00:00    0
2017-01-01 00:30:00    1
2017-01-01 00:31:00    2
dtype: int64Group:  2017-01-01 01:00:00
---------------------------
2017-01-01 01:00:00    3
dtype: int64Group:  2017-01-01 02:00:00
---------------------------
Series([], dtype: int64)Group:  2017-01-01 03:00:00
---------------------------
2017-01-01 03:00:00    4
2017-01-01 03:05:00    5
dtype: int64

了解更多详情,请参阅分组迭代或 itertools.groupby()


Pandas 时间序列 - 纵览与时间戳

Pandas 时间序列 - 日期时间索引

Pandas 时间序列 - DateOffset 对象

Pandas 时间序列 - 实例方法与重采样相关推荐

  1. Pandas 时间序列 - 纵览与时间戳

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 一身报国有万死,双鬓向人无再青. ...

  2. pandas时间序列与自回归ARIMA模型

    文章目录 知识点梳理 1 时间预处理 1.1 创造时间序列 1.2 选择时间序列 1.3 重采样 1.4 滑动窗口 1.5 差分 2.自回归ARIMA模型 1.平稳性(差分) 2. ACF与PACF ...

  3. EduCoder Pandas高效化运算与时间序列处理 第3关:Pandas时间序列的高级应用

    文章目录 任务描述 相关知识 时间频率与偏移量 重新取样.迁移和窗口 重新取样 时间迁移 移动时间窗口 编程要求 测试说明 任务描述 根据相关知识完成下列任务: 求上个季度(仅含工作日)的平均值: 求 ...

  4. Pandas 时间序列 - DateOffset 对象

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 国亡身殒今何有,只留离骚在世间. ...

  5. Pandas时间序列 :rolling 用法快速理解

    相信初学Pandas时间序列时,会遇到rolling函数,不知道该怎么理解,对吧? 让我们用最简单的例子来说明吧. 代码如下: import pandas as pd # 导入 pandas inde ...

  6. pandas 时间序列的优化转化

    pandas 时间序列的优化转化 #!/usr/bin/env Python3 __author__ = '未昔/angelfate' __date__ = '2019/7/26 9:58' # -* ...

  7. Pandas的时间序列数据-resample重采样(31)

    在pandas里对时序的频率的调整称之重新采样,即从一个时频调整为另一个时频的操作,可以借助resample的函数来完成.有upsampling和downsampling(高频变低频)两种.resam ...

  8. Pandas时间序列数据处理和datetime模块详细教程

    时间序列分析中,常常需要处理时间相关数据,故参考<Python for Data Analysis>总结了Python和Pandas常用的时间序列数据处理的相关操作,并在 Python3. ...

  9. 时间序列 | pandas时间序列基础

    时间序列(time series)数据是一种重要的结构化数据形式,应用于多个领域,包括金融学.经济学.生态学.神经科学.物理学等.在多个时间点观察或测量到的任何事物都可以形成一段时间序列.很多时间序列 ...

最新文章

  1. HarmonyOS系统概述
  2. 关于学习Python的一点学习总结(3->标识符->if->模块->字符)
  3. jquery $.extend() 对象内容合并
  4. java ReentrantLock 实现原理
  5. 在公司如何远程控制家中电脑
  6. 驱动人生后门清除方案
  7. string的replaceAll()
  8. 深入浅出统计学 笔记 总结 学习心得
  9. 怎么去除微博图片的水印?
  10. 新浪微博since_id值
  11. 手机投屏到电脑显示屏
  12. Python 变量作用域问题 函数名.变量名
  13. Android 6.0系统中图片剪切空指针崩溃问题解决纪录
  14. c语言中的less函数,less的小白入门介绍
  15. 解决chrome您的连接不是私密连接
  16. 联想笔记本重装win7系统之后无线不能用
  17. linux如何安装黑客帝国cmatrix代码雨效果
  18. 阿里云centos7安装mysql
  19. vanilla-tilt.js: 一个平滑的3D倾斜javascript库。
  20. basler工业相机使用问题总结

热门文章

  1. HDU1273漫步森林
  2. 解压缩命令tar zip rar
  3. 外边距 - margin
  4. 使用HTML5和CSS制作抖音动态首页
  5. Microbiome:微生物组名词定义
  6. 【python 程序题:火车票购买程序】
  7. react+ts+echarts5.x按需导入实现世界地图
  8. 职业高一计算机试题,信息技术教师考试题库
  9. 二层与三层交换机配置
  10. 交通安全与智能控制专业学计算机吗,交通安全与智能控制专业就业前景怎么样...