pandas diff()の使い方|前の行との差分・前日からの増減を計算する方法

日別売上を見ながら、「前日よりいくら増えたのか」を1行ずつ計算するのは大変です。pandasのdiff()を使えば、現在の行から1つ前の行を引いた差分をまとめて計算できます。

先に結論を示すと、前の行からの増減「量」を求める基本形はdf["売上"].diff()です。ただし、diff()は日付そのものではなく、DataFrameの現在の行順に沿って計算します。時系列データでは、日付型への変換と日付順の並び替えを先に済ませることが重要です。

この記事では日別売上を例に、引き算の向き、先頭がNaNになる理由、periodsの意味、shift()pct_change()rolling()との違いまで、Google Colabで実行しながら確認します。

  1. この記事でわかること
  2. 先に結論:増減量を求めるならdiff()を使う
  3. 日別売上のサンプルデータを用意する
  4. diff()の前に日付型と並び順を整える
  5. diff()で前の行との差を計算する
    1. 処理前・計算対象・処理後を表で確認する
  6. diff()の結果を「前日差」列として追加する
  7. periodsで何行前と比較するかを変更する
    1. periodsに負の値を指定するとどうなる?
  8. 並び順が違うとdiff()の結果も変わる
  9. 前日差を正しく読むための2つの注意点
    1. 日付が欠けていると「前の行」と「前日」は一致しない
    2. 途中に欠損値があると差分もNaNになる
  10. diff()・shift()・pct_change()・rolling()を同じデータで比較する
    1. 補足:DataFrame全体や列方向にもdiff()を使える
  11. diff()でよくあるミスと対処法
    1. 1. 日付順に並べず「前日差」と解釈する
    2. 2. 先頭のNaNをエラーだと思う
    3. 3. periodsを日数だと思う
    4. 4. diff()を表示しただけで列が追加されたと思う
    5. 5. 負の値を計算ミスだと思う
    6. 6. 前日比率を求めたいのにdiff()を使う
  12. データ分析の流れでdiff()を使う位置
    1. 売上と前日差をグラフで確認する
  13. まとめ
  14. 関連記事
    1. カテゴリから探す
    2. pandasで前の行との差を求めるにはどうすればよいですか?
    3. diff()の先頭行がNaNになるのはなぜですか?
    4. diff()で前日差や前日比率を計算できますか?
    5. diff()のperiods=2は何を意味しますか?
    6. diff()とshift()の違いは何ですか?
    7. 日付が連続していなくても前日差になりますか?

この記事でわかること

  • diff()で前の行との差分を求める方法
  • 差分が正・負・0になる意味
  • 先頭行がNaNになる理由
  • periodsで比較する行を変える方法
  • 日付順に並べてから計算する理由
  • diff()shift()pct_change()rolling()の使い分け
  • 計算結果を「前日差」列としてDataFrameに追加する方法

DataFrame自体がまだよく分からない場合は、先にPandas DataFrame入門を読むと理解しやすくなります。CSVから試したい場合は、Google ColabでCSVを読み込む方法も参考にしてください。

先に結論:増減量を求めるならdiff()を使う

diff()の標準の計算は、次のとおりです。

現在の行の値 − 1つ前の行の値

たとえば、前日の売上が1,000円、当日の売上が1,300円なら、差分は300です。前日より200円減った場合は-200になります。

目的が似ているメソッドは、求めたい結果で使い分けます。

メソッド 求められるもの 使う場面 結果のイメージ
diff() 前の行との差(増減量) 前日より何円増えたか 300
pct_change() 前の行からの変化率 前日より何%増えたか 0.3(30%)
shift() 前の行の値そのもの 前日の値を別の列に置く 1000
rolling() 直近数行の平均・合計など 日々の変動をならして傾向を見る 3日移動平均
resample() 日・週・月などの期間別集計 日別データを月別にまとめる 月間売上

この記事の中心は、増減「量」を求めるdiff()です。移動平均はpandas rolling()の使い方、期間別集計はpandas resample()の使い方で詳しく解説しています。

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

Google Colabで次のセルを実行してください。増加・減少・変化なしをすべて確認できるように、日付の順番を一部入れ替えたデータを用意します。

import pandas as pd

df = pd.DataFrame({
    "日付": ["2026-08-01", "2026-08-03", "2026-08-02", "2026-08-04", "2026-08-05", "2026-08-06"],
    "売上": [1000, 1300, 1200, 1300, 1300, 1100]
})

df
日付 売上
0 2026-08-01 1000
1 2026-08-03 1300
2 2026-08-02 1200
3 2026-08-04 1300
4 2026-08-05 1300
5 2026-08-06 1100

このままdiff()を使うと、表示されている行順で計算されます。8月3日の次に8月2日があるため、その結果を「前日差」とは呼べません。先に日付型と並び順を整えます。

diff()の前に日付型と並び順を整える

まずto_datetime()で日付列を日付型に変換し、sort_values()で昇順に並べます。並び替え後のインデックスもreset_index(drop=True)で振り直しておくと、行順を確認しやすくなります。

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

df
日付 売上
0 2026-08-01 1000
1 2026-08-02 1200
2 2026-08-03 1300
3 2026-08-04 1300
4 2026-08-05 1300
5 2026-08-06 1100

日付の変換方法はpandas to_datetime()の使い方、並び替えの詳細はpandas 並び替え(sort)入門で確認できます。

ここでは日付が1日刻みで連続しているため、1つ前の行との差を「前日差」として扱えます。

diff()で前の行との差を計算する

売上列にdiff()を使って、結果だけを確認します。

df["売上"].diff()
売上
0 NaN
1 200.0
2 100.0
3 0.0
4 0.0
5 -200.0

結果は上から順にNaN, 200, 100, 0, 0, -200となります。diff()を実行しただけでは、元のDataFrameに列は追加されていません。

処理前・計算対象・処理後を表で確認する

それぞれの行で行われている計算は次のとおりです。

日付 売上 1つ前の売上 引き算 diff()の結果
2026-08-01 1,000 なし 計算できない NaN
2026-08-02 1,200 1,000 1,200 − 1,000 200
2026-08-03 1,300 1,200 1,300 − 1,200 100
2026-08-04 1,300 1,300 1,300 − 1,300 0
2026-08-05 1,300 1,300 1,300 − 1,300 0
2026-08-06 1,100 1,300 1,100 − 1,300 -200

diff()は逆向きではなく、現在行から前の行を引く処理です。したがって、結果の符号は次のように読みます。

結果 意味
正の値 前の行より増加
負の値 前の行より減少
0 前の行から変化なし
NaN 比較相手がない、または計算に必要な値が欠けている

diff()の結果を「前日差」列として追加する

分析しやすいように、差分を新しい列へ代入します。

df["前日差"] = df["売上"].diff()

df
日付 売上 前日差
0 2026-08-01 1000 NaN
1 2026-08-02 1200 200.0
2 2026-08-03 1300 100.0
3 2026-08-04 1300 0.0
4 2026-08-05 1300 0.0
5 2026-08-06 1100 -200.0

これで元の売上と前日差を横に並べて確認できます。先頭行のNaNはエラーではありません。1行目には比較する前日の行がないためです。

整数の売上列でも、先頭にNaNが入るため、結果は通常200.0のような小数で表示されます。計算が間違っているわけではありません。列追加の基本は、pandasで新しい列を追加する方法で詳しく解説しています。

periodsで何行前と比較するかを変更する

diff()periodsは、何行ずらした値と比較するかを指定します。標準はperiods=1です。

ここで重要なのは、periods=2が必ず「2日前」を意味するわけではなく、2行前を意味することです。日付が毎日連続している場合に限り、2行前と2日前が一致します。

df["1行前との差"] = df["売上"].diff(periods=1)
df["2行前との差"] = df["売上"].diff(periods=2)

df[["日付", "売上", "1行前との差", "2行前との差"]]
日付 売上 1行前との差 2行前との差
0 2026-08-01 1000 NaN NaN
1 2026-08-02 1200 200.0 NaN
2 2026-08-03 1300 100.0 300.0
3 2026-08-04 1300 0.0 100.0
4 2026-08-05 1300 0.0 0.0
5 2026-08-06 1100 -200.0 -200.0

比較対象は次のように変わります。

設定 計算 最初に計算できる行
periods=1 現在行 − 1行前 2行目
periods=2 現在行 − 2行前 3行目

たとえば8月3日の売上1,300円について、1行前との差は1,300 − 1,200 = 100、2行前との差は1,300 − 1,000 = 300です。

periodsに負の値を指定するとどうなる?

負の値を指定すると、後ろの行と比較できます。たとえばperiods=-1は「現在行 − 次の行」です。引き算の向きを混同しやすいため、初心者のうちは標準のperiods=1を中心に使えば十分です。

df[["日付", "売上"]].assign(
    次の行との差=df["売上"].diff(periods=-1)
)
日付 売上 次の行との差
0 2026-08-01 1000 -200.0
1 2026-08-02 1200 -100.0
2 2026-08-03 1300 0.0
3 2026-08-04 1300 0.0
4 2026-08-05 1300 200.0
5 2026-08-06 1100 NaN

並び順が違うとdiff()の結果も変わる

diff()は日付を見て自動的に前日を探すメソッドではありません。画面上の1つ前の行と比較します。

最初に用意した並び順のまま計算した場合と、日付順に整えてから計算した場合を比べます。

df_unsorted = pd.DataFrame({
    "日付": pd.to_datetime(["2026-08-01", "2026-08-03", "2026-08-02", "2026-08-04"]),
    "売上": [1000, 1300, 1200, 1300]
})

変更前 = df_unsorted.assign(行間差=df_unsorted["売上"].diff())

df_sorted = df_unsorted.sort_values("日付").reset_index(drop=True)
変更後 = df_sorted.assign(前日差=df_sorted["売上"].diff())

print("変更前:日付順ではない状態")
display(変更前)
print("変更後:日付順に並べた状態")
display(変更後)

変更前:日付順ではない状態

日付 売上 行間差
0 2026-08-01 1000 NaN
1 2026-08-03 1300 300.0
2 2026-08-02 1200 -100.0
3 2026-08-04 1300 100.0

変更後:日付順に並べた状態

日付 売上 前日差
0 2026-08-01 1000 NaN
1 2026-08-02 1200 200.0
2 2026-08-03 1300 100.0
3 2026-08-04 1300 0.0

変更前では8月2日の直前に8月3日があるため、8月2日の差は1,200 − 1,300 = -100です。これは前日差ではなく、単なる行間差です。変更後は8月1日、2日、3日、4日の順になるため、前日からの増減として解釈できます。

時系列データでは、diff()の直前に日付列と並び順を確認する習慣をつけましょう。

前日差を正しく読むための2つの注意点

日付が欠けていると「前の行」と「前日」は一致しない

次は8月2日のデータがない例です。日付順には並んでいますが、8月3日の1つ前の行は8月1日です。

df_gap = pd.DataFrame({
    "日付": pd.to_datetime(["2026-08-01", "2026-08-03", "2026-08-04"]),
    "売上": [1000, 1300, 1200]
})

df_gap["前の行との差"] = df_gap["売上"].diff()
df_gap
日付 売上 前の行との差
0 2026-08-01 1000 NaN
1 2026-08-03 1300 300.0
2 2026-08-04 1200 -100.0

8月3日の結果300は、8月1日との比較です。8月2日の売上が存在しないため、厳密には「前日差」ではありません。

つまり、diff(periods=1)1は1日ではなく1行です。「前日差」と表現する前に、日付が1日刻みで連続しているか確認してください。

途中に欠損値があると差分もNaNになる

売上の途中に欠損値があると、その値を使う差分は計算できません。

df_missing = pd.DataFrame({
    "日付": pd.date_range("2026-08-01", periods=5, freq="D"),
    "売上": [1000, 1200, None, 1500, 1600]
})

df_missing["前日差"] = df_missing["売上"].diff()
df_missing
日付 売上 前日差
0 2026-08-01 1000.0 NaN
1 2026-08-02 1200.0 200.0
2 2026-08-03 NaN NaN
3 2026-08-04 1500.0 NaN
4 2026-08-05 1600.0 100.0

8月3日は売上自体が欠損しているためNaNです。8月4日も、比較する1行前の8月3日が欠損しているためNaNになります。8月5日は8月4日の値があるため、再び計算できます。

欠損値を理由なく0で埋めると、「売上が本当に0だった」と解釈される恐れがあります。欠損が未記録なのか、売上0を意味するのかを確認してから処理してください。埋め方の判断はpandas fillna()の使い方で解説しています。

diff()・shift()・pct_change()・rolling()を同じデータで比較する

似た処理の違いを、同じ売上データで確認します。shift(1)は前の行の売上、pct_change()は変化率、rolling(3).mean()は直近3行の移動平均を返します。

df_compare = df[["日付", "売上"]].copy()
df_compare["前の行の値_shift"] = df_compare["売上"].shift(1)
df_compare["増減量_diff"] = df_compare["売上"].diff()
df_compare["増減率_pct_change"] = df_compare["売上"].pct_change(fill_method=None)
df_compare["3行移動平均_rolling"] = df_compare["売上"].rolling(3).mean()

df_compare
日付 売上 前の行の値_shift 増減量_diff 増減率_pct_change 3行移動平均_rolling
0 2026-08-01 1000 NaN NaN NaN NaN
1 2026-08-02 1200 1000.0 200.0 0.200000 NaN
2 2026-08-03 1300 1200.0 100.0 0.083333 1166.666667
3 2026-08-04 1300 1300.0 0.0 0.000000 1266.666667
4 2026-08-05 1300 1300.0 0.0 0.000000 1300.000000
5 2026-08-06 1100 1300.0 -200.0 -0.153846 1233.333333

たとえば8月2日は、前の行の値が1,000円、増減量が200円、増減率が0.2(20%)です。3行移動平均は3行分の値が揃う8月3日から計算されます。

  • 何円変わったかを知りたい:diff()
  • 何%変わったかを知りたい:pct_change()
  • 前の値そのものを使いたい:shift()
  • 短期的な変動をならしたいrolling()

目的を先に言葉にすると、メソッドを選びやすくなります。

補足:DataFrame全体や列方向にもdiff()を使える

ここまでは、日別売上の前日差を求めるため、売上のSeriesにdiff()を使いました。diff()は数値列からなるDataFrame全体にも使用でき、標準では各列について1つ前の行との差を計算します。文字列列などが含まれる場合は、差分を求めたい数値列を選んで実行するのが安全です。

また、axis=1を指定すると、同じ行にある列同士の差を計算できます。たとえば「4月売上」と「5月売上」の差を横方向に求める場合です。

df_monthly = pd.DataFrame({
    "4月売上": [1000, 1500],
    "5月売上": [1200, 1400]
}, index=["商品A", "商品B"])

df_monthly.diff(axis=1)
4月売上 5月売上
商品A NaN 200
商品B NaN -100

5月売上列には「5月売上 − 4月売上」が表示されます。最初の4月売上列は左側に比較する列がないためNaNです。

商品 4月売上 5月売上 5月 − 4月
商品A 1,000 1,200 200
商品B 1,500 1,400 -100

ただし、時系列データの前日差を求める目的なら、対象の売上列に行方向のdiff()を使う基本形を優先してください。列方向の差分は、月別列などが横に並んだデータで必要になったときに使えば十分です。

diff()でよくあるミスと対処法

1. 日付順に並べず「前日差」と解釈する

diff()は現在の行順で計算します。時系列データでは、日付型への変換と並び替えを先に済ませます。

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

先頭行には比較する前の行がないため、標準ではNaNになります。正常な結果なので、理由なく0で埋めないようにします。

3. periodsを日数だと思う

periods=2は2日前ではなく2行前との比較です。

4. diff()を表示しただけで列が追加されたと思う

df["売上"].diff()は結果を返しますが、元のDataFrameを変更しません。「前日差」列として残す場合は、新しい列へ代入します。

5. 負の値を計算ミスだと思う

標準のdiff()は現在行から前の行を引きます。負の値は、前の行より減少したことを示します。

6. 前日比率を求めたいのにdiff()を使う

diff()が返すのは増減量です。「前日より何%増えたか」を求める場合はpct_change()を選びます。

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

diff()は、読み込んだデータを確認・整形したあとに、変化を表す列を作る処理として使えます。

  1. CSVをDataFrameに読み込む
  2. head()info()で列とデータ型を確認する
  3. 日付列をto_datetime()で日付型に変換する
  4. sort_values()で日付順に並べる
  5. diff()で前の行からの増減列を作る
  6. 増減が大きい日を確認する
  7. 必要に応じてrolling()resample()で傾向を集計する
  8. 折れ線グラフなどで可視化する

このように、diff()はデータの確認・前処理から時系列分析や可視化へ進む橋渡しになります。

売上と前日差をグラフで確認する

最後に、売上と前日差を上下2つの折れ線グラフで確認します。尺度が異なるため、同じ軸へ無理に重ねず、グラフを分けます。

Google Colabで日本語のタイトルや軸ラベルを文字化けさせないため、最初に次のセルを1回実行してjapanize_matplotlibを読み込みます。

%pip install -q japanize-matplotlib
import japanize_matplotlib

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 1, figsize=(9, 6), sharex=True)

axes[0].plot(df["日付"], df["売上"], marker="o")
axes[0].set_ylabel("売上")
axes[0].set_title("日別売上")
axes[0].grid(alpha=0.3)

axes[1].plot(df["日付"], df["前日差"], marker="o", color="tab:orange")
axes[1].axhline(0, color="gray", linewidth=1)
axes[1].set_ylabel("前日差")
axes[1].set_xlabel("日付")
axes[1].set_title("前日からの増減")
axes[1].grid(alpha=0.3)

fig.autofmt_xdate()
plt.tight_layout()
plt.show()
売上と前日差を示す折れ線グラフ
売上水準と前日からの増減を上下に分けて示したグラフ

上段では売上水準、下段では前日からの増減を確認できます。0より上なら増加、下なら減少です。グラフの色・線種・凡例などを整えたい場合は、Matplotlib折れ線グラフの描き方を参考にしてください。

まとめ

diff()を使うと、DataFrameやSeriesで前の行との差分を簡単に計算できます。

  • 標準のdiff()は「現在行 − 1つ前の行」を計算する
  • 正の値は増加、負の値は減少、0は変化なしを表す
  • 先頭行のNaNは比較相手がないためで、エラーではない
  • periodsで比較する行を変更でき、periods=2は原則として2行前を意味する
  • 時系列データは、日付型と並び順を確認してから計算する
  • 日付が欠けている場合、前の行との差を前日差とは限らない
  • 増減率にはpct_change()、前の値にはshift()、移動平均にはrolling()を使う

まずは、日付変換→日付順に並び替え→diff()で差分列を追加という順番を覚えましょう。これで日別売上やアクセス数について、前回からの増減を正しく確認できるようになります。

関連記事

仕様を確認したい場合は、pandas公式ドキュメント:DataFrame.diffも参考になります。

▲ ページトップへ戻る

pandasで前の行との差を求めるにはどうすればよいですか?

対象のSeriesにdiff()を使います。売上列ならdf["売上"].diff()で、現在行から1つ前の行を引いた差分を求められます。

diff()の先頭行がNaNになるのはなぜですか?

先頭行には比較する1つ前の行がないためです。計算エラーではなく、正常な結果です。

diff()で前日差や前日比率を計算できますか?

日付が1日刻みで連続し、日付順に並んでいれば、diff()で前日からの増減量(前日差)を計算できます。割合としての前日比率にはpct_change()を使います。

diff()のperiods=2は何を意味しますか?

現在行と2行前の値との差を意味します。日付が連続している場合は2日前と一致しますが、日付に欠けがあれば2日前とは限りません。

diff()とshift()の違いは何ですか?

diff()は前の行との引き算を行い、増減量を返します。shift()は値を指定行数だけずらし、前の行の値そのものを返します。

日付が連続していなくても前日差になりますか?

なりません。diff()が比較するのは基本的に1つ前の行です。前日の行が存在しなければ、結果は前回観測値との差になります。

コメント

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