API · Pandas

Pandas DataFrame.rolling()関数

DataFrame のローリング()関数は、数学演算のためのローリングウィンドウを提供します。

このページの内容

Python Pandas の DataFrame.rolling() 関数は、数学演算のためのローリングウィンドウを提供します。rolling() を呼び出すだけでは何も計算されません。これは移動ウィンドウを定義する Rolling オブジェクトを返し、sum()、mean()、std() などの集計メソッドが各ウィンドウを 1 行の結果に集約します。ウィンドウは通常、現在の行で終わるため、結果は元の DataFrame と同じインデックスを保持します。そのため rolling() は、累積和、移動平均、その他の実行統計を構築する標準的な方法となっています。

pandas.DataFrame.rolling() の構文

DataFrame.rolling(
    window, min_periods=None, center=False, win_type=None, on=None,
    closed=None, step=None, method='single'
)

パラメーター

window 整数、オフセット、または BaseIndexer のサブクラスです。移動ウィンドウのサイズを指定します。固定された観測数、またはオフセットを使用する場合は '3D' のような時間の範囲です。
min_periods 整数パラメーターです。ウィンドウ内に必要な、NaN でない観測の最小数を指定します。その数に満たないウィンドウは NaN を返します。設定しない場合、デフォルトは固定ウィンドウではウィンドウサイズ、時間ベースのウィンドウでは 1 です。
center ブール値パラメーターです。True の場合、各結果は右端ではなくウィンドウの中央の行にラベル付けされます。
win_type 文字列パラメーターです。'triang' のような重み付きウィンドウの種類を指定し、ウィンドウ内の観測が異なる重みで寄与します。ほとんどの重み付きウィンドウには SciPy が必要です。
on 文字列パラメーターです。インデックスの代わりにローリングウィンドウの計算に使用する列名を指定します。日付が列に格納されている時間ベースのウィンドウで使用します。
closed 文字列パラメーターです。ウィンドウ区間のどちらの側を閉じるかを指定します。right、left、both、neither の 4 つのオプションがあります。デフォルトは right です。
step 整数パラメーターです。ウィンドウは step 行ごとにのみ評価されるため、結果にはその行だけが含まれます。

戻り値

Rolling ウィンドウオブジェクトを返します。それに対して集計メソッドを呼び出すと、入力と同じインデックスを持つ DataFrame が返されます。

上のシグネチャは現在のものです。古いチュートリアルに載っている axis パラメーターは、ローリングウィンドウが常に行方向(インデックス)に沿って移動するため、もう存在しません。渡すと TypeError が発生します(下のエラーセクションで示します)。

例:ウィンドウサイズ 2 の固定ウィンドウによるローリング合計

最も一般的な形式は、行数を数える整数のウィンドウです。この例では、rolling(2).sum() が各行をその直上の行に加算します。

import pandas as pd

dataframe = pd.DataFrame({
    'Attendance': {0: 60, 1: 100, 2: 80, 3: 78, 4: 95},
    'Obtained Marks': {0: 90, 1: 75, 2: 82, 3: 64, 4: 45},
})
print("The Original DataFrame is:")
print(dataframe)
print("The Rolling Sum With a Window of 2 is:")
print(dataframe.rolling(2).sum())

出力:

The Original DataFrame is:
   Attendance  Obtained Marks
0          60              90
1         100              75
2          80              82
3          78              64
4          95              45
The Rolling Sum With a Window of 2 is:
   Attendance  Obtained Marks
0         NaN             NaN
1       160.0           165.0
2       180.0           157.0
3       158.0           146.0
4       173.0           109.0

行 0 には上の行がないため、そのウィンドウには観測が 1 つしかなく、デフォルトの min_periods が必要とする 2 つに満たないため、結果は NaN になります。行 1 以降、各値は現在の行と前の行の合計です。60 + 100 = 160、100 + 80 = 180 のようになります。整数列は、この最初の NaN のために浮動小数点数になります。

例:ローリング平均と min_periods

同じウィンドウはどの集計でも機能します。ここでは rolling(3).mean() が現在の行とその上の 2 行の平均を取ります。デフォルトの min_periods では、最初の 2 行は 3 行のウィンドウを満たすことができず、NaN のままになります。min_periods=1 を設定すると、pandas は冒頭で利用可能な観測数だけを使って処理するため、結果は最初の行から定義されます。

import pandas as pd

dataframe = pd.DataFrame({
    'Attendance': {0: 60, 1: 100, 2: 80, 3: 78, 4: 95},
    'Obtained Marks': {0: 90, 1: 75, 2: 82, 3: 64, 4: 45},
})
print("The Rolling Mean With a Window of 3 is:")
print(dataframe.rolling(3).mean())
print("The Rolling Mean With a Window of 3 and min_periods=1 is:")
print(dataframe.rolling(3, min_periods=1).mean())

出力:

The Rolling Mean With a Window of 3 is:
   Attendance  Obtained Marks
0         NaN             NaN
1         NaN             NaN
2   80.000000       82.333333
3   86.000000       73.666667
4   84.333333       63.666667
The Rolling Mean With a Window of 3 and min_periods=1 is:
   Attendance  Obtained Marks
0   60.000000       90.000000
1   80.000000       82.500000
2   80.000000       82.333333
3   86.000000       73.666667
4   84.333333       63.666667

2 つの出力はインデックス 2 以降で一致します。違いは先頭にあります。min_periods=1 では、最初の行に 60.00(その値単独)、2 行目に 80.00(最初の 2 つの値の平均)が追加で報告されます。min_periods は NaN でない観測を数えることに注意してください。これにより、min_periods はデータ内の欠落に対する主な制御手段にもなります(最後の例で示します)。

例:時間ベースのウィンドウによるローリング合計

window には '3D' のような時間オフセットも指定できます。その場合、ウィンドウは固定された行数ではなく時間の範囲をカバーするため、レコードは間隔がどれだけ不規則でも、その範囲内に入るときにのみ寄与します。日付がインデックスではなく列にある場合は、その列を on で指定します。以下の売上データには、2026-01-04 と 2026-01-07 のレコードがありません。

import pandas as pd

sales = pd.DataFrame({
    'Date': pd.to_datetime(['2026-01-01', '2026-01-02', '2026-01-03',
                            '2026-01-05', '2026-01-06', '2026-01-08']),
    'Sales': [120, 80, 150, 90, 200, 60],
})
print(sales)
print("The Rolling Sum Over the Previous 3 Days is:")
print(sales.rolling('3D', on='Date').sum())

出力:

        Date  Sales
0 2026-01-01    120
1 2026-01-02     80
2 2026-01-03    150
3 2026-01-05     90
4 2026-01-06    200
5 2026-01-08     60
The Rolling Sum Over the Previous 3 Days is:
        Date  Sales
0 2026-01-01  120.0
1 2026-01-02  200.0
2 2026-01-03  350.0
3 2026-01-05  240.0
4 2026-01-06  290.0
5 2026-01-08  260.0

2026-01-05 については、3 日間のウィンドウは 2026-01-02 より前までさかのぼるため、含まれるのは 2026-01-03 と 2026-01-05 の売上のみです。150 + 90 = 240 です。欠けている 2026-01-04 は何も寄与せず、追加の行が固定ウィンドウをずらすようには範囲をずらしません。最初の行にすでに結果があることにも注目してください。時間ベースのウィンドウはデフォルトで min_periods=1 を使用します。これは固定ウィンドウとは逆のデフォルトです。

例:center でラベルを中央に配置し、closed で現在の行を除外する

2 つのパラメーターが、結果が属する場所を変更します。center=True では、集計値はウィンドウの最後の行ではなく中央の行に配置されます。これは、移動平均が平滑化対象のデータと揃うべき場合に望ましい挙動です。最初と最後の行は、中央に完全なウィンドウが配置できないため結果を失います。closed は区間のどちらの端を含めるかを制御します。closed='left' では、ある行のウィンドウはその行より前の行をカバーし、その行自体は自身の統計から除外されます。

import pandas as pd

temps = pd.DataFrame({'Temperature': [10, 12, 14, 16, 18, 20]})
print("The Centered Rolling Mean With a Window of 3 is:")
print(temps.rolling(3, center=True).mean())
print("The Rolling Sum With a Window of 3 and closed='left' is:")
print(temps.rolling(3, closed='left').sum())

出力:

The Centered Rolling Mean With a Window of 3 is:
   Temperature
0          NaN
1         12.0
2         14.0
3         16.0
4         18.0
5          NaN
The Rolling Sum With a Window of 3 and closed='left' is:
   Temperature
0          NaN
1          NaN
2          NaN
3         36.0
4         42.0
5         48.0

インデックス 1 の中央揃えの平均は 12.0、つまり 10、12、14 の平均で、そのウィンドウの中央の行に位置します。closed='left' の合計は、おなじみの 36、42、48 のパターンが 1 行下にずれたものになっています。インデックス 3 では、ウィンドウは行 0 から 2(10 + 12 + 14 = 36)を保持します。これは行 3 自体が除外されているためです。

よくあるエラーと境界ケース

ユーザーが最も驚くことが多い 3 つの挙動があり、それぞれ小さな例で確認できます。

ウィンドウ内の欠損値

min_periods は NaN でない観測を数えるため、1 つの欠損値があると、それを含むすべての固定ウィンドウと、それに続くウィンドウが空になります。min_periods を下げることで、集計は存在する値を使用するようになります。

import pandas as pd

scores = pd.DataFrame({'Score': [50.0, None, 70.0, 90.0]})
print(scores)
print("The Rolling Sum With a Window of 2 is:")
print(scores.rolling(2).sum())
print("The Rolling Sum With a Window of 2 and min_periods=1 is:")
print(scores.rolling(2, min_periods=1).sum())

出力:

   Score
0   50.0
1    NaN
2   70.0
3   90.0
The Rolling Sum With a Window of 2 is:
   Score
0    NaN
1    NaN
2    NaN
3  160.0
The Rolling Sum With a Window of 2 and min_periods=1 is:
   Score
0   50.0
1   50.0
2   70.0
3  160.0

デフォルト設定では、最後の合計 70 + 90 だけが残ります。min_periods=1 では、インデックス 2 のウィンドウには有効な値が 1 つ含まれているため、その合計は 70 になります。欠損したエントリは伝播されずにスキップされます。どちらの挙動もデータを修復するものではありません。部分的なウィンドウが統計にとって意味があるかどうかに基づいて選択してください。

無効な引数は ValueError を発生させる

rolling() は、何かを計算する前に引数を検証します。負のウィンドウは直ちに失敗します。

import pandas as pd

temps = pd.DataFrame({'Temperature': [10, 12, 14, 16, 18, 20]})
print(temps.rolling(-1).sum())

出力:

ValueError: window must be an integer 0 or greater

不明な closed 値も同様に失敗し、ValueError: closed must be 'right', 'left', 'both' or 'neither' となります。2.5 のような小数ウィンドウも、負のウィンドウと同じメッセージで拒否されます。window=0 は受け付けられますが、退化しています。すべてのウィンドウが空になるため、sum() はすべての行で 0.0 を返します。

数値以外の列は DataError を発生させる

集計が受け付けるのは数値データのみです。テキスト列をまだ含む DataFrame にローリングを適用すると、エラーが発生します。

import pandas as pd

mixed = pd.DataFrame({'Name': ['A', 'B', 'C'], 'Value': [1, 2, 3]})
print(mixed.rolling(2).sum())

出力:

pandas.errors.DataError: Cannot aggregate non-numeric type: str

ローリングの前に数値列を選択してください。たとえば mixed[['Value']].rolling(2).sum() のようにするか、先にラベル列を削除します。

留意すべき点

  • rolling() 自体は Rolling オブジェクトを返します。集計メソッドが呼ばれるまで何も計算されません。結果は常に入力のインデックスを持つため、新しい列としてそのまま代入できます。
  • 出力に NaN が現れるとすぐに、整数列は浮動小数点数になります。これは、NaN には整数表現がないためです。
  • グループ化された計算では、df.groupby('key').rolling(2).sum() のように groupby オブジェクトに対して rolling() を呼び出します。ウィンドウはグループの境界を越えるのではなく、グループごとに再開します。
  • win_type による重み付きウィンドウは信号系のデータ向けです。通常のビジネスデータでは、上記の例で示した重みなしの集計が適切なデフォルトです。