首页Python【Python数据分析】6...

【Python数据分析】61.时间序列——重新采样和频率转换1


本系列文章配套代码获取有以下三种途径:

  • 可以在以下网站查看,该网站是使用JupyterLite搭建的web端Jupyter环境,因此无需在本地安装运行环境即可使用,首次运行浏览器需要下载一些配置文件(大约20M):

https://returu.github.io/Python_Data_Analysis/lab/index.html
链接:https://pan.baidu.com/s/1MYkeYeVAIRqbxezQECHwcA?pwd=mnsj 提取码:mnsj
  • 前往GitHub详情页面,单击 code 按钮,选择Download ZIP选项:
https://github.com/returu/Python_Data_Analysis

根据《Python for Data Analysis 3rd Edition》翻译整理

—————————————————–

重新采样(Resampling)是指将时间序列从一个频率转换为另一个频率的过程。

将较高频率数据聚合到较低频率称为向下采样,而将较低频率转换为较高频率称为向上采样。

并非所有重新采样都属于这两个类别中的任何一个。例如,将 W-WED(每周三)转换为 W-FRI(每周五) 既不是向上采样也不是向下采样。

pandas 对象具有 resample 方法,这是所有频率转换的工具函数。resample 具有与 groupby 类似的 API:调用 resample 对数据进行分组,然后再调用聚合函数:

 1>>> dates = pd.date_range("2022-01-01", periods=100)
2
3>>> ts = pd.Series(np.arange(len(dates)), index=dates)
4>>> ts
52022-01-01     0
62022-01-02     1
72022-01-03     2
82022-01-04     3
92022-01-05     4
10              ..
112022-04-06    95
122022-04-07    96
132022-04-08    97
142022-04-09    98
152022-04-10    99
16Freq: D, Length: 100dtype: int32
17
18>>> ts.resample("M").max()
192022-01-31    30
202022-02-28    58
212022-03-31    89
222022-04-30    99
23Freq: M, dtype: int32
24
25>>> ts.resample(rule="M",kind="period").max() #对区间进行聚合262022-01    30
272022-02    58
282022-03    89
292022-04    99
30Freq: M, dtype: int32

resample 是一种灵活且高性能的方法,可用于处理大型时间序列。下表总结了resample的一些选项。

参数
说明
rule 表示所需重采样频率的字符串、DateOffset或timedelta对象(例如,’M’、’5min’或Second(15))
axis 需要重新采样的轴;默认情况axis=0
fill_method 向上采样时的插值方式,"ffill"  "bfill"; 默认不进行插值
closed 向下采样时每个区间的哪一端是封闭的(包含的),"right"  "left"
label 向下采样时,如何使用"right"  "left"的箱体标签标记聚合结果(例如,9:30到9:35的5分钟间隔可以被标记为9:30或9:35)
limit 当向前或向后填充时,填充区间的最大值
kind 对区间("period")或时间戳("timestamp")的聚合;默认为时间序列索引的类型
convention 在对区间重新采样时,用于将低频率转换为高频率的约定("start" 或 "end") 认为“end”
origin 确定重采样箱边缘的“基础”时间戳;也可以是"epoch""start""start_day""end", "end_day"之一
offset 添加到原始数据上的偏移时间间隔默认为None
1.向下采样:

向下采样将数据聚合到一个规则的、较低的频率。你正在聚合的数据不必是固定频率的,所需要的频率定义类用于对时间序列切片以聚合的箱体(bins)边缘。

例如,要将时间转换为每月(MBM),需要将数据分成一个月的时间间隔。每个间隔是半闭合的,一个数据点只属于一个时间间隔,时间间隔的并集必须是整个时间范围。

在使用resample方法进行向下采样时,需要考虑以下两点:
  • 每段时间间隔的哪一边是闭合的;

  • 如何在时间间隔的起始或结束位置标记每个已聚合的箱体bins。
 1# 首先生成一些一小时内的频率数据
2>>> dates = pd.date_range("2022-01-01", periods=12, freq="H")
3
4>>> ts = pd.Series(np.arange(len(dates)), index=dates)
5>>> ts
62022-01-01 00:00:00     0
72022-01-01 01:00:00     1
82022-01-01 02:00:00     2
92022-01-01 03:00:00     3
102022-01-01 04:00:00     4
112022-01-01 05:00:00     5
122022-01-01 06:00:00     6
132022-01-01 07:00:00     7
142022-01-01 08:00:00     8
152022-01-01 09:00:00     9
162022-01-01 10:00:00    10
172022-01-01 11:00:00    11
18Freq: H, dtype: int32
19
20# 通过计算每一组的加和将这些数据聚合到5小时的块或柱内
21>>> ts.resample("5h").sum()
222022-01-01 00:00:00    10
232022-01-01 05:00:00    35
242022-01-01 10:00:00    21
25Freq: 5H, dtype: int32
  • closed参数:
 1# closed="left":向下采样时每个区间的左端是封闭的(包含的)
