Pandas Rolling Window: Rolling, Expanding, and EWM
Updated on
移動平均やスムージングされたシグナルは時系列分析の中核ですが、多くのチームはウィンドウの位置合わせ、欠損値、そして遅い Python ループに悩まされています。
- 問題: Rolling 統計量を手計算するとエラーが出やすく、timestamp とずれがちです。
- 不満の種: ループや場当たり的な
shiftの組み合わせは off‑by‑one エラーや初期期間の穴、そして重いノートブックの原因になります。 - 解決策:
rolling、expanding、ewmを適切なウィンドウ定義(min_periods、時間ベースのウィンドウ、center、adjustなど)と組み合わせて使い、正しく速いベクトル化された結果を得ましょう。
Want an AI agent that understands your pandas notebooks and rolling-window features?
RunCell is a JupyterLab AI agent that can read your code, analyze DataFrames, understand notebook context, debug errors, and even generate & execute code for you. It works directly inside JupyterLab—no switching windows or copy-pasting.
👉 Try RunCell: runcell.dev (opens in a new tab)
クイックリファレンス
| Window type | Best for | Key parameters |
|---|---|---|
rolling | 移動平均、ボラティリティ、カスタムウィンドウ関数 | window=3(または "7D")、min_periods、center、win_type、on |
expanding | 開始時点からの累積統計量 | min_periods |
ewm | 指数減衰スムージングや重み付きメトリクス | span、alpha、halflife、adjust、times |
サンプルデータ
import pandas as pd
dates = pd.date_range("2024-01-01", periods=8, freq="D")
sales = pd.DataFrame({"date": dates, "revenue": [10, 12, 9, 14, 15, 13, 11, 16]})
sales = sales.set_index("date")Rolling Windows(固定幅・時間ベース)
固定サイズのウィンドウ
sales["rev_ma3"] = (
sales["revenue"]
.rolling(window=3, min_periods=2)
.mean()
)min_periodsは結果を出し始めるタイミングを制御します。最初の行は最小カウントに達するまでNaNのままです。center=Trueを指定すると統計量をウィンドウの中央に配置できます(プロット時に便利)。
Datetime index または on= 列に対する時間ベースのウィンドウ
sales_reset = sales.reset_index()
sales_reset["rev_7d_mean"] = (
sales_reset.rolling("7D", on="date")["revenue"].mean()
)- 不規則サンプリングには期間文字列(
"7D"、"48H"など)を使います。pandas は固定件数ではなく、指定した lookback 期間内に入る行を自動で選びます。 - ウィンドウの左右どちら側を含めるかを変えたい場合は、
closed="left"または"right"を調整します。
カスタムウィンドウ関数
sales["rev_range"] = (
sales["revenue"].rolling(4).apply(lambda x: x.max() - x.min(), raw=True)
)raw=True を指定すると、apply 内で NumPy array を直接扱えるため高速になります。
Expanding Windows(累積)
sales["rev_cum_mean"] = sales["revenue"].expanding(min_periods=2).mean()- 各観測値が「それ以前のすべて」を見るべきとき(ランニング平均、累積比率など)には expanding を使います。
shift()と組み合わせて、最新値を過去平均と比較することもできます。
Exponential Weighted Windows
sales["rev_ewm_span4"] = sales["revenue"].ewm(span=4, adjust=False).mean()adjust=Falseは、多くの分析ダッシュボードで使われる典型的なスムージングに近い再帰式を用います。halflifeは直感的な減衰表現を提供します:ewm(halflife=3)は 3 期間ごとに重みを半減させます。- 不規則な timestamp では、
times="date"(または index に設定)を渡すことで、行数ではなく実際の時間差に基づいて重み付けできます。
ウィンドウの選び方(チートシート)
| Goal | Recommended method | Notes |
|---|---|---|
| 短期ノイズの平滑化 | 小さな window と center=True を指定した rolling | 数値列に対して動作。初期から値を見たいなら min_periods を 1 以上に |
| 開始時からのランニング合計・平均 | expanding | 固定ウィンドウなし。累積する KPI に最適 |
| 古い観測値を減衰させる | ewm(span=...) | 大きい rolling window よりモメンタム系シグナルに向く |
| 不規則な timestamp | rolling("7D", on="date") のような時間ベース rolling または ewm(..., times="date") | サンプリングが密な日のバイアスを避けられる |
| 特徴量生成 | rolling().agg(["mean","std","min","max"]) | 複数集約で特徴量セットを手早く構築 |
パフォーマンスと正確性のポイント
- 時間ベースのウィンドウを多用する場合は、datetime 列を
datetime64[ns]にし、index に設定しておきます。 - 速度のために、Python の
applyよりも組み込み集約関数(mean、std、sum、count)を優先しましょう。 - 先見バイアスを避けるには、教師あり学習向け特徴量を作る際、
rollingの前にshift()でターゲットを過去側にずらします。 - 元データが不規則な場合は、
resampleと組み合わせて頻度を正規化してから rolling を行います。
rolling、expanding、ewm を使えば、ループなしでほとんどのスムージングや特徴量エンジニアリングをカバーできます。pandas-to-datetime や pandas-resample と組み合わせて時間軸を整えれば、チャートやモデルにそのまま投入できる高速で信頼性の高いメトリクスを得られます。