日別売上を見ながら、「前日よりいくら増えたのか」を1行ずつ計算するのは大変です。pandasのdiff()を使えば、現在の行から1つ前の行を引いた差分をまとめて計算できます。
先に結論を示すと、前の行からの増減「量」を求める基本形はdf["売上"].diff()です。ただし、diff()は日付そのものではなく、DataFrameの現在の行順に沿って計算します。時系列データでは、日付型への変換と日付順の並び替えを先に済ませることが重要です。
この記事では日別売上を例に、引き算の向き、先頭がNaNになる理由、periodsの意味、shift()・pct_change()・rolling()との違いまで、Google Colabで実行しながら確認します。
この記事でわかること
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()は、読み込んだデータを確認・整形したあとに、変化を表す列を作る処理として使えます。
- CSVをDataFrameに読み込む
head()やinfo()で列とデータ型を確認する- 日付列を
to_datetime()で日付型に変換する sort_values()で日付順に並べるdiff()で前の行からの増減列を作る- 増減が大きい日を確認する
- 必要に応じて
rolling()やresample()で傾向を集計する - 折れ線グラフなどで可視化する
このように、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入門|作り方・基本操作をわかりやすく解説
- Google ColabでCSVを読み込む方法|アップロード・Drive・read_csv
- pandas to_datetime()の使い方|文字列の日付変換とformat・NaT対処
- pandas 並び替え(sort)入門|sort_values・sort_indexの違い
- pandas rolling()の使い方|移動平均・window・NaNを解説
- pandas resample()の使い方|月別・週別に集計する方法
- Matplotlib折れ線グラフの描き方
- Pandasロードマップ
仕様を確認したい場合は、pandas公式ドキュメント:DataFrame.diffも参考になります。
コメント