ふくふくHukuhuku Inc.
EP.04Anomaly 10分公開: 2026-05-10

時系列の異常検知:STL分解と Prophet

「金曜は普段からアクセスが多い」「12 月は売上が伸びる」── 季節性を考慮した異常検知。STL 分解で trend/seasonal/residual に分解し、residual で異常を見つける。

#時系列#STL#Prophet
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

「金曜は元々アクセス多い」のに「金曜のアクセスが普段より多い」を異常検知したい── 季節性を考慮した時系列異常検知の話。

ダミーデータの生成(実走できるサンプル)

週次季節性 + 異常 5 件のダミー時系列
Python
import numpy as npimport pandas as pd
np.random.seed(42)dates = pd.date_range("2026-01-01", periods=180, freq="D")trend = np.linspace(100, 120, 180)weekly = 10 * np.sin(2 * np.pi * np.arange(180) / 7)  # 週次季節性noise = np.random.normal(0, 3, 180)series = pd.Series(trend + weekly + noise, index=dates)
# 異常を 5 件埋め込むanomaly_idx = [30, 60, 100, 130, 160]series.iloc[anomaly_idx] += np.random.choice([-30, 30], 5)
df = series.reset_index()df.columns = ["ds", "y"]print(df.head())

STL 分解で異常検知

Seasonal-Trend decomposition using LOESS。時系列を trend + seasonal + residual に分解し、residual の異常を検知する。 EP.21 の移動平均と並ぶ時系列前処理の定石。

statsmodels で STL 分解 → 異常検出
Python
from statsmodels.tsa.seasonal import STLimport matplotlib.pyplot as pltimport japanize_matplotlib  # noqa: F401
stl = STL(series, period=7).fit()residual = stl.resid
# residual に対して 3σthreshold = 3 * residual.std()detected = residual[residual.abs() > threshold]print(f"検出件数: {len(detected)}")print(f"検出日: {list(detected.index.strftime('%Y-%m-%d'))}")
# 可視化fig, axes = plt.subplots(4, 1, figsize=(12, 10), sharex=True)stl.observed.plot(ax=axes[0]); axes[0].set_title("元データ")stl.trend.plot(ax=axes[1]); axes[1].set_title("トレンド")stl.seasonal.plot(ax=axes[2]); axes[2].set_title("季節性")stl.resid.plot(ax=axes[3]); axes[3].set_title("残差")axes[3].axhline(threshold, color="r", linestyle="--", alpha=0.5, label=f"+{threshold:.1f}σ")axes[3].axhline(-threshold, color="r", linestyle="--", alpha=0.5)axes[3].scatter(detected.index, detected.values, color="red", s=80, zorder=5, label="異常")axes[3].legend()plt.tight_layout(); plt.show()

Prophet で異常検知(信頼区間外)

Facebook が開発した時系列予測ライブラリ。uncertainty interval(信頼区間) を出してくれるので、「予測区間を外れたら異常」という判定に使える。ホリデー設定で日本特有の祝日も組み込める。

Prophet で異常検知(実走例)
Python
# !pip install prophetfrom prophet import Prophetimport pandas as pd
m = Prophet(    weekly_seasonality=True,    yearly_seasonality=False,    interval_width=0.95,  # 95% 信頼区間)# 日本の祝日を組み込むm.add_country_holidays(country_name="JP")m.fit(df)
# 既存日付を予測forecast = m.predict(df[["ds"]])
# 信頼区間外を異常とするresult = df.merge(forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]], on="ds")result["anomaly"] = (result["y"] < result["yhat_lower"]) | (result["y"] > result["yhat_upper"])print(f"異常検出: {result['anomaly'].sum()} 件")print(result[result['anomaly']][["ds", "y", "yhat", "yhat_lower", "yhat_upper"]].head())
# 可視化(Prophet 標準)fig = m.plot(forecast)ax = fig.gca()anomalies = result[result["anomaly"]]ax.scatter(anomalies["ds"], anomalies["y"], color="red", s=80, label="異常", zorder=5)ax.legend(); plt.tight_layout(); plt.show()

STL vs Prophet の使い分け

観点STLProphet
学習速度数秒数秒〜数十秒
祝日対応なし(自前)国別ビルトイン
季節性1 種類のみ複数(週・年・カスタム)
外れ値耐性中(LOESS で頑健)
未来予測◎(本来用途)
運用コスト中(依存重め)

ふくふくの進め方

の異常検知に季節性を組み込みたい」というご相談には、STL → Prophet の段階導入を 1〜2 週間で。

次回予告

EP.05 は多変量異常検知:PCA と Mahalanobis 距離。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp