pandas の expanding と ewm で累積・指数移動平均を計算する

時系列データの分析では、移動平均のほかに累積統計量や指数加重移動平均を計算したい場面があります。pandas の expanding と ewm を使えば、こうした計算をメソッド一つで実行できます。

expanding で累積統計量を計算する

expanding は「データの先頭から現在の行まで」を対象とするウィンドウ関数です。rolling が固定幅の窓を使うのに対し、expanding は窓が徐々に広がっていきます。

import pandas as pd

df = pd.DataFrame({
    "date": pd.date_range("2024-01-01", periods=6, freq="D"),
    "sales": [100, 150, 120, 180, 90, 200]
})

df["cumulative_mean"] = df["sales"].expanding().mean()
df["cumulative_sum"] = df["sales"].expanding().sum()
print(df)

1 行目は 100 の平均で 100.0、2 行目は 100 と 150 の平均で 125.0 というように、行が進むほど対象データが増えていきます。累積合計は cumsum で代替できますが、expanding なら mean、std、min、max なども同じインタフェースで計算できるのが利点です。

rolling(n)

直近 n 行の固定窓で計算する。短期的なトレンドの把握に向く

expanding

先頭から現在行までの拡張窓で計算する。累積的な統計量の算出に向く

expanding の min_periods

min_periods を指定すると、最低限のデータ数を満たさない行は NaN になります。

df["exp_std"] = df["sales"].expanding(min_periods=3).std()

標準偏差はデータが 2 個以上ないと計算できないため、min_periods=3 とすれば最初の 2 行は NaN となり、3 行目から値が入り始めます。

ewm で指数加重移動平均を計算する

ewm(Exponentially Weighted Moving)は、直近のデータに大きな重みを付けて計算するウィンドウ関数です。株価のテクニカル分析などでよく使われます。

df["ewm_mean"] = df["sales"].ewm(span=3).mean()
print(df)

span は「おおよそ何日分のデータを重視するか」を表すパラメータです。span が小さいほど直近のデータに敏感に反応し、大きいほど滑らかな線になります。

ewm のパラメータ

ewm の減衰の強さは span、halflife、alpha のいずれかで指定できます。

span重心を基準とした期間。span=n で α=2/(n+1)
halflife半減期。影響が半分になるまでの期間
alpha平滑化係数(0〜1)。直接指定する

3 つのうち 1 つだけを指定します。span=3 とすると α=0.5、span=9 とすると α=0.2 になり、span が大きいほど過去のデータの影響が長く残ります。

実践例:移動平均との比較

rolling と ewm の結果を並べてみると、特徴の違いがよくわかります。

df["sma_3"] = df["sales"].rolling(3).mean()
df["ema_3"] = df["sales"].ewm(span=3).mean()
print(df[["date", "sales", "sma_3", "ema_3"]])

単純移動平均(SMA)は窓内のデータを均等に扱うため変動に対する反応が遅く、指数加重移動平均(EMA)は直近のデータをより重視するためトレンドの変化に素早く追従します。どちらが適切かはデータの性質と分析の目的次第です。

expanding と ewm は rolling と並んで pandas の時系列分析を支える重要なツールです。累積的な推移を見たいときは expanding、直近の動きを重視したいときは ewm と使い分けましょう。