pandas rolling()の使い方|移動平均・window・NaNを初心者向けに解説

日別売上やアクセス数を折れ線グラフにしても、値が大きく上下していると「増えているのか、単にばらついているだけなのか」が分かりにくいことがあります。

このようなときに使えるのが、pandasのrolling()です。直近の複数行を少しずつずらしながら平均を計算し、短期的な変動をならして傾向を見やすくできます。

先に結論を示すと、rolling(window=3).mean()は、原則として現在行を含む直近3行の平均を求めます。データが1日1行で日付も連続していれば、「3日移動平均」として読めます。ただし、window=3自体が自動的に3日間を意味するわけではありません。

また、結果の先頭に出るNaNはエラーではありません。3行分のデータがまだそろっていないためです。

最初に覚える手順は、「日付順に並べる → rolling()で計算する → 元の値と比べる」の3つだけです。

この記事では、Google Colabで実行できる日別売上データを使い、3日・7日移動平均、min_periodsresample()との違い、折れ線グラフでの確認までを順番に解説します。

  1. この記事でわかること
  2. rolling()は直近の複数行をずらしながら計算する
  3. rolling()・resample()・通常のmean()の違い
  4. 日別売上のサンプルデータを用意する
  5. rolling()の前に日付型と並び順を確認する
  6. rolling(window=3).mean()で3日移動平均を計算する
    1. window=3が対象にする値を処理前後表で確認する
  7. 先頭2行がNaNになる理由
    1. min_periods=1で途中から計算する場合
  8. center=Trueは結果を中央の行に置く
  9. 3日移動平均と7日移動平均を使い分ける
  10. rolling().mean()とrolling().sum()の違い
    1. rolling()の後ろで使える主な集計メソッド
  11. 元の売上と移動平均を折れ線グラフで比較する
  12. rolling(3)とrolling(“3D”)は対象範囲が違う
  13. rolling()でよくあるミスと注意点
    1. window=3を必ず3日間だと思ってしまう
    2. 日付順に並べず計算する
    3. 先頭のNaNをエラーだと思う
    4. rolling()だけで元のDataFrameが変わると思う
    5. 欠損値があっても同じように計算できると思う
  14. データ分析の流れでrolling()を使う位置
  15. まとめ
  16. 次に読みたい関連記事
    1. カテゴリから探す
    2. pandasのrolling()は何をするメソッドですか?
    3. rolling(3)の3は3日という意味ですか?
    4. rolling()の結果で最初の行がNaNになるのはなぜですか?
    5. min_periods=1を指定すればNaNを消してもよいですか?
    6. rolling()とresample()は何が違いますか?
    7. center=Trueはどんなときに使いますか?
    8. DataFrame全体にrolling()を使えますか?
    9. expanding()やewm()とは何が違いますか?

この記事でわかること

  • rolling()を使う場面と基本的な書き方
  • rolling(window=3).mean()のwindowが表す範囲
  • 3日移動平均と7日移動平均の計算方法
  • 先頭にNaNが出る理由とmin_periodsの役割
  • rolling()resample()・通常のmean()の違い
  • center=Trueで結果を置く位置を変える方法
  • 行数指定とrolling("3D")による期間指定の違い
  • 元の値と移動平均を折れ線グラフで比較する方法

この記事のゴールは、目的に合ったwindowを選び、移動平均列を作って、元の値と比較しながら傾向を説明できるようになることです。

rolling()は直近の複数行をずらしながら計算する

rolling()の「rolling window」は、日本語では「移動窓」と考えると分かりやすいでしょう。

たとえばwindow=3なら、対象範囲を次のように1行ずつ移動させます。

1. 1〜3行目を使って計算する 2. 2〜4行目を使って計算する 3. 3〜5行目を使って計算する

平均を求める場合の基本形は次のとおりです。

df["売上"].rolling(window=3).mean()

列を1つ選ぶとSeriesになるため、これはSeriesにrolling()を適用して平均を求める書き方です。複数の数値列を選んだDataFrameにもrolling()を使えますが、この記事では1列に絞って仕組みを確認します。

rolling()・resample()・通常のmean()の違い

似て見える処理でも目的が異なります。最初に次の基準で選びましょう。

方法 目的 計算対象 行数の変化 使用場面 代表的な書き方
rolling() 直近の値をならす・合計する 現在行を含む直近n行 原則として元と同じ 3日移動平均、直近7件の平均 s.rolling(3).mean()
resample() 時間単位を変えて再集計する 日・週・月などの期間 通常は変わる 日別データを月別合計にする df.resample("MS").sum()
通常のmean() 列全体の平均を1つ求める 列全体 1つの値になる 全期間の平均売上を知る s.mean()

