Python 时间序列分析:Pandas Resampling 和 Rolling 的高级用法
大家好,今天我们深入探讨 Pandas 在时间序列分析中两个非常强大的工具:Resampling (重采样) 和 Rolling (滚动窗口)。我们将不仅仅停留在基本用法上,而是着重讲解它们的高级特性,并通过实际的代码示例来展示如何灵活运用它们解决实际问题。
1. Resampling 的高级用法
Resampling 是将时间序列数据从一个频率转换为另一个频率的过程。这在处理不同时间粒度的数据,例如将每日数据聚合为每月数据,或将分钟数据插值为小时数据时非常有用。
1.1. loffset
:调整标签时间
loffset
参数允许我们调整重采样后生成的标签时间。默认情况下,Pandas 会将聚合后的区间的左端点作为标签。loffset
允许我们将其移动到区间的右端点,中心或其他任何时间点。
import pandas as pd
import numpy as np
# 创建一个示例时间序列
rng = pd.date_range('2023-01-01', periods=10, freq='D')
ts = pd.Series(np.arange(10), index=rng)
# 按周重采样,并使用 loffset 将标签移动到周五
weekly_sum = ts.resample('W-FRI').sum()
print("默认标签 (周日):")
print(ts.resample('W').sum())
print("n使用 loffset 后的标签 (周五):")
print(weekly_sum)
在这个例子中,resample('W').sum()
默认使用每周的起始日(星期日)作为标签。而 resample('W-FRI').sum()
则使用每周的星期五作为标签。
1.2. label
:选择标签位置
label
参数用于确定使用哪个区间边缘作为标签。它可以取两个值:'left'
(默认)和 'right'
。
# 按天重采样,但使用右侧边缘作为标签
daily_sum_right = ts.resample('D', label='right').sum()
print("默认标签 (左侧):")
print(ts.resample('D', label='left').sum()) # 默认行为,等价于 ts.resample('D').sum()
print("n右侧标签:")
print(daily_sum_right)
在这个例子中,label='right'
使得重采样后的标签指向每天的结束时间。 虽然在这里的效果看起来和没有重采样一样,但在更复杂的重采样频率下(例如,从小时到天),label
参数的效果会更加明显。
1.3. closed
:选择包含哪个区间端点
closed
参数用于确定哪些区间端点应该包含在重采样区间中。它可以取两个值:'right'
(默认)和 'left'
。
# 创建一个新的时间序列,频率为小时
rng = pd.date_range('2023-01-01', periods=24, freq='H')
ts = pd.Series(np.arange(24), index=rng)
# 按天重采样,并使用 closed='left' 包含左侧端点
daily_sum_left = ts.resample('D', closed='left').sum()
print("默认 closed (右侧):")
print(ts.resample('D', closed='right').sum()) # 默认行为
print("n包含左侧端点:")
print(daily_sum_left)
closed='left'
表示每个重采样区间包含左侧端点但不包含右侧端点。 这意味着,例如,对于 2023-01-01,它将包含 2023-01-01 00:00:00 到 2023-01-01 23:00:00 的数据,而不包含 2023-01-02 00:00:00 的数据。
1.4. on
:指定重采样的列
当DataFrame包含多个列时,on
参数允许我们指定哪个列应该被用作重采样的索引。
# 创建一个包含日期的 DataFrame
data = {'date': pd.date_range('2023-01-01', periods=10),
'value': np.arange(10)}
df = pd.DataFrame(data)
# 使用 'date' 列作为重采样的索引
df_resampled = df.resample('2D', on='date').sum() # 每两天求和
print(df_resampled)
在这个例子中,df.resample('2D', on='date').sum()
将DataFrame按照’date’列进行每两天一次的重采样,并对’value’列进行求和。注意,on
参数需要将指定的列提升为索引,否则 resample
方法无法找到用于重采样的索引。
1.5. 自定义重采样函数
resample
配合 apply
方法可以实现更加复杂的重采样操作。我们可以定义自己的聚合函数,并在重采样后应用它。
# 定义一个自定义的聚合函数,计算中位数和标准差
def custom_agg(x):
return pd.Series({'median': x.median(), 'std': x.std()})
# 按周重采样,并应用自定义的聚合函数
weekly_agg = ts.resample('W').apply(custom_agg)
print(weekly_agg)
在这个例子中,custom_agg
函数计算了每个重采样区间的的中位数和标准差。 apply
方法将这个函数应用到每个重采样区间,从而得到包含中位数和标准差的DataFrame。
2. Rolling 的高级用法
Rolling (滚动窗口) 允许我们对时间序列数据应用一个滑动窗口,并在每个窗口上执行计算。这对于平滑数据,计算移动平均值,或其他基于窗口的统计量非常有用。
2.1. win_type
:选择窗口类型
win_type
参数允许我们选择不同的窗口类型。除了默认的矩形窗口外,Pandas 还提供了多种其他窗口类型,例如三角窗,汉明窗,高斯窗等。
# 计算移动平均值,使用三角窗
rolling_triangle = ts.rolling(window=3, win_type='triang').mean()
print("矩形窗:")
print(ts.rolling(window=3).mean())
print("n三角窗:")
print(rolling_triangle)
不同的窗口类型会对计算结果产生不同的影响。三角窗对窗口中心的值赋予更高的权重,而对窗口边缘的值赋予更低的权重,从而使得移动平均值更加平滑。
2.2. center
:居中窗口
center
参数允许我们将窗口居中对齐。默认情况下,窗口是向后对齐的,这意味着计算结果对应于窗口的最后一个数据点。将 center
设置为 True
可以将窗口居中对齐,使得计算结果对应于窗口的中心数据点。
# 计算移动平均值,并将窗口居中
rolling_centered = ts.rolling(window=3, center=True).mean()
print("非居中窗口:")
print(ts.rolling(window=3).mean())
print("n居中窗口:")
print(rolling_centered)
使用居中窗口可以减少延迟,使得移动平均值更好地反映数据的趋势。
2.3. axis
:指定滚动轴
当处理DataFrame时,axis
参数允许我们指定沿着哪个轴进行滚动。默认情况下,axis=0
,表示沿着行进行滚动。我们可以将其设置为 axis=1
,以沿着列进行滚动。
# 创建一个 DataFrame
df = pd.DataFrame(np.random.randn(5, 3), columns=['A', 'B', 'C'])
# 沿着列计算移动平均值
rolling_cols = df.rolling(window=2, axis=1).mean()
print("原始数据:")
print(df)
print("n沿着列滚动:")
print(rolling_cols)
在这个例子中,df.rolling(window=2, axis=1).mean()
计算了每行的相邻两列的平均值。
2.4. method
:指定计算方法
method
参数允许我们指定滚动窗口的计算方法。它可以取两个值:'single'
(默认)和 'table'
。 'single'
方法逐个计算每个窗口的值,而 'table'
方法将数据组织成一个表格,然后对表格进行计算,这在某些情况下可以提高性能。
# 创建一个较大的时间序列
rng = pd.date_range('2023-01-01', periods=1000, freq='D')
ts = pd.Series(np.random.randn(1000), index=rng)
# 计算移动平均值,并使用 'table' 方法
rolling_table = ts.rolling(window=10, method='table').mean()
# 默认方法
rolling_single = ts.rolling(window=10, method='single').mean()
# 可以用 timeit 模块测试性能差异
# import timeit
# single_time = timeit.timeit(lambda: ts.rolling(window=10, method='single').mean(), number=100)
# table_time = timeit.timeit(lambda: ts.rolling(window=10, method='table').mean(), number=100)
# print(f"Single method time: {single_time}")
# print(f"Table method time: {table_time}")
print("Table method:")
print(rolling_table.head())
print("nSingle method:")
print(rolling_single.head())
对于大型数据集,method='table'
通常比 method='single'
更加高效。
2.5. 自定义滚动窗口函数
与重采样类似,我们可以使用 apply
方法将自定义函数应用到每个滚动窗口。
# 定义一个自定义的滚动窗口函数,计算窗口内的最大值和最小值之差
def custom_rolling(x):
return x.max() - x.min()
# 计算滚动窗口内的最大值和最小值之差
rolling_range = ts.rolling(window=10).apply(custom_rolling)
print(rolling_range.head(15))
在这个例子中,custom_rolling
函数计算了每个滚动窗口内的最大值和最小值之差。apply
方法将这个函数应用到每个滚动窗口,从而得到一个包含滚动窗口范围的Series。
2.6 closed
:定义窗口端点包含情况
closed
参数在滚动窗口中与重采样中的含义类似,控制窗口端点是否包含在窗口内。它接受的值有:'right'
(默认),'left'
,'both'
,和 'neither'
。
'right'
: 窗口包含右端点,不包含左端点。'left'
: 窗口包含左端点,不包含右端点。'both'
: 窗口包含左右两个端点。'neither'
: 窗口不包含左右任何端点。
# 使用不同的 closed 参数
print("默认(right):")
print(ts.rolling(window=3).mean().head())
print("nLeft:")
print(ts.rolling(window=3, closed='left').mean().head())
print("nBoth:")
print(ts.rolling(window=3, closed='both').mean().head())
print("nNeither:")
print(ts.rolling(window=3, closed='neither').mean().head())
closed
参数影响窗口的包含规则,在某些情况下,特别是当窗口大小较小时,会对计算结果产生显著影响。
3. 实际应用案例
现在,我们通过一个实际的应用案例来展示如何结合使用 Resampling 和 Rolling。
假设我们有某个股票的每日收盘价数据,我们想要计算该股票的月度平均收盘价,并计算过去三个月的移动平均值。
# 从 CSV 文件中读取股票数据
# 这里假设你有一个名为 'stock_data.csv' 的文件,包含 'Date' 和 'Close' 两列
try:
stock_data = pd.read_csv('stock_data.csv', parse_dates=['Date'], index_col='Date')
except FileNotFoundError:
print("请先准备好 stock_data.csv 文件,包含 Date 和 Close 两列")
exit()
# 按月重采样,计算月度平均收盘价
monthly_avg = stock_data['Close'].resample('M').mean()
# 计算过去三个月的移动平均值
rolling_monthly_avg = monthly_avg.rolling(window=3).mean()
# 打印结果
print("月度平均收盘价:")
print(monthly_avg)
print("n过去三个月的移动平均值:")
print(rolling_monthly_avg)
在这个例子中,我们首先使用 resample('M').mean()
将每日数据转换为月度平均数据。然后,我们使用 rolling(window=3).mean()
计算过去三个月的移动平均值,从而平滑月度数据并更好地反映股票的长期趋势。
4. 总结
我们深入探讨了 Pandas 中 Resampling 和 Rolling 的高级用法,包括 loffset
,label
,closed
,on
,win_type
,center
,axis
和 method
等参数。我们还展示了如何使用 apply
方法将自定义函数应用到重采样区间和滚动窗口。通过实际的应用案例,我们展示了如何结合使用 Resampling 和 Rolling 来解决实际问题。 掌握这些高级技巧可以帮助你更有效地处理和分析时间序列数据。
Resampling 和 Rolling 的核心功能
Resampling 用于改变时间序列数据的频率,而 Rolling 则用于在滑动窗口上计算统计量。理解它们的高级参数和自定义函数可以极大地扩展时间序列分析的能力。