窗口操作#
pandas 包含一套紧凑的 API,用于执行窗口操作——即在值的滑动分区上执行聚合的操作。该 API 的工作方式类似于 groupby API,即 Series 和 DataFrame 使用必要的参数调用窗口方法,然后依次调用聚合函数。
窗口是通过从当前观测值向前回溯窗口长度来构成的。上述结果可以通过对以下窗口化数据分区求和得出:
概述#
pandas 支持 4 种类型的窗口操作:
滚动窗口:在值上进行通用的固定或可变滑动窗口。
加权窗口:由
scipy.signal库提供的加权、非矩形窗口。扩展窗口:在值上进行累积窗口。
指数加权窗口:在值上进行累积和指数加权窗口。
概念 |
方法 |
返回对象 |
支持基于时间的窗口 |
支持链式 groupby |
支持 table 方法 |
支持在线操作 |
|---|---|---|---|---|---|---|
滚动窗口 |
|
|
是 |
是 |
是 (1.3 版本开始) |
否 |
加权窗口 |
|
|
否 |
否 |
否 |
否 |
扩展窗口 |
|
|
否 |
是 |
是 (1.3 版本开始) |
否 |
指数加权窗口 |
|
|
否 |
是 (1.2 版本开始) |
否 |
是 (1.3 版本开始) |
如上所述,一些操作支持指定一个基于偏移量的窗口:
此外,一些方法支持将 groupby 操作与窗口操作链接起来,它会首先按指定的键对数据进行分组,然后对每个组执行窗口操作。
备注
窗口操作目前仅支持数值型数据(整数和浮点数),并且将始终返回 float64 类型的值。
警告
某些窗口聚合操作,如 mean, sum, var 和 std 方法可能会由于底层的窗口算法累积求和而产生数值不精确的问题。当数值相差 \(1/np.finfo(np.double).eps\) 时,会导致截断。必须注意的是,较大的值可能会影响不包含这些值的窗口。为了尽可能地保持精度,会使用 Kahan summation 来计算滚动求和。
在 1.3.0 版本加入.
某些窗口操作还支持构造函数中的 method='table' 选项,该选项会作用于整个 DataFrame 而不是一次处理单个列或行。这可以为具有许多列或行的 DataFrame (以及相应的 axis 参数) 提供有用的性能优势,或者能够利用其他列来执行窗口操作。仅当在相应的调用方法中指定了 engine='numba' 时,才能使用 method='table' 选项。
例如,可以通过指定一个单独的权重列,使用 weighted mean 来计算 apply() 。
在 1.3 版本加入.
某些窗口操作还支持在构造窗口对象后使用的 online 方法,该方法返回一个新对象,支持传入新的 DataFrame 或 Series 对象以继续进行窗口计算(即在线计算)。
此新窗口对象上的方法必须先调用聚合方法来“预热”在线计算的初始状态。然后,可以将新的 DataFrame 或 Series 对象传递给 update 参数以继续进行窗口计算。
所有窗口操作都支持 min_periods 参数,该参数规定了窗口中必须包含的非 np.nan 值的最小数量;否则,结果值为 np.nan。时间类窗口 min_periods 的默认值为 1,固定窗口的默认值为 window。
此外,所有窗口操作都支持 aggregate 方法,用于返回应用于窗口的多个聚合结果。
滚动窗口#
通用的滚动窗口支持将窗口指定为固定数量的观测值,或者根据偏移量指定可变数量的观测值。如果提供了基于时间的偏移量,则相应的基于时间的索引必须是单调的。
有关所有支持的聚合函数,请参阅 滚动窗口函数 。
中心化窗口#
默认情况下,标签设置在窗口的右边缘,但有一个 center 关键字可用,因此标签可以设置在中心。
这也适用于类 datetime 索引。
在 1.3.0 版本加入.
滚动窗口端点#
可以使用 closed 参数来指定是否在滚动窗口计算中包含区间端点:
值 |
行为 |
|---|---|
|
闭合右端点 |
|
闭合左端点 |
|
|
|
开放端点 |
例如,在许多需要避免当前信息影响过去信息的问题中,将右端点设置为开放是有用的。这允许滚动窗口计算“直到那一时刻”的统计数据,但不包括那一时刻。
自定义窗口滚动#
除了接受整数或偏移量作为 window 参数外,rolling 还接受 BaseIndexer 子类,允许用户定义计算窗口边界的自定义方法。BaseIndexer 子类需要定义一个 get_window_bounds 方法,该方法返回一个包含两个数组的元组,第一个数组是窗口的起始索引,第二个数组是窗口的结束索引。此外,num_values、min_periods、center、closed 和 step 将自动传递给 get_window_bounds,并且定义的该方法必须始终接受这些参数。
例如,如果我们有以下 DataFrame
并且我们想使用一个扩展窗口,其中 use_expanding 为 True,否则使用大小为 1 的窗口,我们可以创建以下 BaseIndexer 子类:
您可以 here 查看 BaseIndexer 子类的其他示例
其中一个值得注意的子类是 VariableOffsetWindowIndexer,它允许在非固定偏移量(如 BusinessDay)上进行滚动操作。
对于某些问题,未来的知识可用于分析。例如,当每个数据点都是从实验中读取的完整时间序列时,就会发生这种情况,任务是提取潜在的条件。在这些情况下,执行前瞻性滚动窗口计算可能很有用。为此,可以使用 FixedForwardWindowIndexer 类。这个 BaseIndexer 子类实现了一个封闭的固定宽度前瞻性滚动窗口,我们可以如下使用它:
我们也可以通过使用切片、应用滚动聚合,然后翻转结果来实现这一点,如下面的示例所示:
滚动应用#
apply() 函数接受一个额外的 func 参数,并执行通用的滚动计算。func 参数应该是一个从 ndarray 输入产生单个值的函数。raw 指定窗口是作为 Series 对象(raw=False)还是 ndarray 对象(raw=True)进行转换。
Numba 引擎#
此外,apply() 可以利用 Numba (如果已安装为可选依赖项)。可以通过指定 engine='numba' 和 engine_kwargs 参数(raw 也必须设置为 True)来使用 Numba 执行 apply 聚合。有关参数的一般用法和性能注意事项,请参阅 enhancing performance with Numba 。
Numba 可应用于可能两个例程:
如果
func是标准的 Python 函数,引擎将对传入的函数进行 JIT 编译。func也可以是已 JIT 编译的函数,在这种情况下,引擎不会再次 JIT 编译该函数。引擎将 JIT 编译应用于每个窗口的 apply 函数的 for 循环。
engine_kwargs 参数是一个字典,其中包含将传递给 numba.jit decorator 的关键字参数。这些关键字参数将应用于传入的函数(如果是标准 Python 函数)以及应用于每个窗口的 for 循环。
在 1.3.0 版本加入.
mean、median、max、min 和 sum 也支持 engine 和 engine_kwargs 参数。
二元窗口函数#
cov() 和 corr() 可以计算两个 Series 或 DataFrame Series 或 DataFrame DataFrame 的任意组合的移动窗口统计信息。每种情况下的行为如下:
两个
Series:计算配对的统计信息。DataFrameSeries:计算 DataFrame 中每列与传入 Series 的统计信息,从而返回一个 DataFrame。DataFrameDataFrame:默认情况下,计算匹配列名的统计信息,返回一个 DataFrame。如果传递关键字参数pairwise=True,则计算每对列的统计信息,返回一个具有DataFrame的MultiIndex,其值为相关的日期(请参阅 the next section )。
例如:
计算滚动成对协方差和相关性#
在金融数据分析和其他领域,通常需要计算一系列时间序列的协方差和相关性矩阵。通常,人们也对移动窗口的协方差和相关性矩阵感兴趣。这可以通过传递 pairwise 关键字参数来实现,在 DataFrame 输入的情况下,这将产生一个 MultiIndexed DataFrame ,其 index 是相关的日期。在只有一个 DataFrame 参数的情况下,甚至可以省略 pairwise 参数:
备注
缺失值将被忽略,并且每个条目都使用成对完整观测值进行计算。
假设缺失数据是随机缺失的,这将导致协方差矩阵的估计是无偏的。然而,对于许多应用来说,这种估计可能无法接受,因为估计的协方差矩阵不保证是半正定的。这可能导致估计的相关值具有大于一的绝对值,和/或一个不可逆的协方差矩阵。更多细节请参见 Estimation of covariance matrices 。
加权窗口#
.rolling 中的 win_type 参数会生成常用于滤波和谱估计的加权窗口。win_type 必须是与 scipy.signal window function 对应的字符串。为了使用这些窗口,必须安装 Scipy,并且 Scipy 窗口方法接受的补充参数必须在聚合函数中指定。
有关所有支持的聚合函数,请参阅 加权窗口函数 。
扩展窗口#
扩展窗口会生成一个聚合统计值的数值,该数值包含了截至该时间点所有可用数据。由于这些计算是滚动统计的特例,因此在 pandas 中实现它们的方式如下,以下两个调用是等效的:
有关所有支持的聚合函数,请参阅 Expanding window functions 。
指数加权窗口#
指数加权窗口类似于扩展窗口,但每个先前点相对于当前点都呈指数衰减权重。
通常,加权移动平均计算如下:
其中 \(x_t\) 是输入,\(y_t\) 是结果,\(w_i\) 是权重。
有关所有支持的聚合函数,请参阅 Exponentially-weighted window functions 。
EW 函数支持两种指数权重变体。默认的 adjust=True 使用权重 \(w_i = (1 - \alpha)^i\) ,得到:
当指定 adjust=False 时,移动平均计算如下:
这等价于使用以下权重:
备注
这些方程有时用 \(\alpha' = 1 - \alpha\) 来表示,例如:
上述两种变体之间的区别在于我们处理的是具有有限历史的序列。考虑一个具有无限历史的序列,当 adjust=True 时:
注意到分母是一个公比为 \(1 - \alpha\) ,首项为 1 的几何级数,我们得到:
这与上面 adjust=False 的表达式相同,因此对于无限序列,这两种变体是等效的。当 adjust=False 时,我们有 \(y_0 = x_0\) 和 \(y_t = \alpha x_t + (1 - \alpha) y_{t-1}\) 。因此,这里假设 \(x_0\) 不是一个普通值,而是该点之前无限序列的指数加权矩。
必须有 \(0 < \alpha \leq 1\) ,虽然可以直接传递 \(\alpha\) ,但通常更容易考虑 EW(指数加权)矩的**跨度 (span)**、质心 (center of mass, com) 或**半衰期 (half-life)**:
必须精确指定 span、center of mass、half-life 和 alpha 中的一个参数给 EW 函数:
Span 对应于通常所说的“N 日 EW 移动平均”。
Center of mass 具有更物理的解释,可以从跨度来考虑:\(c = (s - 1) / 2\) 。
Half-life 是指数权重减半所需的时间周期。
Alpha 直接指定平滑因子。
您还可以根据可转换为 timedelta 的单位指定 halflife,以指定当同时指定一系列 times 时,观测值衰减到其值的一半所需的时间量。
以下公式用于计算带有时间输入向量的指数加权移动平均:
ExponentialMovingWindow 还有一个 ignore_na 参数,它决定中间的 null 值如何影响权重的计算。当 ignore_na=False`(默认值)时,权重是基于绝对位置计算的,因此中间的 null 值会影响结果。当 `ignore_na=True 时,通过忽略中间的 null 值来计算权重。例如,假设 adjust=True,如果 ignore_na=False,则 3, NaN, 5 的加权平均计算如下:
而如果 ignore_na=True,则加权平均计算如下:
:meth:`~Ewm.var :meth:`~Ewm.std 和 :meth:`~Ewm.cov 函数有一个 bias 参数,指定结果是包含有偏统计量还是无偏统计量。例如,如果 bias=True,则 ewmvar(x) 计算为 ewmvar(x) = ewma(x**2) - ewma(x)**2;而如果 `bias=False`(默认值),则有偏方差统计量会乘以去偏因子:
(对于 \(w_i = 1\) ,这可以简化为通常的 \(N / (N - 1)\) 因子,其中 \(N = t + 1\) 。)有关更多详细信息,请参阅 Wikipedia 上的 Weighted Sample Variance 。