2# 此时,传递的频率以5小时的增量定义箱体边界。对于这个频率,默认情况下,左箱体边界是包含的,
3# 因此00:00值包含在00:00 到05:00 时间间隔内,而05:00值不包含在该时间间隔内。
4>>> ts.resample("5h" , closed="left").sum()
52022-01-01 00:00:00    10
62022-01-01 05:00:00    35
72022-01-01 10:00:00    21
8Freq: 5H, dtype: int32
9
10# closed="right":向下采样时每个区间的右端是封闭的(包含的)
11# 因此00:00值不包含在00:00 到05:00 时间间隔内,而05:00值包含在该时间间隔内。
12>>> ts.resample("5h" , closed="right").sum()
132021-12-31 19:00:00     0
142022-01-01 00:00:00    15
152022-01-01 05:00:00    40
162022-01-01 10:00:00    11
17Freq: 5H, dtype: int32
  • label参数:

1# 生成的时间序列由每个箱体左侧的时间戳标记。通过传递 label="right",你可以用右箱体边界标记它们
2>>> ts.resample("5h" , closed="right" , label="right").sum()
32022-01-01 00:00:00     0
42022-01-01 05:00:00    15
52022-01-01 10:00:00    40
62022-01-01 15:00:00    11
7Freq: 5H, dtype: int32
  • to_offset:

如果希望将结果索引移动一定的数量。例如从右边界减去一小时,以便更清楚时间戳指的是那个时间间隔。要实现该功能,需要向结果索引添加一个偏移量。

 1>>> from pandas.tseries.frequencies import to_offset
2
3>>> result = ts.resample("5h", closed="right", label="right").sum()
4>>> result
52022-01-01 00:00:00     0
62022-01-01 05:00:00    15
72022-01-01 10:00:00    40
82022-01-01 15:00:00    11
9Freq: 5H, dtype: int32
10
11>>> result.index = result.index + to_offset("-1h")
12
13>>> result
142021-12-31 23:00:00     0
152022-01-01 04:00:00    15
162022-01-01 09:00:00    40
172022-01-01 14:00:00    11
18Freq: 5H, dtype: int32
1.1 开端-峰值-谷值-结束(OHLC)重新采样:

在金融领域,聚合时间序列的一种流行方法是为每个桶计算四个值:第一个值(开端)、最后一个值(结束)、最大值(峰值)、最小值(谷值)。

通过使用 ohlc 聚合函数,将会获得包含四种聚合值的DataFrame,这些值在数据的单词函数调用中被高效计算:

 1>>> ts = pd.Series(np.random.permutation(np.arange(len(dates))), index=dates)
2>>> ts
32022-01-01 00:00:00    11
42022-01-01 01:00:00     7
52022-01-01 02:00:00     4
62022-01-01 03:00:00    10
72022-01-01 04:00:00     1
82022-01-01 05:00:00     8
92022-01-01 06:00:00     5
102022-01-01 07:00:00     2
112022-01-01 08:00:00     6
122022-01-01 09:00:00     3
132022-01-01 10:00:00     0
142022-01-01 11:00:00     9
15Freq: H, dtype: int32
16
17>>> ts.resample("5h").ohlc()
18                     open  high  low  close
192022-01-01 00:00:00    11    11    1      1
202022-01-01 05:00:00     8     8    2      3
212022-01-01 10:00:00     0     9    0      9
2.向上采样(Upsampling )和插值(Interpolation):

向上采样是从较低频率转换为较高频率,不需要聚合。

1# 首先生成一个包含每周数据的DataFrame
2>>> df = pd.DataFrame(np.arange(6).reshape((23)),
3...                      index=pd.date_range("2022-01-01",periods=2,freq="W-MON"),# W-MON:每周一
4...                      columns=["A""B""C"])
5
6>>> df
7            A  B  C
82022-01-03  0  1  2
92022-01-10  3  4  5

当对该数据使用聚合函数时,每一组只有一个值,会在间隙中产生缺失值。使用 asfreq 方法在不聚合的情况下转换到更高频率:

 1>>> df_daily = df.resample("D").asfreq()
2>>> df_daily
3              A    B    C
42022-01-03  0.0  1.0  2.0
52022-01-04  NaN  NaN  NaN
62022-01-05  NaN  NaN  NaN
72022-01-06  NaN  NaN  NaN
82022-01-07  NaN  NaN  NaN
92022-01-08  NaN  NaN  NaN
102022-01-09  NaN  NaN  NaN
112022-01-10  3.0  4.0  5.0

fillnareindex方法中可用的填充或插值方法可用于重采样。

 1# 假设你想在非周一的日期上向前填充每周数值
2>>> df.resample("D").ffill()
3            A  B  C
42022-01-03  0  1  2
52022-01-04  0  1  2
62022-01-05  0  1  2
72022-01-06  0  1  2
82022-01-07  0  1  2
92022-01-08  0  1  2
102022-01-09  0  1  2
112022-01-10  3  4  5
12
13# 也可以选择仅向前填充一定数量的区间,以限制继续使用观测值的时距离
14>>> df.resample("D").ffill(limit=3)
15              A    B    C
162022-01-03  0.0  1.0  2.0
172022-01-04  0.0  1.0  2.0
182022-01-05  0.0  1.0  2.0
192022-01-06  0.0  1.0  2.0
202022-01-07  NaN  NaN  NaN
212022-01-08  NaN  NaN  NaN
222022-01-09  NaN  NaN  NaN
232022-01-10  3.0  4.0  5.0

需要注意的是,新日期索引根本不需要与旧日期索引重合:

1# W-TUE:每周二
2>>> df.resample("W-TUE").ffill()
3            A  B  C
42022-01-04  0  1  2
52022-01-11  3  4  5


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments