窗口操作
pandas 包含一组紧凑的 API,用于执行窗口操作 - 一种在值的滑动分区上执行聚合的操作。该 API 的功能类似于groupby
API,Series
和DataFrame
调用具有必要参数的窗口方法,然后随后调用聚合函数。
In [1]: s = pd.Series(range(5)) In [2]: s.rolling(window=2).sum() Out[2]: 0 NaN 1 1.0 2 3.0 3 5.0 4 7.0 dtype: float64
窗口由从当前观察值向后查看窗口长度组成。上述结果可以通过对数据的以下窗口分区求和来得出:
In [3]: for window in s.rolling(window=2): ...: print(window) ...: 0 0 dtype: int64 0 0 1 1 dtype: int64 1 1 2 2 dtype: int64 2 2 3 3 dtype: int64 3 3 4 4 dtype: int64
概述
pandas 支持 4 种类型的窗口操作:
- 滚动窗口:对值进行通用固定或可变滑动窗口。
- 加权窗口:由
scipy.signal
库提供的加权非矩形窗口。 - 扩展窗口:对值进行累积窗口。
- 指数加权窗口:对值进行累积和指数加权窗口。
概念 | 方法 | 返回对象 | 支持基于时间的窗口 | 支持链式分组 | 支持表方法 | 支持在线操作 |
滚动窗口 | rolling |
pandas.typing.api.Rolling |
是 | 是 | 是(自 1.3 版本起) | 否 |
加权窗口 | rolling |
pandas.typing.api.Window |
否 | 否 | 否 | 否 |
扩展窗口 | expanding |
pandas.typing.api.Expanding |
否 | 是 | 是(自 1.3 版本起) | 否 |
指数加权窗口 | ewm |
pandas.typing.api.ExponentialMovingWindow |
否 | 是(自 1.2 版本起) | 否 | 是(自 1.3 版本起) |
如上所述,一些操作支持根据时间偏移量指定窗口:
In [4]: s = pd.Series(range(5), index=pd.date_range('2020-01-01', periods=5, freq='1D')) In [5]: s.rolling(window='2D').sum() Out[5]: 2020-01-01 0.0 2020-01-02 1.0 2020-01-03 3.0 2020-01-04 5.0 2020-01-05 7.0 Freq: D, dtype: float64
此外,一些方法支持将groupby
操作与窗口操作链接在一起,该操作将首先按指定键对数据进行分组,然后对每个组执行窗口操作。
In [6]: df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a'], 'B': range(5)}) In [7]: df.groupby('A').expanding().sum() Out[7]: B A a 0 0.0 2 2.0 4 6.0 b 1 1.0 3 4.0
注意
窗口操作目前仅支持数值数据(整数和浮点数),并且始终返回float64
值。
警告
一些窗口聚合方法,mean
,sum
,var
和std
方法可能由于底层窗口算法累积和而受到数值不精确性的影响。当值的数量级不同时(1/np.finfo(np.double).eps),会导致截断。必须注意,大值可能会对不包括这些值的窗口产生影响。使用Kahan 求和算法来计算滚动求和以尽可能保持准确性。
自 1.3.0 版本起新增。
一些窗口操作还支持构造函数中的method='table'
选项,该选项可以在整个DataFrame
上执行窗口操作,而不是一次处理单个列或行。对于具有许多列或行(使用相应的axis
参数)的DataFrame
,这可以提供有用的性能优势,或者在窗口操作期间利用其他列。只有在相应的方法调用中指定了engine='numba'
时,才能使用method='table'
选项。
例如,可以通过在apply()
中指定一个权重列来计算加权平均值。
In [8]: def weighted_mean(x): ...: arr = np.ones((1, x.shape[1])) ...: arr[:, :2] = (x[:, :2] * x[:, 2]).sum(axis=0) / x[:, 2].sum() ...: return arr ...: In [9]: df = pd.DataFrame([[1, 2, 0.6], [2, 3, 0.4], [3, 4, 0.2], [4, 5, 0.7]]) In [10]: df.rolling(2, method="table", min_periods=0).apply(weighted_mean, raw=True, engine="numba") # noqa: E501 Out[10]: 0 1 2 0 1.000000 2.000000 1.0 1 1.800000 2.000000 1.0 2 3.333333 2.333333 1.0 3 1.555556 7.000000 1.0
1.3 版本中新增。
一些窗口操作在构造窗口对象后还支持online
方法,该方法返回一个新对象,支持传入新的DataFrame
或Series
对象,以使用新值继续窗口计算(即在线计算)。
新窗口对象上的方法必须首先调用聚合方法以“启动”在线计算的初始状态。然后,可以通过update
参数传递新的DataFrame
或Series
对象来继续窗口计算。
In [11]: df = pd.DataFrame([[1, 2, 0.6], [2, 3, 0.4], [3, 4, 0.2], [4, 5, 0.7]]) In [12]: df.ewm(0.5).mean() Out[12]: 0 1 2 0 1.000000 2.000000 0.600000 1 1.750000 2.750000 0.450000 2 2.615385 3.615385 0.276923 3 3.550000 4.550000 0.562500
In [13]: online_ewm = df.head(2).ewm(0.5).online() In [14]: online_ewm.mean() Out[14]: 0 1 2 0 1.00 2.00 0.60 1 1.75 2.75 0.45 In [15]: online_ewm.mean(update=df.tail(1)) Out[15]: 0 1 2 3 3.307692 4.307692 0.623077
所有窗口操作都支持一个min_periods
参数,该参数规定窗口必须具有的非np.nan
值的最小数量;否则,结果值为np.nan
。对于基于时间的窗口,默认值为 1,对于固定窗口,默认为window
。
In [16]: s = pd.Series([np.nan, 1, 2, np.nan, np.nan, 3]) In [17]: s.rolling(window=3, min_periods=1).sum() Out[17]: 0 NaN 1 1.0 2 3.0 3 3.0 4 2.0 5 3.0 dtype: float64 In [18]: s.rolling(window=3, min_periods=2).sum() Out[18]: 0 NaN 1 NaN 2 3.0 3 3.0 4 NaN 5 NaN dtype: float64 # Equivalent to min_periods=3 In [19]: s.rolling(window=3, min_periods=None).sum() Out[19]: 0 NaN 1 NaN 2 NaN 3 NaN 4 NaN 5 NaN dtype: float64
此外,所有窗口操作都支持aggregate
方法,用于返回应用于窗口的多个聚合的结果。
In [20]: df = pd.DataFrame({"A": range(5), "B": range(10, 15)}) In [21]: df.expanding().agg(["sum", "mean", "std"]) Out[21]: A B sum mean std sum mean std 0 0.0 0.0 NaN 10.0 10.0 NaN 1 1.0 0.5 0.707107 21.0 10.5 0.707107 2 3.0 1.0 1.000000 33.0 11.0 1.000000 3 6.0 1.5 1.290994 46.0 11.5 1.290994 4 10.0 2.0 1.581139 60.0 12.0 1.581139 ```## 滚动窗口 通用滚动窗口支持将窗口指定为固定数量的观测值或基于偏移量的可变数量的观测值。如果提供了基于时间的偏移量,则相应的基于时间的索引必须是单调的。 ```py In [22]: times = ['2020-01-01', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-29'] In [23]: s = pd.Series(range(5), index=pd.DatetimeIndex(times)) In [24]: s Out[24]: 2020-01-01 0 2020-01-03 1 2020-01-04 2 2020-01-05 3 2020-01-29 4 dtype: int64 # Window with 2 observations In [25]: s.rolling(window=2).sum() Out[25]: 2020-01-01 NaN 2020-01-03 1.0 2020-01-04 3.0 2020-01-05 5.0 2020-01-29 7.0 dtype: float64 # Window with 2 days worth of observations In [26]: s.rolling(window='2D').sum() Out[26]: 2020-01-01 0.0 2020-01-03 1.0 2020-01-04 3.0 2020-01-05 5.0 2020-01-29 4.0 dtype: float64
查看所有支持的聚合函数,请参阅滚动窗口函数。
居中窗口
默认情况下,标签设置为窗口的右边缘,但可以使用center
关键字将标签设置��中心。
In [27]: s = pd.Series(range(10)) In [28]: s.rolling(window=5).mean() Out[28]: 0 NaN 1 NaN 2 NaN 3 NaN 4 2.0 5 3.0 6 4.0 7 5.0 8 6.0 9 7.0 dtype: float64 In [29]: s.rolling(window=5, center=True).mean() Out[29]: 0 NaN 1 NaN 2 2.0 3 3.0 4 4.0 5 5.0 6 6.0 7 7.0 8 NaN 9 NaN dtype: float64
这也可以应用于类似于日期时间的索引。
1.3.0 版本中新增。
In [30]: df = pd.DataFrame( ....: {"A": [0, 1, 2, 3, 4]}, index=pd.date_range("2020", periods=5, freq="1D") ....: ) ....: In [31]: df Out[31]: A 2020-01-01 0 2020-01-02 1 2020-01-03 2 2020-01-04 3 2020-01-05 4 In [32]: df.rolling("2D", center=False).mean() Out[32]: A 2020-01-01 0.0 2020-01-02 0.5 2020-01-03 1.5 2020-01-04 2.5 2020-01-05 3.5 In [33]: df.rolling("2D", center=True).mean() Out[33]: A 2020-01-01 0.5 2020-01-02 1.5 2020-01-03 2.5 2020-01-04 3.5 2020-01-05 4.0 ```### 滚动窗口端点 可以使用`closed`参数指定在滚动窗口计算中包含间隔端点的方式: | 值 | 行为 | | --- | --- | | `'right'` | 关闭右端点 | | `'left'` | 关闭左端点 | | `'both'` | 关闭两个端点 | | `'neither'` | 开放端点 | 例如,将右端点保持开放在许多需要确保没有来自当前信息到过去信息的污染的问题中非常有用。这允许滚动窗口计算统计数据“直到那个时间点”,但不包括那个时间点。 ```py In [34]: df = pd.DataFrame( ....: {"x": 1}, ....: index=[ ....: pd.Timestamp("20130101 09:00:01"), ....: pd.Timestamp("20130101 09:00:02"), ....: pd.Timestamp("20130101 09:00:03"), ....: pd.Timestamp("20130101 09:00:04"), ....: pd.Timestamp("20130101 09:00:06"), ....: ], ....: ) ....: In [35]: df["right"] = df.rolling("2s", closed="right").x.sum() # default In [36]: df["both"] = df.rolling("2s", closed="both").x.sum() In [37]: df["left"] = df.rolling("2s", closed="left").x.sum() In [38]: df["neither"] = df.rolling("2s", closed="neither").x.sum() In [39]: df Out[39]: x right both left neither 2013-01-01 09:00:01 1 1.0 1.0 NaN NaN 2013-01-01 09:00:02 1 2.0 2.0 1.0 1.0 2013-01-01 09:00:03 1 2.0 3.0 2.0 1.0 2013-01-01 09:00:04 1 2.0 3.0 2.0 1.0 2013-01-01 09:00:06 1 1.0 2.0 1.0 NaN ```### 自定义窗口滚动 除了接受整数或偏移作为`window`参数外,`rolling`还接受一个`BaseIndexer`子类,允许用户定义用于计算窗口边界的自定义方法。`BaseIndexer`子类将需要定义一个`get_window_bounds`方法,返回两个数组的元组,第一个是窗口的起始索引,第二个是窗口的结束索引。此外,`num_values`、`min_periods`、`center`、`closed`和`step`将自动传递给`get_window_bounds`,定义的方法必须始终接受这些参数。 例如,如果我们有以下`DataFrame` ```py In [40]: use_expanding = [True, False, True, False, True] In [41]: use_expanding Out[41]: [True, False, True, False, True] In [42]: df = pd.DataFrame({"values": range(5)}) In [43]: df Out[43]: values 0 0 1 1 2 2 3 3 4 4
如果我们想要使用一个扩展窗口,其中use_expanding
为True
,否则为大小为 1 的窗口,我们可以创建以下BaseIndexer
子类:
In [44]: from pandas.api.indexers import BaseIndexer In [45]: class CustomIndexer(BaseIndexer): ....: def get_window_bounds(self, num_values, min_periods, center, closed, step): ....: start = np.empty(num_values, dtype=np.int64) ....: end = np.empty(num_values, dtype=np.int64) ....: for i in range(num_values): ....: if self.use_expanding[i]: ....: start[i] = 0 ....: end[i] = i + 1 ....: else: ....: start[i] = i ....: end[i] = i + self.window_size ....: return start, end ....: In [46]: indexer = CustomIndexer(window_size=1, use_expanding=use_expanding) In [47]: df.rolling(indexer).sum() Out[47]: values 0 0.0 1 1.0 2 3.0 3 3.0 4 10.0
您可以在这里查看其他BaseIndexer
子类的示例。
在这些示例中,一个值得注意的子类是VariableOffsetWindowIndexer
,它允许在非固定偏移(如BusinessDay
)上进行滚动操作。
In [48]: from pandas.api.indexers import VariableOffsetWindowIndexer In [49]: df = pd.DataFrame(range(10), index=pd.date_range("2020", periods=10)) In [50]: offset = pd.offsets.BDay(1) In [51]: indexer = VariableOffsetWindowIndexer(index=df.index, offset=offset) In [52]: df Out[52]: 0 2020-01-01 0 2020-01-02 1 2020-01-03 2 2020-01-04 3 2020-01-05 4 2020-01-06 5 2020-01-07 6 2020-01-08 7 2020-01-09 8 2020-01-10 9 In [53]: df.rolling(indexer).sum() Out[53]: 0 2020-01-01 0.0 2020-01-02 1.0 2020-01-03 2.0 2020-01-04 3.0 2020-01-05 7.0 2020-01-06 12.0 2020-01-07 6.0 2020-01-08 7.0 2020-01-09 8.0 2020-01-10 9.0
对于一些问题,未来的知识可用于分析。例如,当每个数据点都是从实验中读取的完整时间序列时,任务是提取潜在条件。在这些情况下,执行前瞻性滚动窗口计算可能很有用。为此,可以使用FixedForwardWindowIndexer
类。这个BaseIndexer
子类实现了一个闭合的固定宽度前瞻性滚动窗口,我们可以按照以下方式使用它:
In [54]: from pandas.api.indexers import FixedForwardWindowIndexer In [55]: indexer = FixedForwardWindowIndexer(window_size=2) In [56]: df.rolling(indexer, min_periods=1).sum() Out[56]: 0 2020-01-01 1.0 2020-01-02 3.0 2020-01-03 5.0 2020-01-04 7.0 2020-01-05 9.0 2020-01-06 11.0 2020-01-07 13.0 2020-01-08 15.0 2020-01-09 17.0 2020-01-10 9.0
我们还可以通过使用切片、应用滚动聚合,然后翻转结果来实现这一点,如下面的示例所示:
In [57]: df = pd.DataFrame( ....: data=[ ....: [pd.Timestamp("2018-01-01 00:00:00"), 100], ....: [pd.Timestamp("2018-01-01 00:00:01"), 101], ....: [pd.Timestamp("2018-01-01 00:00:03"), 103], ....: [pd.Timestamp("2018-01-01 00:00:04"), 111], ....: ], ....: columns=["time", "value"], ....: ).set_index("time") ....: In [58]: df Out[58]: value time 2018-01-01 00:00:00 100 2018-01-01 00:00:01 101 2018-01-01 00:00:03 103 2018-01-01 00:00:04 111 In [59]: reversed_df = df[::-1].rolling("2s").sum()[::-1] In [60]: reversed_df Out[60]: value time 2018-01-01 00:00:00 201.0 2018-01-01 00:00:01 101.0 2018-01-01 00:00:03 214.0 2018-01-01 00:00:04 111.0 ```### 滚动应用 `apply()`函数接受额外的`func`参数并执行通用的滚动计算。`func`参数应该是一个从 ndarray 输入产生单个值的函数。`raw`指定窗口是作为`Series`对象(`raw=False`)还是 ndarray 对象(`raw=True`)。 ```py In [61]: def mad(x): ....: return np.fabs(x - x.mean()).mean() ....: In [62]: s = pd.Series(range(10)) In [63]: s.rolling(window=4).apply(mad, raw=True) Out[63]: 0 NaN 1 NaN 2 NaN 3 1.0 4 1.0 5 1.0 6 1.0 7 1.0 8 1.0 9 1.0 dtype: float64 ```### Numba 引擎 此外,如果安装了 [Numba](https://numba.pydata.org/) 作为可选依赖项,`apply()` 可以利用 Numba。通过指定 `engine='numba'` 和 `engine_kwargs` 参数(`raw` 也必须设置为 `True`),可以使用 Numba 执行应用聚合。有关参数的一般用法和性能考虑,请参见使用 Numba 提升性能。 Numba 将应用于可能的两个例程: 1. 如果 `func` 是一个标准的 Python 函数,引擎将[JIT](https://numba.pydata.org/numba-doc/latest/user/overview.html)传递的函数。`func` 也可以是一个已经 JIT 的函数,在这种情况下,引擎将不会再次 JIT 函数。 1. 引擎将对应用函数应用于每个窗口的 for 循环进行 JIT。 `engine_kwargs` 参数是一个关键字参数字典,将传递给[numba.jit 装饰器](https://numba.pydata.org/numba-doc/latest/reference/jit-compilation.html#numba.jit)。这些关键字参数将应用于*传递的函数*(如果是标准的 Python 函数)和对每个窗口进行的应用循环。 版本 1.3.0 中的新功能。 `mean`、`median`、`max`、`min` 和 `sum` 也支持 `engine` 和 `engine_kwargs` 参数。### 二进制窗口函数 `cov()` 和 `corr()` 可以计算关于两个`Series`或任何`DataFrame`/`Series`或`DataFrame`/`DataFrame`组合的移动窗口统计。在每种情况下的行为如下: + 两个`Series`:计算配对的统计量。 + `DataFrame`/`Series`:计算 DataFrame 的每一列与传递的 Series 的统计量,从而返回一个 DataFrame。 + `DataFrame`/`DataFrame`:默认情况下计算匹配列名的统计量,返回一个 DataFrame。如果传递了关键字参数 `pairwise=True`,则为每对列计算统计量,返回一个具有值为相关日期的`DataFrame`的`MultiIndex`(请参见下一节)。 例如: ```py In [64]: df = pd.DataFrame( ....: np.random.randn(10, 4), ....: index=pd.date_range("2020-01-01", periods=10), ....: columns=["A", "B", "C", "D"], ....: ) ....: In [65]: df = df.cumsum() In [66]: df2 = df[:4] In [67]: df2.rolling(window=2).corr(df2["B"]) Out[67]: A B C D 2020-01-01 NaN NaN NaN NaN 2020-01-02 -1.0 1.0 -1.0 1.0 2020-01-03 1.0 1.0 1.0 -1.0 2020-01-04 -1.0 1.0 1.0 -1.0 ```### 计算滚动配对协方差和相关性 在金融数据分析和其他领域,常常需要计算一组时间序列的协方差和相关矩阵。通常也对移动窗口的协方差和相关矩阵感兴趣。可以通过传递`pairwise`关键字参数来实现这一点,在`DataFrame`输入的情况下,将产生一个多级索引的`DataFrame`,其`index`是相关日期。在单个 DataFrame 参数的情况下,甚至可以省略`pairwise`参数: 注意 缺失值将被忽略,并且每个条目将使用成对完整观测值计算。 假设缺失数据是随机缺失的,这将导致对协方差矩阵的估计是无偏的。然而,对于许多应用程序,这种估计可能不可接受,因为估计的协方差矩阵不能保证是半正定的。这可能导致估计的相关性具有绝对值大于一,和/或不可逆的协方差矩阵。有关更多详细信息,请参阅[协方差矩阵的估计](https://en.wikipedia.org/w/index.php?title=Estimation_of_covariance_matrices)。 ```py In [68]: covs = ( ....: df[["B", "C", "D"]] ....: .rolling(window=4) ....: .cov(df[["A", "B", "C"]], pairwise=True) ....: ) ....: In [69]: covs Out[69]: B C D 2020-01-01 A NaN NaN NaN B NaN NaN NaN C NaN NaN NaN 2020-01-02 A NaN NaN NaN B NaN NaN NaN ... ... ... ... 2020-01-09 B 0.342006 0.230190 0.052849 C 0.230190 1.575251 0.082901 2020-01-10 A -0.333945 0.006871 -0.655514 B 0.649711 0.430860 0.469271 C 0.430860 0.829721 0.055300 [30 rows x 3 columns] ```## 加权窗口 `.rolling`中的`win_type`参数生成了常用于滤波和频谱估计的加权窗口。`win_type`必须是一个对应于[scipy.signal 窗口函数](https://docs.scipy.org/doc/scipy/reference/signal.windows.html#module-scipy.signal.windows)的字符串。必须安装 Scipy 才能使用这些窗口,并且必须在聚合函数中指定 Scipy 窗口方法所需的补充参数。 ```py In [70]: s = pd.Series(range(10)) In [71]: s.rolling(window=5).mean() Out[71]: 0 NaN 1 NaN 2 NaN 3 NaN 4 2.0 5 3.0 6 4.0 7 5.0 8 6.0 9 7.0 dtype: float64 In [72]: s.rolling(window=5, win_type="triang").mean() Out[72]: 0 NaN 1 NaN 2 NaN 3 NaN 4 2.0 5 3.0 6 4.0 7 5.0 8 6.0 9 7.0 dtype: float64 # Supplementary Scipy arguments passed in the aggregation function In [73]: s.rolling(window=5, win_type="gaussian").mean(std=0.1) Out[73]: 0 NaN 1 NaN 2 NaN 3 NaN 4 2.0 5 3.0 6 4.0 7 5.0 8 6.0 9 7.0 dtype: float64
对于所有支持的聚合函数,请参阅加权窗口函数。## 扩展窗口
扩展窗口产生一个聚合统计量的值,其中包含截至该时间点的所有可用数据。由于这些计算是滚动统计的特例,因此在 pandas 中实现了以下两个调用是等效的:
In [74]: df = pd.DataFrame(range(5)) In [75]: df.rolling(window=len(df), min_periods=1).mean() Out[75]: 0 0 0.0 1 0.5 2 1.0 3 1.5 4 2.0 In [76]: df.expanding(min_periods=1).mean() Out[76]: 0 0 0.0 1 0.5 2 1.0 3 1.5 4 2.0
对于所有支持的聚合函数,请参阅扩展窗口函数。## 指数加权窗口
指数加权窗口类似于扩展窗口,但是每个先前点相对于当前点按指数方式加权。
一般来说,加权移动平均值计算如下
[y_t = \frac{\sum_{i=0}^t w_i x_{t-i}}{\sum_{i=0}^t w_i},]
其中(x_t)是输入,(y_t)是结果,(w_i)是权重。
对于所有支持的聚合函数,请参阅指数加权窗口函数。
EW 函数支持指数权重的两个变体。默认情况下,adjust=True
使用权重(w_i = (1 - \alpha)^i),得到
[y_t = \frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)² x_{t-2} + … + (1 - \alpha)^t x_{0}}{1 + (1 - \alpha) + (1 - \alpha)² + … + (1 - \alpha)^t}]
当指定adjust=False
时,移动平均值计算如下
[
y0=x0 yt=(1−α)yt−1+αxt,�0=�0 ��=(1−�)��−1+���,
]
这等价于使用权重
[
wi={α(1−α)iif i<t (1−α)iif i=t.��={�(1−�)�if �<� (1−�)�if �=�.
]
注意
有时这些方程以(\alpha’ = 1 - \alpha)的形式书写,例如
[y_t = \alpha’ y_{t-1} + (1 - \alpha’) x_t.]
上述两个变体之间的差异是因为我们处理的是具有有限历史记录的系列。考虑一个具有无限历史记录的系列,其中adjust=True
:
[y_t = \frac{x_t + (1 - \alpha)x_{t-1} + (1 - \alpha)² x_{t-2} + …} {1 + (1 - \alpha) + (1 - \alpha)² + …}]
注意分母是一个初始项为 1 且比率为(1 - \alpha)的几何级数,我们有
[
yt=xt+(1−α)xt−1+(1−α)²xt−2+…11−(1−α) =[xt+(1−α)xt−1+(1−α)²xt−2+…]α =αxt+[(1−α)xt−1+(1−α)²xt−2+…]α =αxt+(1−α)[xt−1+(1−α)xt−2+…]α =αxt+(1−α)yt−1��=��+(1−�)��−1+(1−�)²��−2+…11−(1−�) =[��+(1−�)��−1+(1−�)²��−2+…]� =���+[(1−�)��−1+(1−�)²��−2+…]� =���+(1−�)[��−1+(1−�)��−2+…]� =���+(1−�)��−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 矩的跨度、质心(com)或半衰期:
[
α={2s+1,对于跨度 s≥1 11+c,对于质心 c≥0 1−explog0.5h,对于半衰期 h>0�={2�+1,对于跨度 �≥1 11+�,对于质心 �≥0 1−explog0.5ℎ,对于半衰期 ℎ>0
]
必须精确指定跨度、质心、半衰期和alpha中的一个来使用 EW 函数:
- 跨度对应于通常称为“N 天 EW 移动平均”的概念。
- 质心具有更具物理意义的解释,可以按照跨度来考虑:(c = (s - 1) / 2)。
- 半衰期是指数权重减少到一半所需的时间段。
- Alpha直接指定平滑因子。
您还可以指定halflife
,以时间间隔可转换的单位来指定观察值衰减到一半所需的时间,同时指定一系列times
。
In [77]: df = pd.DataFrame({"B": [0, 1, 2, np.nan, 4]}) In [78]: df Out[78]: B 0 0.0 1 1.0 2 2.0 3 NaN 4 4.0 In [79]: times = ["2020-01-01", "2020-01-03", "2020-01-10", "2020-01-15", "2020-01-17"] In [80]: df.ewm(halflife="4 days", times=pd.DatetimeIndex(times)).mean() Out[80]: B 0 0.000000 1 0.585786 2 1.523889 3 1.523889 4 3.233686
以下公式用于计算具有时间输入向量的指数加权均值:
[y_t = \frac{\sum_{i=0}^t 0.5^\frac{t_{t} - t_{i}}{\lambda} x_{t-i}}{\sum_{i=0}^t 0.5^\frac{t_{t} - t_{i}}{\lambda}},]
指数加权窗口也有一个ignore_na
参数,用于确定中间空值如何影响权重的计算。当ignore_na=False
(默认)时,权重是基于绝对位置计算的,因此中间的空值会影响结果。当ignore_na=True
时,通过忽略中间的空值来计算权重。例如,假设adjust=True
,如果ignore_na=False
,则3, NaN, 5
的加权平均值将被计算为
[\frac{(1-\alpha)² \cdot 3 + 1 \cdot 5}{(1-\alpha)² + 1}.]
当ignore_na=True
时,加权平均值将被计算为
[\frac{(1-\alpha) \cdot 3 + 1 \cdot 5}{(1-\alpha) + 1}.]
var()
、std()
和cov()
函数有一个bias
参数,指定结果是否应包含有偏或无偏的统计数据。例如,如果bias=True
,则ewmvar(x)
被计算为ewmvar(x) = ewma(x**2) - ewma(x)**2
;而如果bias=False
(默认),有偏方差统计数据将通过去偏因子进行缩放
[\frac{\left(\sum_{i=0}^t w_i\right)²}{\left(\sum_{i=0}^t w_i\right)² - \sum_{i=0}^t w_i²}.]
(对于(w_i = 1),这将减少到通常的(N / (N - 1))因子,其中(N = t + 1)。)有关更多详细信息,请参阅维基百科上的加权样本方差。 ## 概述
pandas 支持 4 种类型的窗口操作:
- 滚动窗口:对数值进行通用的固定或可变滑动窗口。
- 加权窗口:由
scipy.signal
库提供的加权、非矩形窗口。 - 扩展窗口:对数值进行累积窗口。
- 指数加权窗口:对数值进行累积和指数加权的窗口。
概念 | 方法 | 返回对象 | 支持基于时间的窗口 | 支持链接的 groupby | 支持表方法 | 支持在线操作 |
滚动窗口 | rolling |
pandas.typing.api.Rolling |
是 | 是 | 是(自版本 1.3 起) | 否 |
加权窗口 | rolling |
pandas.typing.api.Window |
否 | 否 | 否 | 否 |
扩展窗口 | expanding |
pandas.typing.api.Expanding |
否 | 是 | 是(自版本 1.3 起) | 否 |
指数加权窗口 | ewm |
pandas.typing.api.ExponentialMovingWindow |
否 | 是(自版本 1.2 起) | 否 | 是(自版本 1.3 起) |
Pandas 2.2 中文官方教程和指南(二十一·一)(2)https://developer.aliyun.com/article/1509510