移動平均
このレッスンでできるようになること。rolling で移動平均を計算し、日々の凸凹の裏にある傾向を読めるようになります。
日別の売上を折れ線で描くと、たいていギザギザになります。土日は多く、平日は少ない。給料日の後は増える。こうした周期的な上下は本物の変化ですが、知りたいのが「全体として伸びているのか」であれば、この凸凹は邪魔です。凸凹をならして傾向だけを取り出すのが移動平均です。
移動平均は、その日を含む直近の何日かの平均を、日ごとに計算していったものです。7日移動平均なら、曜日の影響がちょうど1周するので、曜日による上下が消えます。週の周期を持つデータで7日を選ぶのは、そういう理由です。
Python
daily = df.groupby("売上日")["金額"].sum().sort_index()
smoothed = daily.rolling(window=7).mean()rolling は窓を作るだけで、まだ計算はしません。mean や sum をつないで初めて値が出ます。窓が埋まらない最初の6日分は NaN になります。これも欠損ではなく「まだ計算できない」という意味なので、0で埋めてはいけません。傾向線が0から立ち上がる不自然な図になります。
移動平均を使うときの注意が2つあります。1つめは、直近の動きが鈍く見えることです。平均には過去の値が混ざっているので、急に売上が落ちても移動平均はゆっくりしか下がりません。異変の検知には向きません。2つめは、窓の幅で印象が変わることです。幅を広げるほど滑らかになりますが、実際の変化も見えなくなります。曜日の影響を消したいなら7日、月内の変動を見たいなら30日というように、消したい周期に合わせて選びます。
読み方の例を挙げます。日別の生の線が上下していても、移動平均の線が右上がりなら「変動はあるが基調は伸びている」と言えます。逆に生の線が最近高くても、移動平均が下向きなら「直近の高さは一時的で、流れは下降している」と読みます。この2本を重ねて描くと、変動と傾向を同時に見せられます。第6章で覚えた複数系列の描き方がここで効いてきます。
要件
- 売上日ごとに集計してから sort_index() で古い順に並べる
- 移動平均は rolling(window=window).mean() で求める
- 窓が埋まらない期間の NaN は dropna で落とす
- averages は round(float(...), 1) で丸める
- direction は最初と最後の移動平均を比べて決める
入出力例
smooth_daily("売上日,店舗,商品名,カテゴリ,数量,金額
2026-01-01,渋谷店,白磁のマグカップ,食器,1,1000
2026-01-02,渋谷店,白磁のマグカップ,食器,1,3000
2026-01-03,横浜店,鉄のフライパン,調理器具,1,2000
2026-01-04,横浜店,鉄のフライパン,調理器具,1,4000
2026-01-05,大宮店,布製収納バスケット,収納,1,6000
", 3) → {"averages":[2000,3000,4000],"dates":["2026-01-03","2026-01-04","2026-01-05"],"direction":"上向き"}
smooth_daily("売上日,店舗,商品名,カテゴリ,数量,金額
2026-02-01,渋谷店,鋳物ホーロー鍋,調理器具,1,8000
2026-02-02,渋谷店,鋳物ホーロー鍋,調理器具,1,6000
2026-02-03,大宮店,積み重ね収納ボックス,収納,1,4000
2026-02-04,大宮店,積み重ね収納ボックス,収納,1,2000
", 2) → {"averages":[7000,5000,3000],"dates":["2026-02-02","2026-02-03","2026-02-04"],"direction":"下向き"}