日別売上を見て、「前日より100円増えた」ことは分かっても、「何%増えたか」の計算で迷うことはありませんか。
Pandasでは、前の行からの増減率をpct_change()で計算できます。
df["前日比"] = df["売上"].pct_change(fill_method=None)
最初に覚えるポイントは3つです。
- 結果の
0.1は10%増加を表す - 最初の行は比較元がないため
NaNになる - 比較するのは暦上の前日ではなくデータ上の前の行
したがって「前日比」と呼べるのは、日付が1日間隔で古い順に並んでいる場合です。この記事では日別売上を例に、基本的な使い方から結果の読み方、periods、0や欠損値の注意点まで解説します。
この記事でわかること
pct_change()で前の行からの増減率を求める方法0.1や-0.2をパーセントで読む方法- 最初の行が
NaNになる理由 periodsで比較する行を変える方法- 日付の並び、欠損値、比較元が0の場合の注意点
diff()・shift()・rolling()との使い分け
この記事のゴールは、日付と行順を確認してからpct_change()を使い、増減率を正しく計算・解釈できるようになることです。
先に結論:増減率を求めるならpct_change()を使う
似た処理は、知りたい内容によって使い分けます。
| 機能 | 何を求めるか | 選ぶ場面 | 主な注意点 |
|---|---|---|---|
pct_change() |
前の行からの増減率 | 前日比・前月比を知りたい | 結果は割合。0.1は10% |
diff() |
前の行との差 | 何円・何個増えたか知りたい | 単位は元データと同じ |
shift() |
前の行の値 | 現在値と比較元を並べたい | それ自体は差や率を計算しない |
rolling() |
直近数行の集計値 | 移動平均で変動を滑らかにしたい | 増減率を求める処理ではない |
たとえば、売上が1,000円から1,100円になった場合、diff()の結果は100円、pct_change()の結果は0.1、つまり10%です。
増減した量ならdiff()、増減した割合ならpct_change()と判断すると迷いにくくなります。
pct_change()の計算式と結果の読み方
pct_change()は、現在の値を前の行と比べて、どれだけ増減したかを割合で返します。
増減率 = (現在の値 − 前の行の値) ÷ 前の行の値
結果を読むときは、符号と100倍した値に注目します。
| 結果 | パーセントでの読み方 | 意味 |
|---|---|---|
0.10 |
10% | 10%増加 |
-0.20 |
-20% | 20%減少 |
0.00 |
0% | 変化なし |
1.00 |
100% | 2倍になった |
-1.00 |
-100% | 0になった |
たとえば0.1は0.1%ではなく、10%増加です。
日別売上のサンプルデータを用意する
ここでは、5日分の日付と売上を持つDataFrameを使います。Google Colabで上から順番に実行できます。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"日付": ["2026-08-18", "2026-08-19", "2026-08-20", "2026-08-21", "2026-08-22"],
"売上": [1000, 1100, 990, 990, 1188]
})
df
| 日付 | 売上 | |
|---|---|---|
| 0 | 2026-08-18 | 1000 |
| 1 | 2026-08-19 | 1100 |
| 2 | 2026-08-20 | 990 |
| 3 | 2026-08-21 | 990 |
| 4 | 2026-08-22 | 1188 |
売上は1,000円、1,100円、990円、990円、1,188円と変化しています。この同じデータで、差額と増減率の違いを確認します。
pct_change()の前に日付型と並び順を確認する
pct_change()は、日付の意味を読み取って「前日」を探すのではなく、現在の行と前の行を比較します。そのため、計算前に日付型へ変換し、古い日付から並べることが重要です。
df["日付"] = pd.to_datetime(df["日付"])
df = df.sort_values("日付").reset_index(drop=True)
df.dtypes
| 0 | |
|---|---|
| 日付 | datetime64[ns] |
| 売上 | int64 |
日付がdatetime64[ns]になっていることを確認します。そのうえでsort_values()を使い、日付の昇順に整えています。
日付変換の詳細は「pandas to_datetime()の使い方」、並び替えは「pandas 並び替え(sort)入門」で確認できます。
pct_change()で前の行からの増減率を計算する
売上列にpct_change()を使います。fill_method=Noneを明示すると、欠損値を自動的に前の値で補わずに計算できます。
df["前日比"] = df["売上"].pct_change(fill_method=None)
df
| 日付 | 売上 | 前日比 | |
|---|---|---|---|
| 0 | 2026-08-18 | 1000 | NaN |
| 1 | 2026-08-19 | 1100 | 0.1 |
| 2 | 2026-08-20 | 990 | -0.1 |
| 3 | 2026-08-21 | 990 | 0.0 |
| 4 | 2026-08-22 | 1188 | 0.2 |
前日比列では、2行目が0.1、3行目が-0.1、4行目が0.0、5行目が0.2になります。
- 1,000円から1,100円:10%増加
- 1,100円から990円:10%減少
- 990円から990円:変化なし
- 990円から1,188円:20%増加
最初の行がNaNになるのは、比較する前の行が存在しないためです。エラーではありません。
どの値と比較したかを表で確認する
結果だけでは計算の向きが分かりにくいため、shift()で比較元、diff()で増減額を表示します。現在値・比較元・結果を横に並べると、どの値を分母にしたか確認できます。
comparison = df[["日付", "売上"]].copy()
comparison["前の行の売上"] = comparison["売上"].shift(1)
comparison["増減額"] = comparison["売上"].diff()
comparison["増減率"] = comparison["売上"].pct_change(fill_method=None)
comparison["増減率(%)"] = comparison["増減率"] * 100
comparison
| 日付 | 売上 | 前の行の売上 | 増減額 | 増減率 | 増減率(%) | |
|---|---|---|---|---|---|---|
| 0 | 2026-08-18 | 1000 | NaN | NaN | NaN | NaN |
| 1 | 2026-08-19 | 1100 | 1000.0 | 100.0 | 0.1 | 10.0 |
| 2 | 2026-08-20 | 990 | 1100.0 | -110.0 | -0.1 | -10.0 |
| 3 | 2026-08-21 | 990 | 990.0 | 0.0 | 0.0 | 0.0 |
| 4 | 2026-08-22 | 1188 | 990.0 | 198.0 | 0.2 | 20.0 |
2行目では、現在の売上1,100円から比較元の1,000円を引き、その100円を1,000円で割っています。
| 現在の売上 | 前の行の売上 | 増減額 | 計算 | 増減率 |
|---|---|---|---|---|
| 1,100 | 1,000 | 100 | (1100 - 1000) / 1000 |
0.10=10% |
| 990 | 1,100 | -110 | (990 - 1100) / 1100 |
-0.10=-10% |
| 990 | 990 | 0 | (990 - 990) / 990 |
0.00=0% |
| 1,188 | 990 | 198 | (1188 - 990) / 990 |
0.20=20% |
役割は次のように整理できます。
shift():比較元の値を確認するdiff():増減した量を求めるpct_change():増減した割合を求める
増減率をパーセントで表示する
pct_change()の結果を数値としてパーセントに直す場合は、100を掛けます。分析に使える数値のまま保持するため、%記号を含む文字列には変換しません。
df["前日比(%)"] = (df["前日比"] * 100).round(1)
df[["日付", "売上", "前日比", "前日比(%)"]]
| 日付 | 売上 | 前日比 | 前日比(%) | |
|---|---|---|---|---|
| 0 | 2026-08-18 | 1000 | NaN | NaN |
| 1 | 2026-08-19 | 1100 | 0.1 | 10.0 |
| 2 | 2026-08-20 | 990 | -0.1 | -10.0 |
| 3 | 2026-08-21 | 990 | 0.0 | 0.0 |
| 4 | 2026-08-22 | 1188 | 0.2 | 20.0 |
前日比の0.1と、前日比(%)の10.0は同じ変化を表します。前者は割合、後者は100倍したパーセント値です。
列を追加する基本については「pandasで新しい列を追加する方法」で詳しく確認できます。
periodsで2行前からの増減率を計算する
periodsは、何行前と比較するかを指定する引数です。初期値は1です。periods=2にすると2行前と比較します。
df["2行前比"] = df["売上"].pct_change(periods=2, fill_method=None)
df["2行前比(%)"] = (df["2行前比"] * 100).round(1)
df[["日付", "売上", "2行前比", "2行前比(%)"]]
| 日付 | 売上 | 2行前比 | 2行前比(%) | |
|---|---|---|---|---|
| 0 | 2026-08-18 | 1000 | NaN | NaN |
| 1 | 2026-08-19 | 1100 | NaN | NaN |
| 2 | 2026-08-20 | 990 | -0.01 | -1.0 |
| 3 | 2026-08-21 | 990 | -0.10 | -10.0 |
| 4 | 2026-08-22 | 1188 | 0.20 | 20.0 |
最初の2行は、2行前の比較元がないためNaNになります。
3行目の売上990円は2行前の1,000円と比べて1%減少、4行目の990円は2行前の1,100円と比べて10%減少、5行目の1,188円は2行前の990円と比べて20%増加しています。
periods=2は「2日前」ではなく2行前です。日付が1日間隔で並んでいるときだけ、2日前との比較と一致します。
正の値・負の値・0・NaNをどう読むか
結果は次のように読みます。
| 結果 | 判断 |
|---|---|
| 正の値 | 比較元より増加 |
| 負の値 | 比較元より減少 |
0.0 |
比較元から変化なし |
NaN |
比較元がない、または計算に必要な値が欠けている |
注意したいのは0です。100から0への変化は-100%ですが、0から100への増加率は計算できません。比較元の0を分母にできないため、増加と減少は単純に対称にはなりません。
コードは動くが結果を誤解しやすい場面
前の行は必ずしも前日ではない
次のデータでは、8月19日の次が8月22日です。pct_change()は8月22日を8月19日と比較します。
business_days = pd.DataFrame({
"日付": pd.to_datetime(["2026-08-18", "2026-08-19", "2026-08-22"]),
"売上": [1000, 1100, 1210]
})
business_days["前の行からの増減率"] = business_days["売上"].pct_change(fill_method=None)
business_days
| 日付 | 売上 | 前の行からの増減率 | |
|---|---|---|---|
| 0 | 2026-08-18 | 1000 | NaN |
| 1 | 2026-08-19 | 1100 | 0.1 |
| 2 | 2026-08-22 | 1210 | 0.1 |
8月22日の結果は10%ですが、これは8月21日との前日比ではなく、データ上の前の行である8月19日からの増減率です。
営業日データなら「前営業日比」と呼べます。暦上の前日比が必要な場合は、日付の間隔を確認し、必要に応じて日次の行をそろえてから計算します。月次データなら同じ考え方で前月比を計算できます。
比較元が0の場合は無限大になる
比較元が0の場合、増減率の計算では0による割り算が発生します。
zero_example = pd.DataFrame({
"売上": [100, 0, 50]
})
zero_example["増減率"] = zero_example["売上"].pct_change(fill_method=None)
zero_example
| 売上 | 増減率 | |
|---|---|---|
| 0 | 100 | NaN |
| 1 | 0 | -1.0 |
| 2 | 50 | inf |
100から0への変化は-1.0、つまり-100%です。一方、0から50への変化はinf(無限大)になります。
これはコードの失敗ではなく、比較元が0なので通常の増減率を定義できないためです。0を都合のよい別の値に置き換えるのではなく、元データで0が何を意味するか確認し、必要なら該当行を別扱いにします。
欠損値を安易に0で埋めない
欠損値があるデータでは、比較に必要な値がそろわない行がNaNになります。
missing_example = pd.DataFrame({
"売上": [100, np.nan, 120]
})
missing_example["増減率"] = missing_example["売上"].pct_change(fill_method=None)
missing_example
| 売上 | 増減率 | |
|---|---|---|
| 0 | 100.0 | NaN |
| 1 | NaN | NaN |
| 2 | 120.0 | NaN |
2行目は現在値が欠損し、3行目は比較元となる2行目が欠損しているため、どちらも増減率を計算できません。
欠損値を0で埋めてから計算すると、実際には観測されていない「売上0円」を作り、-100%やinfを発生させる可能性があります。補完する場合は、列の意味と欠損理由を確認してください。欠損値の扱いは「pandas fillna()の使い方」で詳しく解説しています。
Pandasのバージョンによる欠損値補完の挙動へ依存しないよう、この記事ではfill_method=Noneを明示しています。
日付を並び替えないと計算結果が変わる
pct_change()は現在の行順を使います。日付が降順や不規則な順番のままでもコードは動きますが、前日比としては誤った結果になることがあります。
計算前に次の3点を確認します。
- 日付列がdatetime型になっている
- 日付が古い順に並んでいる
- 各行の日付間隔が目的に合っている
CSVを読み込んだ直後は、head()・dtypes・日付の並びを確認してから計算すると安全です。
日別売上と前日比を折れ線グラフで確認する
最後に、売上と前日比を同じ期間で可視化します。左軸が売上、右軸が前日比です。日本語をColabで表示するため、最初の実行時にjapanize-matplotlibを読み込みます。
%pip -q install japanize-matplotlib
import matplotlib.pyplot as plt
import japanize_matplotlib
fig, ax1 = plt.subplots(figsize=(9, 5))
ax1.plot(df["日付"], df["売上"], marker="o", color="tab:blue", label="売上")
ax1.set_xlabel("日付")
ax1.set_ylabel("売上(円)", color="tab:blue")
ax1.tick_params(axis="y", labelcolor="tab:blue")
ax1.grid(alpha=0.3)
ax2 = ax1.twinx()
ax2.plot(df["日付"], df["前日比(%)"], marker="s", color="tab:red", label="前日比")
ax2.axhline(0, color="gray", linewidth=1)
ax2.set_ylabel("前日比(%)", color="tab:red")
ax2.tick_params(axis="y", labelcolor="tab:red")
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc="upper left")
plt.title("日別売上と前日比の推移")
fig.autofmt_xdate()
plt.tight_layout()
plt.show()
売上が同じ990円だった8月21日は前日比が0%、1,188円へ増えた8月22日は20%になります。
グラフでは、売上の水準と増減率を混同しないことが重要です。売上が最も大きい日と、増加率が最も大きい日は必ずしも一致しません。折れ線グラフの基本設定は「Matplotlib 折れ線グラフ入門」で確認できます。
データ分析の流れでpct_change()を使う位置
pct_change()は、データを読み込んですぐ使うのではなく、日付と値を確認した後の「変化を計算する」段階で使用します。
- CSVなどからDataFrameを読み込む
head()やdtypesで内容を確認するto_datetime()で日付型へ変換するsort_values()で日付順に並べるpct_change()で増減率を計算するrolling()や折れ線グラフで傾向を確認する
期間ごとの合計値を作る場合は、先にresample()で月次などへ集計してからpct_change()を使います。移動平均で短期変動を滑らかにする場合は「pandas rolling()の使い方」、期間集計は「pandas resample()の使い方」を参照してください。
まとめ
pct_change()は前の行からの増減率を計算する0.1は10%増加、-0.2は20%減少を表す- 最初の行は比較元がないため
NaNになる periods=2は2日前ではなく2行前との比較になる- 前日比として使う前に、日付型・並び順・日付間隔を確認する
- 比較元が0の場合は
inf、欠損値を含む比較はNaNになることがある - 増減量は
diff()、比較元はshift()、平滑化はrolling()を使う
まずは「割合ならpct_change()」「量ならdiff()」と使い分けましょう。そのうえで、結果が前日比・前営業日比・前月比のどれに当たるかを確認することが大切です。
関連記事
- pandas diff()の使い方|前の行との差分・前日からの増減を計算する方法
- pandas rolling()の使い方|移動平均・window・NaNを初心者向けに解説
- pandas resample()の使い方|日付データを月別・週別に集計する方法
- pandas 並び替え(sort)入門|sort_values・sort_indexの違い
- pandas to_datetime()の使い方|文字列の日付変換とNaT対処
- pandasで新しい列を追加する方法
- pandas fillna()の使い方|欠損値を埋める方法
- Matplotlib 折れ線グラフ入門
- Pandas DataFrame入門|作り方と基本操作
pct_change()の0.1は何%ですか?
10%です。pct_change()は割合を返すため、パーセントで読むときは100を掛けます。-0.2なら20%減少です。
最初の行がNaNになるのはなぜですか?
比較する前の行が存在しないためです。エラーではなく、計算に必要な比較元がないことを表しています。
前日比と前月比は計算できますか?
計算できます。ただし、pct_change()は日付ではなく前の行と比較します。日次データを日付順に並べれば前日比、月次データを月順に並べれば前月比として使えます。日付が欠けている場合は、前営業日比などになる点に注意してください。
pct_change()とdiff()の違いは何ですか?
pct_change()は増減率、diff()は増減量を求めます。1,000円から1,100円になった場合、pct_change()は0.1(10%)、diff()は100円です。
比較元が0の場合はどうなりますか?
0で割ることになるため、増加時にはinfが返ることがあります。通常の増減率を定義できない状態なので、0が何を意味するか確認し、別扱いを検討します。
欠損値がある場合はどうなりますか?
fill_method=Noneを指定した場合、現在値または比較元が欠損している行はNaNになります。欠損値を埋める場合は、データ上の意味を確認してから処理してください。
結果をパーセント表示できますか?
結果に100を掛ければパーセント値になります。計算に使う場合は、%記号を付けた文字列ではなく数値のまま保存する方が扱いやすくなります。
前日比が合わないのはなぜですか?
日付の並び順、日付の欠け、重複日付、欠損値、比較元が0でないかを確認してください。pct_change()が比較するのは暦上の前日ではなく、現在の並びで1つ前にある行です。
DataFrameの複数列にも使えますか?
使えます。df[["売上", "客数"]].pct_change(fill_method=None)のように指定すると、売上と客数を列ごとに計算します。最初は、この記事のように1列ずつ結果を確認する方が理解しやすいでしょう。
axisやfreqも覚える必要がありますか?
通常の前日比・前月比では、まず初期設定の行方向だけ理解すれば十分です。列方向を比較するaxisや、日時オフセットを使うfreqは発展的な指定なので、必要になった段階で確認しましょう。
コメント