迷ったときは、出力後も1日ごとの行を残したいかで判断します。 1日ごとの行を残して傾向をならすならrolling()、月別・週別などに行をまとめるならresample()です。列全体を代表する平均値が1つだけ必要なら、通常のmean()を使います。

月別・週別集計は、pandas resample()の使い方で詳しく解説しています。

日別売上のサンプルデータを用意する

Google Colabで次のコードを実行してください。2026年8月1日から14日まで、1日1行で日付が連続するデータです。

売上は日ごとに上下しますが、全体として少しずつ増える値にしています。このデータなら、移動平均によって短期的な上下がならされる様子を確認できます。

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({
    "日付": [
        "2026-08-01", "2026-08-02", "2026-08-03", "2026-08-04",
        "2026-08-05", "2026-08-06", "2026-08-07", "2026-08-08",
        "2026-08-09", "2026-08-10", "2026-08-11", "2026-08-12",
        "2026-08-13", "2026-08-14"
    ],
    "売上": [100, 160, 120, 190, 150, 220, 180, 250, 210, 280, 230, 310, 270, 340]
})

df
日付 売上
0 2026-08-01 100
1 2026-08-02 160
2 2026-08-03 120
3 2026-08-04 190
4 2026-08-05 150
5 2026-08-06 220
6 2026-08-07 180
7 2026-08-08 250
8 2026-08-09 210
9 2026-08-10 280
10 2026-08-11 230
11 2026-08-12 310
12 2026-08-13 270
13 2026-08-14 340

自分のCSVをGoogle Colabへ読み込む手順は、Google ColabでCSVを読み込む方法を参照してください。DataFrame自体の基本操作を確認したい場合は、Pandas DataFrame入門が役立ちます。

rolling()の前に日付型と並び順を確認する

移動平均は「直前の行」を使うため、行の順番が重要です。日付が文字列のままならdatetime型に変換し、古い日付から新しい日付の順へ並べます。

今回は日付が連続する1日1行のデータなので、window=3を3日移動平均として説明できます。欠損日があるデータでは、同じコードは「直近3日」ではなく直近3行の平均です。

df["日付"] = pd.to_datetime(df["日付"])
df = df.sort_values("日付").reset_index(drop=True)

df.dtypes
日付 datetime64[ns]
売上 int64

日付datetime64[ns]になっていれば変換できています。

rolling(window=3).mean()で3日移動平均を計算する

売上列にrolling(window=3).mean()を適用し、結果を「3日移動平均」という新しい列へ追加します。

df["3日移動平均"] = df["売上"].rolling(window=3).mean()

df[["日付", "売上", "3日移動平均"]]
日付 売上 3日移動平均
0 2026-08-01 100 NaN
1 2026-08-02 160 NaN
2 2026-08-03 120 126.67
3 2026-08-04 190 156.67
4 2026-08-05 150 153.33
5 2026-08-06 220 186.67
6 2026-08-07 180 183.33
7 2026-08-08 250 216.67
8 2026-08-09 210 213.33
9 2026-08-10 280 246.67
10 2026-08-11 230 240.0
11 2026-08-12 310 273.33
12 2026-08-13 270 270.0
13 2026-08-14 340 306.67

window=3が対象にする値を処理前後表で確認する

最初の5行は次のように計算されます。

日付 元の売上 平均対象となる値 3日移動平均
2026-08-01 100 3行未満 NaN
2026-08-02 160 3行未満 NaN
2026-08-03 120 100・160・120 126.67
2026-08-04 190 160・120・190 156.67
2026-08-05 150 120・190・150 153.33

8月3日の値は、(100 + 160 + 120) ÷ 3 = 126.67です。次の行では対象が1行ずれ、8月2日〜4日の売上を平均します。

この表で重要なのは、各行の結果が、その行と直前2行から作られていることです。移動平均は元の行数を保ちながら各行に対応する平均を返し、列全体の平均を1つだけ返すdf["売上"].mean()とは異なります。

先頭2行がNaNになる理由

初期設定では、windowに指定した数の有効な値がそろうまで結果を計算しません。window=3の場合は次の状態になります。

  • 1行目:利用できる値が1個だけなのでNaN
  • 2行目:利用できる値が2個だけなのでNaN
  • 3行目:3個そろうので移動平均を計算

したがって、先頭のNaNはエラーではなく、同じ条件の3行平均をまだ計算できないことを示す正常な結果です。単純にfillna(0)で0へ置き換えると、「平均売上が0だった」と誤解されるので避けましょう。

min_periods=1で途中から計算する場合

min_periodsは、結果を計算するために最低限必要な有効値の数です。min_periods=1を指定すると、最初の行から結果が出ます。

df["3日移動平均_min1"] = (
    df["売上"]
    .rolling(window=3, min_periods=1)
    .mean()
)

df[["日付", "売上", "3日移動平均", "3日移動平均_min1"]].head(5)
日付 売上 3日移動平均 3日移動平均_min1
0 2026-08-01 100 NaN 100.0
1 2026-08-02 160 NaN 130.0
2 2026-08-03 120 126.67 126.67
3 2026-08-04 190 156.67 156.67
4 2026-08-05 150 153.33 153.33

初期設定とmin_periods=1の違いを整理します。

日付 利用できる値の数 初期設定の結果 min_periods=1 比較時の注意点
2026-08-01 1 NaN 100.00 1個だけの平均
2026-08-02 2 NaN 130.00 2個の平均
2026-08-03 3 126.67 126.67 3個の平均

min_periods=1はNaNを減らせますが、先頭の値は3個ではなく1個または2個の平均です。すべての行を同じ条件で比較したい場合は、初期設定のNaNを残すほうが分かりやすいことがあります。

center=Trueは結果を中央の行に置く

初期設定のcenter=Falseでは、計算結果をwindowの末尾、つまり現在行に置きます。center=Trueを指定すると、結果をwindowの中央に置きます。

指定 3行の計算結果を置く位置 向いている場面
center=False(初期設定) 3行目(末尾) 現在までの値から傾向を確認する
center=True 2行目(中央) 前後の値を使って中央時点をならす

同じ3つの値を平均しても、結果が表示される行が変わります。

center比較 = pd.DataFrame({
    "日付": df["日付"],
    "売上": df["売上"],
    "center=False": df["売上"].rolling(window=3).mean(),
    "center=True": df["売上"].rolling(window=3, center=True).mean()
})

center比較.head(6)
日付 売上 center=False center=True
0 2026-08-01 100 NaN NaN
1 2026-08-02 160 NaN 126.67
2 2026-08-03 120 126.67 156.67
3 2026-08-04 190 156.67 153.33
4 2026-08-05 150 153.33 186.67
5 2026-08-06 220 186.67 183.33

たとえば100・160・120の平均126.67は、初期設定では3行目の8月3日、center=Trueでは中央に当たる2行目の8月2日に表示されます。

この記事の移動平均は「現在までの直近値から傾向を見る」ことが目的なので、以降は初期設定のcenter=Falseを使います。

3日移動平均と7日移動平均を使い分ける

次に、同じ売上データへ7行の移動平均も追加します。サンプルは1日1行で日付が連続しているため、ここでは7日移動平均として扱えます。

df["7日移動平均"] = df["売上"].rolling(window=7).mean()

df[["日付", "売上", "3日移動平均", "7日移動平均"]]
日付 売上 3日移動平均 7日移動平均
0 2026-08-01 100 NaN NaN
1 2026-08-02 160 NaN NaN
2 2026-08-03 120 126.67 NaN
3 2026-08-04 190 156.67 NaN
4 2026-08-05 150 153.33 NaN
5 2026-08-06 220 186.67 NaN
6 2026-08-07 180 183.33 160.0
7 2026-08-08 250 216.67 181.43
8 2026-08-09 210 213.33 188.57
9 2026-08-10 280 246.67 211.43
10 2026-08-11 230 240.0 217.14
11 2026-08-12 310 273.33 240.0
12 2026-08-13 270 270.0 247.14
13 2026-08-14 340 306.67 270.0
比較項目 window=3 window=7
使うデータ数 直近3行 直近7行
滑らかさ 小さい 大きい
急な変化への反応 比較的速い 比較的遅い
向いている目的 短期的な動きの確認 やや長い傾向の確認
先頭のNaN 2行 6行

windowを大きくすると線は滑らかになりますが、急な上昇や下降が遅れて表れます。3日と7日のどちらが常に優れているわけではなく、どの程度の短期変動をならしたいかで選びます。

なお、移動平均は過去の値をならして見せる方法であり、将来を予測する機能ではありません。

rolling().mean()とrolling().sum()の違い

rolling()の後ろには、目的に合った集計メソッドを続けます。

  • mean():直近の平均を求め、変動をならす
  • sum():直近の合計を求める

たとえば「直近3日間の売上合計」を求める場合は、sum()を使います。

df["直近3日売上合計"] = df["売上"].rolling(window=3).sum()

df[["日付", "売上", "3日移動平均", "直近3日売上合計"]].head(7)
日付 売上 3日移動平均 直近3日売上合計
0 2026-08-01 100 NaN NaN
1 2026-08-02 160 NaN NaN
2 2026-08-03 120 126.67 380.0
3 2026-08-04 190 156.67 470.0
4 2026-08-05 150 153.33 460.0
5 2026-08-06 220 186.67 560.0
6 2026-08-07 180 183.33 550.0

同じwindowでも、mean()は傾向をならす用途、sum()は直近期間の累計を確認する用途に向いています。

rolling()の後ろで使える主な集計メソッド

rolling()は対象範囲を決める処理です。その後ろに、目的に合った集計メソッドを続けます。

メソッド 求める値 使用例
mean() 平均 売上の短期変動をならす
sum() 合計 直近3日分の売上合計を求める
min() 最小値 直近期間の最低売上を確認する
max() 最大値 直近期間の最高売上を確認する
median() 中央値 極端な値の影響を抑えて中心を見る
std() 標準偏差 直近期間のばらつきを確認する
count() 有効値の個数 window内のデータ数を確認する

初心者は、まずmean()sum()を使い分けられれば十分です。ほかのメソッドも書き方は同じで、必要になったときに選べます。

元の売上と移動平均を折れ線グラフで比較する

数値表だけでなく、元の売上、3日移動平均、7日移動平均を同じグラフへ描くと、windowによる滑らかさの違いが分かります。

ここではグラフの装飾ではなく、元の値の上下が移動平均でどのようにならされるかに注目してください。

plt.figure(figsize=(10, 5))
plt.plot(df["日付"], df["売上"], marker="o", alpha=0.55, label="Daily sales")
plt.plot(df["日付"], df["3日移動平均"], linewidth=2.5, label="3-row moving average")
plt.plot(df["日付"], df["7日移動平均"], linewidth=2.5, label="7-row moving average")

plt.xlabel("Date")
plt.ylabel("Sales")
plt.title("Daily sales and moving averages")
plt.grid(alpha=0.3)
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
日別売上と3日移動平均・7日移動平均を比較した折れ線グラフ
日別売上と3日移動平均・7日移動平均の比較

3日移動平均は元の売上の変化に比較的早く反応し、7日移動平均はさらに滑らかになります。一方で、windowが大きいほど直近の変化が遅れて見える点には注意が必要です。

グラフの色・線種・凡例などを詳しく設定したい場合は、Matplotlib折れ線グラフの描き方を参照してください。

rolling(3)とrolling(“3D”)は対象範囲が違う

ここまで使ったrolling(3)は直近3行を対象にします。一方、日付をインデックスにした時系列データでは、rolling("3D")のように実際の期間を指定できます。

違いが分かるように、8月3日と4日が欠けたデータで比較します。

df_gap = pd.DataFrame({
    "日付": pd.to_datetime(["2026-08-01", "2026-08-02", "2026-08-05", "2026-08-06"]),
    "売上": [100, 160, 120, 190]
}).set_index("日付")

df_gap["直近3行平均"] = df_gap["売上"].rolling(3).mean()
df_gap["直近3日平均"] = df_gap["売上"].rolling("3D").mean()

df_gap
売上 直近3行平均 直近3日平均
2026-08-01 100.0 NaN 100.0
2026-08-02 160.0 NaN 130.0
2026-08-05 120.0 126.67 120.0
2026-08-06 190.0 156.67 155.0

8月5日の「直近3行平均」は8月1日・2日・5日の3行を使います。一方、「直近3日平均」は実際の日付間隔を見るため、8月5日時点の直近3日内にある値だけが対象です。

書き方 windowの基準 欠損日がある場合
rolling(3) 行数 日付が離れていても直近3行を使う
rolling("3D") 実際の3日間 その期間内にある行だけを使う

1日1行で日付が連続していれば両者は似た結果になりますが、欠損日や不規則な時刻があるデータでは一致しません。期間指定にはDatetimeIndexが必要です。この記事の中心は行数ベースの移動平均なので、期間指定はこの違いだけ押さえれば十分です。

rolling()でよくあるミスと注意点

window=3を必ず3日間だと思ってしまう

数値のwindow=3は基本的に3行です。1日に複数行がある場合や、日付が抜けている場合は3日間と一致しません。期間ベースではrolling("7D")のような指定もできますが、日付インデックスなどの前提が増えるため、この記事では詳しく扱いません。

日付順に並べず計算する

rolling()は現在の行順を使います。日付が前後したままでは、時間の流れに沿った移動平均になりません。先にdatetime型へ変換し、sort_values()で並べ替えましょう。

先頭のNaNをエラーだと思う

必要な値がwindowの数に達していないためです。0埋めで隠すのではなく、NaNが生じる理由を確認します。

rolling()だけで元のDataFrameが変わると思う

rolling()の計算結果は自動的に元のDataFrameへ追加されません。残したい場合は、この記事の例のように新しい列へ代入します。列追加の基本は、pandasで新しい列を追加する方法で確認できます。

欠損値があっても同じように計算できると思う

元データに欠損値があると、window内の有効値の数とmin_periodsによって結果が変わります。まず欠損の場所と意味を確認し、必要な件数を満たしているか判断してください。

データ分析の流れでrolling()を使う位置

rolling()は、データを読み込んだ直後ではなく、日付や並び順を整えた後に使います。

1. CSVやExcelを読み込む 2. head()dtypesで内容と型を確認する 3. 日付列をto_datetime()で変換する 4. 日付順に並べ替える 5. 必要に応じてresample()で時間単位を整える 6. rolling()で短期変動をならす 7. 折れ線グラフで元の値と比較する

年・月・曜日を取り出して別の切り口で集計したい場合は、pandas dtの使い方へ進んでください。

発展的な機能には、開始行から対象範囲を広げるexpanding()、新しい値へ大きな重みを付けるewm()、グループ別に計算するgroupby().rolling()などがあります。center=Trueによる結果位置の変更や欠損日の補間も含め、これらは基本を理解してから学べば十分です。

まとめ

  • rolling()は、直近の複数行を1行ずつずらしながら計算する
  • rolling(window=3).mean()は、原則として現在行を含む直近3行の平均を求める
  • 数値のwindowは基本的に行数であり、自動的に日数を意味するわけではない
  • 3行そろう前のNaNはエラーではなく、同じ条件で計算できないことを示す
  • min_periods=1なら先頭から計算できるが、利用する値の数が行ごとに異なる
  • center=Trueを指定すると、計算結果をwindowの中央に置ける
  • rolling(3)は直近3行、rolling("3D")は実際の直近3日間を対象にする
  • window=3は変化へ比較的早く反応し、window=7は滑らかだが反応が遅くなる
  • 傾向を見るならmean()、直近の合計を見るならsum()を使う
  • 集計単位を変えるresample()と、値をならすrolling()は目的が異なる
  • 計算前に日付型と並び順を確認し、計算後は元の値とグラフで比較する

まずはこの記事のサンプルで3日移動平均を実行し、windowを7へ変えたときに結果がどのように変化するか確認してみてください。

次に読みたい関連記事

▲ ページトップへ戻る

pandasのrolling()は何をするメソッドですか?

現在行を含む直近の複数行を対象に、平均・合計などを繰り返し計算するメソッドです。日別売上の短期的な変動をならし、傾向を見やすくする場面などで使います。

rolling(3)の3は3日という意味ですか?

基本的には3行という意味です。データが1日1行で日付も連続している場合に限り、3日移動平均として読めます。実際の期間を基準にする方法にはrolling("3D")などがありますが、日付インデックスなどの前提が必要です。

rolling()の結果で最初の行がNaNになるのはなぜですか?

windowで指定した数の有効な値がまだそろっていないためです。window=3の初期設定では、最初の2行がNaNになり、3行目から結果が出ます。

min_periods=1を指定すればNaNを消してもよいですか?

目的によります。先頭から値を表示できますが、最初は1個、次は2個、その後は3個の平均となり、計算条件がそろいません。元データに欠損値がある場合も、有効値の数がmin_periods以上かで結果が決まるため、NaNを消す前に利用件数を確認してください。

rolling()とresample()は何が違いますか?

rolling()は直近数行をずらしながら計算し、原則として元の行数を保ちます。resample()は日別を月別にするように時間単位を変えて再集計するため、通常は行数も変わります。1日ごとの行を残すか、期間ごとにまとめるかで判断してください。

center=Trueはどんなときに使いますか?

計算結果をwindowの中央に置きたいときに使います。過去から現在までの傾向を見る通常の移動平均では初期設定のまま、前後の値で中央時点をならしたい場合はcenter=Trueが候補です。

DataFrame全体にrolling()を使えますか?

使えます。複数の数値列を持つDataFrameに適用すると、各数値列へ同じwindowの計算が行われます。ただし、初心者は分析対象の列を選んでから適用すると、結果を理解しやすくなります。

expanding()やewm()とは何が違いますか?

expanding()は開始点から現在行まで計算範囲を広げます。ewm()は一般に新しい値へ大きな重みを付けて計算します。まずは一定数の直近行を扱うrolling()から覚えると分かりやすいでしょう。

コメント

タイトルとURLをコピーしました