はじめに:勘ではなくデータで売上を見通したい

「来週どれくらい売れそうか」を、経験と勘でなんとなく見積もっている。中小ECや個人事業主の現場では、よくある光景だと思います。仕入れや広告予算、在庫の発注は、本当はもう少し根拠のある数字で決めたいところです。

とはいえ、時系列予測のために Python を書いて、ライブラリを学んで、モデルを管理して……となると、片手間ではなかなか手が回りません。

そこで便利なのが BigQuery ML の ARIMA_PLUS です。すでに BigQuery に売上データが入っているなら、SQLを数本書くだけで週次の売上予測ができてしまいます。本記事では、学習データの準備から予測の出力、そして定期再学習の自動化までを、中小ECの現場目線で順番に見ていきます。

ARIMA_PLUS とは

ARIMA_PLUS は、BigQuery ML が提供する時系列予測用のモデルタイプです。名前のとおり古典的な ARIMA をベースにしつつ、実務で困りがちな部分を自動でケアしてくれるのが特徴です。

  • トレンド(右肩上がり・右肩下がり)の自動推定
  • 季節性(週次・年次など)の自動検出
  • 祝日効果(国を指定すると、その国の祝日の影響を考慮)
  • 外れ値・欠損値のある程度の自動補正

うれしいのは、Python やノートブックを用意しなくても、いつもの SQL の延長で完結する点です。データの置き場所(BigQuery)と分析の道具(SQL)が同じなので、データを外に持ち出す手間もありません。

ARIMA_PLUS は単一系列向けのモデルです。「商品カテゴリごとにまとめて予測したい」という場合は、後述の time_series_id_col を使うと、1つの CREATE MODEL で複数系列を同時に学習できます。

学習データの準備

まずは予測のもとになる売上データを整えます。時系列モデルに必要なのは、基本的に 「日付」と「その日の値(売上)」の2列だけです。

ここでは注文明細テーブル raw.orders から、日次の売上を集計する例を考えます。

-- 日次売上を集計する
SELECT
  DATE(ordered_at) AS sales_date,
  SUM(amount)      AS sales_amount
FROM `myproject.raw.orders`
WHERE status = 'paid'              -- キャンセル・未決済は除外
GROUP BY sales_date
ORDER BY sales_date;

ECの売上は曜日の波が大きいので、ノイズを抑えたいときは週次に丸めるのも有効です。DATE_TRUNC で週の頭(月曜)にそろえて集計します。

-- 週次売上を集計する(週の起点を月曜にそろえる)
SELECT
  DATE_TRUNC(DATE(ordered_at), WEEK(MONDAY)) AS sales_week,
  SUM(amount)                                AS sales_amount
FROM `myproject.raw.orders`
WHERE status = 'paid'
GROUP BY sales_week
ORDER BY sales_week;

データの粒度(日次か週次か)は、最後まで統一しておくのが鉄則です。学習を日次でやったら予測も日次、というように合わせます。粒度が混ざると予測がうまく機能しません。

なお、ARIMA_PLUS は日付の歯抜け(欠損日)をある程度補ってくれますが、学習に使う期間はできるだけ連続しているほうが安定します。季節性をきちんと捉えるには、最低でも1年分以上のデータがあると安心です。

モデルを作る(CREATE MODEL)

データが用意できたら、CREATE MODEL でモデルを学習します。OPTIONSmodel_type='ARIMA_PLUS' を指定し、どの列が時刻でどの列が値なのかを伝えるだけです。

CREATE OR REPLACE MODEL `myproject.mart.sales_forecast_model`
OPTIONS(
  model_type           = 'ARIMA_PLUS',
  time_series_timestamp_col = 'sales_date',   -- 時刻の列
  time_series_data_col      = 'sales_amount', -- 予測したい値の列
  holiday_region            = 'JP',           -- 日本の祝日を考慮
  auto_arima                = TRUE,           -- パラメータを自動探索
  data_frequency            = 'AUTO_FREQUENCY' -- 頻度(日次/週次など)も自動判定
) AS
SELECT
  DATE(ordered_at) AS sales_date,
  SUM(amount)      AS sales_amount
FROM `myproject.raw.orders`
WHERE status = 'paid'
GROUP BY sales_date;

ポイントを補足します。

  • holiday_region = 'JP' を入れると、日本の祝日(年末年始や連休)による売上の凹凸を考慮してくれます。
  • auto_arima = TRUE にしておくと、ARIMAの細かいパラメータ(p, d, q)を BigQuery 側が自動で探索します。最初はこれに任せて問題ありません。
  • 複数商品をまとめて予測したいときは、集計に商品IDなどを残し、time_series_id_col = 'product_id'OPTIONS に追加します。

複数系列をまとめて学習する場合

CREATE OR REPLACE MODEL `myproject.mart.sales_forecast_by_category`
OPTIONS(
  model_type           = 'ARIMA_PLUS',
  time_series_timestamp_col = 'sales_date',
  time_series_data_col      = 'sales_amount',
  time_series_id_col        = 'category',  -- カテゴリごとに別々のモデルを学習
  holiday_region            = 'JP'
) AS
SELECT
  DATE(ordered_at) AS sales_date,
  category,
  SUM(amount)      AS sales_amount
FROM `myproject.raw.orders`
WHERE status = 'paid'
GROUP BY sales_date, category;

これで、カテゴリごとに個別のモデルが1つの CREATE MODEL で同時に作られます。

ML.FORECAST で予測を出す

学習したモデルから将来の予測を取り出すには ML.FORECAST を使います。horizon で何ステップ先まで予測するかを指定します。日次データなら horizon => 28 でおよそ4週間先までです。

SELECT
  forecast_timestamp,           -- 予測の対象日
  forecast_value,               -- 予測した売上(中央値)
  prediction_interval_lower_bound, -- 予測区間の下限
  prediction_interval_upper_bound  -- 予測区間の上限
FROM
  ML.FORECAST(
    MODEL `myproject.mart.sales_forecast_model`,
    STRUCT(
      28  AS horizon,            -- 28ステップ先まで予測
      0.8 AS confidence_level    -- 予測区間の信頼水準(80%)
    )
  )
ORDER BY forecast_timestamp;

forecast_value が予測の中心値、*_bound の2列が「だいたいこの範囲に収まりそう」という幅(予測区間)です。1つの数字だけを鵜呑みにせず、上下の幅もセットで見るのが、予測とうまく付き合うコツです。

週次で予測したい場合は、週次に集計したデータでモデルを作り、horizon を「何週先まで予測するか」の数(例:12)にします。

結果をそのまま使うのではなく、テーブルに保存しておくとダッシュボードからも参照しやすくなります。

CREATE OR REPLACE TABLE `myproject.mart.weekly_sales_forecast` AS
SELECT
  DATE(forecast_timestamp) AS forecast_date,
  ROUND(forecast_value)    AS forecast_amount,
  ROUND(prediction_interval_lower_bound) AS lower_bound,
  ROUND(prediction_interval_upper_bound) AS upper_bound
FROM
  ML.FORECAST(
    MODEL `myproject.mart.sales_forecast_model`,
    STRUCT(28 AS horizon, 0.8 AS confidence_level)
  );

精度の見方・季節性・限界

予測モデルは「当てるための機械」ではなく、「不確実さの幅を見える化する道具」と捉えると扱いやすくなります。

モデルがデータからどんな構造を読み取ったかは ML.ARIMA_EVALUATE で確認できます。

SELECT *
FROM ML.ARIMA_EVALUATE(MODEL `myproject.mart.sales_forecast_model`);

この結果には、検出された季節性の周期や、AIC(モデルの当てはまりの指標。小さいほど良いとされます)などが並びます。has_holiday_effectseasonal_periods を見れば、「ちゃんと週次の波や祝日効果を拾えているか」をざっくり判断できます。

注意したいのは限界です。ARIMA_PLUS は過去のパターンの延長線を引くモデルなので、過去に例のない出来事は予測できません。大型セールの初開催、テレビ・SNSでの突発的なバズ、新商品の発売などは、予測区間を平気で飛び越えます。こうしたイベントが分かっている週は、予測値を機械的に信じず、人の判断で上振れ・下振れを補正してください。

外れ値(一時的な異常値)も要注意です。たとえば「システム障害で1日だけ売上ゼロ」のような日が学習データに混ざると、トレンドの推定が歪むことがあります。明らかに異常な日は、学習用クエリの WHERE であらかじめ除外しておくのが安全です。

なお、本記事に登場する数値はすべて構文を示すための例です。実際の精度はデータの量や質、扱う商材の特性によって大きく変わります。まずは自分のデータで動かし、何週か予測と実績を並べて確かめてみてください。

自動化:スケジュールクエリで定期再学習

予測は一度作って終わりではありません。新しい売上が積み上がるたびに学習し直さないと、すぐに古くなってしまいます。とはいえ毎週手でクエリを実行するのは現実的ではないので、BigQuery のスケジュールクエリで自動化します。

やることはシンプルで、「モデルを再学習する CREATE MODEL」と「予測をテーブルに書き出す ML.FORECAST」を、定期実行に登録するだけです。

-- スケジュールクエリに登録する内容(例:毎週月曜の朝に実行)
-- 1. 最新データでモデルを再学習
CREATE OR REPLACE MODEL `myproject.mart.sales_forecast_model`
OPTIONS(
  model_type           = 'ARIMA_PLUS',
  time_series_timestamp_col = 'sales_date',
  time_series_data_col      = 'sales_amount',
  holiday_region            = 'JP',
  auto_arima                = TRUE
) AS
SELECT
  DATE(ordered_at) AS sales_date,
  SUM(amount)      AS sales_amount
FROM `myproject.raw.orders`
WHERE status = 'paid'
GROUP BY sales_date;

再学習と書き出しを分けたい場合は、スケジュールクエリを2本に分け、書き出し側を学習の少しあとの時刻に設定すると安全です。スケジュールクエリの作り方や運用上の注意点は、BigQueryのスケジュールクエリでデータマートを毎日自動更新する で詳しく解説していますので、あわせてご覧ください。

頻度の目安としては、週次予測なら週1回の再学習で十分なことが多いです。日次で頻繁に学習し直すよりも、無駄なコストを抑えられます。BigQuery の費用を抑える工夫は BigQueryの料金を月1万円以下に抑える実践テクニック にまとめてあります。

まとめ

ARIMA_PLUS を使えば、Python もインフラも用意せず、SQLだけでEC売上の週次予測ができます。本記事の流れを整理すると、次の4ステップです。

  1. 学習データの準備 — 日付と売上の2列に集計する
  2. モデルの作成CREATE MODEL ... OPTIONS(model_type='ARIMA_PLUS', ...)
  3. 予測の取得ML.FORECAST で予測値と予測区間を出す
  4. 自動化 — スケジュールクエリで定期的に再学習する

大事なのは、予測値を「絶対の正解」ではなく「判断の補助線」として使うことです。予測区間の幅を意識し、セールやイベントなど機械が知らない事情は人が補う。この組み合わせで、勘だけに頼っていた仕入れや予算配分に、ぐっと根拠が加わります。

まずは手元の売上データで、4週間先の予測を1本出してみるところから始めてみてください。