ウィンドウ処理#
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
ライブラリによって提供される、ウェイト付きの非矩形ウィンドウ。展開ウィンドウ:値に対する累積ウィンドウ。
指数加重ウィンドウ:値に対する累積および指数加重ウィンドウ。
概念 |
メソッド |
返されるオブジェクト |
時間ベースのウィンドウをサポート |
チェーンされたgroupbyをサポート |
テーブルメソッドをサポート |
オンライン操作をサポート |
---|---|---|---|---|---|---|
ローリングウィンドウ |
|
|
はい |
はい |
はい(バージョン1.3以降) |
いいえ |
ウェイト付きウィンドウ |
|
|
いいえ |
いいえ |
いいえ |
いいえ |
展開ウィンドウ |
|
|
いいえ |
はい |
はい(バージョン1.3以降) |
いいえ |
指数加重ウィンドウ |
|
|
いいえ |
はい(バージョン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'
オプションもサポートしています。これは、一度に1つの列または行ではなく、DataFrame
全体でウィンドウ処理操作を実行します。これは、多くの列または行を持つDataFrame
(対応するaxis
引数を使用)の場合、またはウィンドウ処理操作中に他の列を利用する場合に、パフォーマンス上の利点をもたらす可能性があります。method='table'
オプションは、対応するメソッド呼び出しでengine='numba'
が指定されている場合にのみ使用できます。
たとえば、加重平均の計算は、個別の重みの列を指定することで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
オブジェクトを渡して、新しい値(つまり、オンライン計算)でウィンドウ処理計算を続行できる新しいオブジェクトを返します。
この新しいウィンドウ処理オブジェクトのメソッドは、最初に集計メソッドを呼び出してオンライン計算の初期状態を「準備」する必要があります。その後、新しいDataFrame
またはSeries
オブジェクトをupdate
引数に渡して、ウィンドウ処理計算を続行できます。
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
すべてのウィンドウ処理操作は、ウィンドウが持つ必要のある非np.nan
値の最小量を決定するmin_periods
引数をサポートしています。そうでない場合、結果はnp.nan
になります。min_periods
は、時間ベースのウィンドウでは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
ローリングウィンドウ#
一般的なローリングウィンドウでは、ウィンドウを一定数の観測値またはオフセットに基づく可変数の観測値として指定できます。時間ベースのオフセットが提供されている場合、対応する時間ベースのインデックスは単調でなければなりません。
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
これは、datetimeのようなインデックスにも適用できます。
バージョン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
パラメータで指定できます。
値 |
動作 |
---|---|
|
右端点を閉じる |
|
左端点を閉じる |
|
両端点を閉じる |
|
端点を開く |
たとえば、右端点を開いておくことは、現在の情報から過去の情報への汚染がないことが必要な多くの問題で役立ちます。これにより、ローリングウィンドウは「その時点まで」の統計を計算できますが、その時点自体は含まれません。
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
サブクラスは、ウィンドウの開始インデックスを格納した配列とウィンドウの終了インデックスを格納した配列の2つのタプルを返すget_window_bounds
メソッドを定義する必要があります。さらに、num_values
、min_periods
、center
、closed
、step
はget_window_bounds
に自動的に渡され、定義されたメソッドは常にこれらの引数を受け入れる必要があります。
例えば、以下のDataFrame
があるとします。
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
サブクラスの他の例はこちらで確認できます。
これらの例の中で注目すべきサブクラスの1つは、BusinessDay
のような固定されていないオフセットに対するローリング操作を可能にするVariableOffsetWindowIndexer
です。
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
)としてキャストされるかを指定します。
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エンジン#
さらに、apply()
は、オプションの依存関係としてインストールされている場合、Numbaを活用できます。engine='numba'
およびengine_kwargs
引数を指定することで、Numbaを使用して適用集計を実行できます(raw
もTrue
に設定する必要があります)。引数の一般的な使用方法とパフォーマンスに関する考慮事項については、Numbaによるパフォーマンスの向上を参照してください。
Numbaは、可能性のある2つのルーチンに適用されます。
func
が標準的なPython関数の場合、エンジンは渡された関数をJITコンパイルします。func
はJITコンパイル済みの関数にすることもでき、その場合、エンジンは関数を再度JITコンパイルしません。エンジンは、適用関数が各ウィンドウに適用されるforループをJITコンパイルします。
engine_kwargs
引数は、numba.jitデコレータに渡されるキーワード引数の辞書です。これらのキーワード引数は、渡された関数(標準的なPython関数の場合)と、各ウィンドウに対する適用forループの両方に適用されます。
バージョン1.3.0の新機能。
mean
、median
、max
、min
、sum
もengine
およびengine_kwargs
引数をサポートします。
バイナリウィンドウ関数#
cov()
とcorr()
は、2つのSeries
、またはDataFrame
/Series
、DataFrame
/DataFrame
の任意の組み合わせに関する移動ウィンドウ統計を計算できます。各ケースにおける動作は以下のとおりです。
2つの
Series
:ペアリングの統計を計算します。DataFrame
/Series
:渡されたSeriesを使用してDataFrameの各列の統計を計算し、DataFrameを返します。DataFrame
/DataFrame
:デフォルトでは、一致する列名の統計を計算し、DataFrameを返します。pairwise=True
キーワード引数が渡された場合、各列のペアの統計を計算し、MultiIndex
を値とするDataFrameを返します(次のセクションを参照)。
例えば
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
入力がMultiIndexed DataFrame
を生成します。そのindex
は問題の日付です。単一のDataFrame引数の場合は、pairwise
引数を省略することもできます。
注意
欠損値は無視され、各エントリはペアワイズ完全観測値を使用して計算されます。
欠損データがランダムに欠損していると仮定すると、これは共分散行列の不偏推定値になります。しかし、多くのアプリケーションでは、推定された共分散行列が正定値半定値であることが保証されないため、この推定値は許容できない可能性があります。これにより、推定された相関の絶対値が1より大きくなったり、共分散行列が非可逆になったりする可能性があります。詳細については、共分散行列の推定を参照してください。
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ウィンドウ関数に対応する文字列である必要があります。これらのウィンドウを使用するにはScipyをインストールする必要があり、Scipyウィンドウメソッドが使用する補足的な引数は集計関数で指定する必要があります。
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では次の2つの呼び出しが等価になるように実装されています。
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
サポートされているすべての集計関数については、拡大ウィンドウ関数を参照してください。
指数加重ウィンドウ#
指数加重ウィンドウは拡大ウィンドウに似ていますが、各前のポイントは現在のポイントに対して指数関数的に重みが減少します。
一般に、加重移動平均は次のように計算されます。
ここで、\(x_t\)は入力、\(y_t\)は結果、\(w_i\)は重みです。
サポートされているすべての集計関数については、指数加重ウィンドウ関数を参照してください。
EW関数は、指数ウェイトの2つのバリアントをサポートしています。デフォルトのadjust=True
は、ウェイト\(w_i = (1 - \alpha)^i\)を使用し、以下を与えます。
adjust=False
を指定すると、移動平均は以下のように計算されます。
これは、以下のウェイトを使用することと同等です。
注意
これらの式は、\(\alpha' = 1 - \alpha\)の観点から記述されることもあります。例:
上記2つのバリアントの違いは、有限の履歴を持つ系列を扱っているためです。adjust=True
を持つ無限の履歴を持つ系列を考えてみましょう。
分母は初項が1で、公比が\(1 - \alpha\)の幾何級数であることに注意すると、
これは上記adjust=False
と同じ式であり、したがって無限系列に対する2つのバリアントの等価性を示しています。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、中心(com)、または半減期のいずれかを考える方が簡単です。
EW関数には、span、中心、半減期、alphaのいずれか1つを正確に指定する必要があります。
spanは、一般的に「N日EW移動平均」と呼ばれるものに対応します。
中心はより物理的な解釈を持ち、spanに関して\(c = (s - 1) / 2\)として考えることができます。
半減期とは、指数ウェイトが半分に減少する期間です。
Alphaは、平滑化係数を直接指定します。
times
のシーケンスも指定する場合、timedeltaに変換可能な単位でhalflife
を指定して、観測値が元の値の半分に減衰するまでの時間を指定することもできます。
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
時間の入力ベクトルを使用して指数加重平均を計算するために、次の式が使用されます。
ExponentialMovingWindowには、ignore_na
引数もあります。これは、中間的なNull値がウェイトの計算にどのように影響するかを決定します。ignore_na=False
(デフォルト)の場合、ウェイトは絶対的な位置に基づいて計算されるため、中間的なNull値は結果に影響します。ignore_na=True
の場合、中間的なNull値を無視してウェイトが計算されます。例えば、adjust=True
を仮定すると、ignore_na=False
の場合、3, NaN, 5
の加重平均は以下のように計算されます。
ignore_na=True
の場合、加重平均は以下のように計算されます。
var()
、std()
、および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を参照してください。