はじめに:誰が次に買ってくれそうかを知りたい
「メルマガやクーポンを全員に同じだけ配っているけれど、本当はもっと買いそうなお客さんに集中したい」。中小ECや個人事業主の現場では、よくある悩みだと思います。
ただ、「買いそうな人」を勘で選ぶと、たいてい上得意ばかりに偏ってしまいます。本当に効くのは「あと一押しで買いそうな人」を見つけることなのですが、それを目視で探すのはなかなか大変です。
そこで使えるのが BigQuery ML の購買予測モデルです。すでに BigQuery に購買履歴や行動ログが入っているなら、SQLを数本書くだけで「次に買う確率」をお客さんごとに出せます。本記事では、学習データの準備からモデルの作成、見込み客の抽出、そして評価と注意点までを、中小ECの現場目線で順番に見ていきます。
時系列で「全体の売上がどう動くか」を予測したい場合は、ARIMA_PLUSでEC売上の週次予測を自動化する記事も合わせて参考にしてください。今回は「個人ごとに買うかどうか」を当てる、いわば分類の話です。
やりたいことを整理する
今回作るのは、こういうモデルです。
- 入力:お客さんごとの特徴量(過去の購入回数、最終購入からの経過日数、閲覧した商品数 など)
- 出力:「これから一定期間内に購入するかどうか(する=1 / しない=0)」の確率
このように「Yes / No」を当てる問題は、機械学習では 二値分類 と呼びます。BigQuery ML なら LOGISTIC_REG(ロジスティック回帰)というモデルで手軽に扱えます。シンプルですが、結果の解釈がしやすく、最初の一本としては十分に実用的です。
💡 補足 「ロジスティック回帰」という名前に「回帰」と入っていますが、やっていることは分類です。出力が 0〜1 の確率になるので、しきい値(例:0.5)で「買う / 買わない」に分けられる、というイメージで大丈夫です。
ステップ1:学習データを準備する
機械学習でいちばん大事なのは、実はモデルよりも学習データの作り方です。ここがずれていると、どんなモデルでも当たりません。
今回は「ある基準日までの行動」から「その後30日以内に購入したか」を予測する形にします。つまり、特徴量を集める期間と、答え(ラベル)を集める期間をきっちり分けるのがポイントです。
ここでは、注文テーブル orders と閲覧ログ pageviews があると仮定して、基準日を 2026-05-31 として特徴量を作ります。
-- 学習用の特徴量+ラベルを作るクエリ
CREATE OR REPLACE TABLE `myproject.ec.training_data` AS
WITH
-- 基準日「以前」の行動から特徴量を作る
features AS (
SELECT
o.customer_id,
COUNT(DISTINCT o.order_id) AS order_count, -- 累計注文回数
SUM(o.total_amount) AS total_spend, -- 累計購入金額
DATE_DIFF(DATE '2026-05-31', MAX(o.order_date), DAY) AS days_since_last, -- 最終購入からの日数
AVG(o.total_amount) AS avg_order_value -- 平均購入単価
FROM `myproject.ec.orders` AS o
WHERE o.order_date <= DATE '2026-05-31'
GROUP BY o.customer_id
),
-- 閲覧行動も特徴量に加える
browsing AS (
SELECT
customer_id,
COUNT(*) AS pageview_count, -- 基準日前30日の閲覧数
COUNT(DISTINCT product_id) AS viewed_products
FROM `myproject.ec.pageviews`
WHERE event_date BETWEEN DATE_SUB(DATE '2026-05-31', INTERVAL 30 DAY)
AND DATE '2026-05-31'
GROUP BY customer_id
),
-- 基準日「より後」の30日で実際に買ったか(=答え)
label AS (
SELECT DISTINCT customer_id, 1 AS purchased
FROM `myproject.ec.orders`
WHERE order_date BETWEEN DATE_ADD(DATE '2026-05-31', INTERVAL 1 DAY)
AND DATE_ADD(DATE '2026-05-31', INTERVAL 30 DAY)
)
SELECT
f.customer_id,
f.order_count,
f.total_spend,
f.days_since_last,
f.avg_order_value,
IFNULL(b.pageview_count, 0) AS pageview_count,
IFNULL(b.viewed_products, 0) AS viewed_products,
IFNULL(l.purchased, 0) AS purchased -- ラベル:買った=1 / 買ってない=0
FROM features AS f
LEFT JOIN browsing AS b USING (customer_id)
LEFT JOIN label AS l USING (customer_id);
ポイントは、ラベル(答え)を 基準日より後 の期間から作っていることです。特徴量に「未来の情報」が混ざると、後述する「データ漏洩」という問題が起きてしまいます。
💡 補足 特徴量は最初から欲張らなくて大丈夫です。「最終購入からの日数」「累計注文回数」「累計金額」のいわゆる RFM 的な3つだけでも、けっこう手応えのあるモデルになります。まずは少数で動かして、効きそうな特徴量を後から足していくのがおすすめです。
ステップ2:CREATE MODEL でモデルを学習する
学習データができたら、モデルの作成は CREATE MODEL 一発です。model_type に LOGISTIC_REG を指定し、答えの列を input_label_cols で教えてあげます。
⚠️ 注意 BigQuery ML の構文・オプション名・出力列名(
ML.PREDICTの結果列など)はバージョンによって変わることがあります。実際に動かす前に、必ず最新の公式ドキュメントで確認してください。
CREATE OR REPLACE MODEL `myproject.ec.purchase_prediction`
OPTIONS (
model_type = 'LOGISTIC_REG', -- ロジスティック回帰(二値分類)
input_label_cols = ['purchased'], -- 答えの列
auto_class_weights = TRUE, -- 買う人/買わない人の偏りを自動で補正
data_split_method = 'AUTO_SPLIT', -- 学習用と評価用を自動で分割
l2_reg = 0.1 -- 過学習を抑える正則化
) AS
SELECT
-- customer_id は識別子なので学習からは外す
order_count,
total_spend,
days_since_last,
avg_order_value,
pageview_count,
viewed_products,
purchased
FROM `myproject.ec.training_data`;
いくつか実務で効くオプションがあります。
auto_class_weights = TRUE:EC では「買わない人」が圧倒的に多く、データが偏りがちです。これを付けないと「全員買わない」と予測するだけのモデルになりかねません。data_split_method = 'AUTO_SPLIT':学習用と評価用のデータを自動で分けてくれます。手元のデータで自分を採点しても意味がないので、評価用を分けておくのが鉄則です。l2_reg:過学習(後述)を抑えるためのブレーキです。
customer_id を学習列に入れていない点にも注意してください。お客さん一人ひとりに固有の ID は予測の役に立たないどころか、過学習の原因になります。
ステップ3:ML.PREDICT で見込み客を抽出する
学習が終わったら、ML.PREDICT で予測します。ここでは「いま現在のお客さん」の特徴量を同じ形で用意して、購入確率を出します。
ML.PREDICT の結果には predicted_purchased_probs という配列が付いてきて、各クラス(1 と 0)の確率が入っています。ここから「購入する(label = 1)の確率」だけ取り出すと扱いやすくなります。
-- 購入確率が高い順に見込み客を抽出する
SELECT
customer_id,
predicted_purchased AS predicted_label, -- モデルの判定(0/1)
-- 「購入する(=1)」確率だけ取り出す
(SELECT prob
FROM UNNEST(predicted_purchased_probs)
WHERE label = 1) AS purchase_probability
FROM ML.PREDICT(
MODEL `myproject.ec.purchase_prediction`,
(
SELECT * FROM `myproject.ec.current_customers` -- 学習時と同じ特徴量を持つテーブル
)
)
WHERE (SELECT prob
FROM UNNEST(predicted_purchased_probs)
WHERE label = 1) >= 0.6 -- 確率60%以上を見込み客とする
ORDER BY purchase_probability DESC;
この結果を使えば、たとえば「購入確率60%以上のお客さんだけにクーポンを配る」「上位300人にだけリターゲティング広告を当てる」といった、メリハリのある施策が組めます。全員に同じ予算を配るより、効率はぐっと上がるはずです。
💡 補足 しきい値(ここでは 0.6)は固定の正解があるわけではありません。「予算が限られているから上位だけに絞りたい」なら高めに、「取りこぼしを減らしたい」なら低めに、施策の目的に合わせて調整してください。
ステップ4:評価指標と、過学習・データ漏洩の注意
モデルができたら、必ず精度を確認します。ML.EVALUATE で主要な指標がまとめて出ます。
SELECT *
FROM ML.EVALUATE(MODEL `myproject.ec.purchase_prediction`);
ここで特に見たいのが ROC AUC です。これは「買う人と買わない人をどれだけ見分けられるか」を 0〜1 で表す指標で、0.5 だと当てずっぽうと同じ、1.0 に近いほど優秀、という読み方になります。EC の購買予測では 0.7〜0.8 くらい出れば実用ラインと言われることが多いです(あくまで一般的な目安の例です。実際の数字はデータ次第なので、ご自身の環境で確認してください)。
精度(accuracy)だけを見るのは危険です。買わない人が95%を占めるデータなら、「全員買わない」と答えるだけで精度95%になってしまうからです。偏ったデータでは、ROC AUC や適合率・再現率(precision / recall)まで合わせて見るようにしてください。
そして、購買予測でいちばん気をつけたいのが次の2つです。
⚠️ 注意:データ漏洩(リーク)に気をつける 予測したい「未来」の情報が、うっかり特徴量に混ざっていないか必ず確認してください。たとえば「予測対象期間中の閲覧数」を特徴量に入れてしまうと、評価上の精度は跳ね上がりますが、本番では使えないモデルになります。「答えを知った状態で問題を解いている」状態だからです。特徴量とラベルの集計期間を、はっきり時間で区切るのが対策です。
⚠️ 注意:過学習(オーバーフィッティング)に気をつける 学習データだけにやたら強くて、新しいデータでは外す状態を過学習といいます。
AUTO_SPLITで分けた評価用データの ROC AUC が、学習時より大きく下がっていたら過学習のサインです。特徴量を増やしすぎない、l2_regを効かせる、データ件数を増やす、といった対策で抑えられます。
データが少ない(数百件など)うちは、無理に複雑なモデルを作るより、特徴量を絞ってシンプルに保つほうが結果的に安定します。
まとめ
BigQuery ML を使えば、Python を書かなくても SQL だけで購買予測モデルが作れます。今回の流れを振り返ると、次の4ステップでした。
- 学習データの準備:特徴量とラベルの期間を時間で区切って作る
- CREATE MODEL:
LOGISTIC_REGで購入有無を分類する - ML.PREDICT:購入確率で見込み客を抽出する
- 評価と注意:ROC AUC で精度を確認し、過学習・データ漏洩を防ぐ
最初の一本としては、特徴量を3〜4個に絞ったシンプルなモデルで十分です。まずは動かしてみて、「思ったより当たるな」「ここが効いてるな」という手応えを掴むところから始めるのがおすすめです。
なお、こうしたSQLを書くのにハードルを感じる場合は、自然言語で BigQuery に問い合わせられる仕組みも整ってきています。Gemini in BigQueryで自然言語からSQLを生成する記事も合わせて読むと、「SQLが苦手でもデータ活用を始める」イメージが湧きやすいと思います。