スーパーの毎週のチラシに載せる特売品の販売数を、過去の特売の実績・売価・曜日・天気から店舗ごとに見込み、発注量の案を出す
毎週のチラシに載せる特売品について、特売期間の販売数を店舗ごとに見込みます。過去の特売の実績、売価と値引き、曜日、天気予報を材料にし、販売数の幅から店舗別の発注量の案を作ってバイヤーに渡します。
- 連携・自動化
- Python
- 対象業界
- 商社/小売
- 対象部門
- 購買
- 対象業務
- 集計・分析
- 主な課題
- データ分析に時間がかかる/判断に時間がかかる/属人化している
- AIで行う処理
- 予測
- 主な効果
- 判断支援/工数削減/機会損失防止
- 導入難易度
- ★★★★★
- 実装レベル
- 本格構成
- 費用感
- 個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- チラシの掲載が決まった品目の一覧を受け取る
- 品目ごとに、自分の特売の実績表から、過去に同じ商品を載せた回を探す
- 見つかった回の売価・掲載面・曜日と、今回の条件を見比べる
- POSから前回の特売期間の店舗別の販売数を確かめる。売り切れた店舗が無かったかを店舗への問い合わせの記録で見る
- 天気予報を見て、気温や雨で売れ方が変わる品目かを考える
- 店舗ごとの発注量を決めて発注システムに入れる
- 人チラシの掲載が決まったら、品目・売価・掲載面・特売の期間を掲載の記録に入れる
- 自動毎週火曜の朝、Pythonのプログラムが掲載の記録とPOSの実績、天気予報を取り込む
- 自動学習済みのモデルが、品目×店舗ごとに特売期間の販売数を、中央と上側の2つの値で見込む
- 自動店舗の在庫と、品目の区分(日持ちする/しない)から、発注量の案を作る
- 自動見込みの根拠(条件の近い過去の回、その回の売り切れの有無)を添えて、バイヤーごとの一覧にする
- 人バイヤーが一覧を見て、店舗の事情(改装、近くの競合店の開店)で直し、発注システムに入れる
- 自動特売の後に、見込みと実績と売り切れの有無を突き合わせ、次の学び直しに使う
各工程の詳しい説明を読む
- チラシの掲載が決まった品目の一覧を受け取る
- 品目ごとに、自分の特売の実績表から、過去に同じ商品を載せた回を探す
- 見つかった回の売価・掲載面・曜日と、今回の条件を見比べる
- POSから前回の特売期間の店舗別の販売数を確かめる。売り切れた店舗が無かったかを店舗への問い合わせの記録で見る
- 天気予報を見て、気温や雨で売れ方が変わる品目かを考える
- 店舗ごとの発注量を決めて発注システムに入れる
(a)過去の回を探すのに時間がかかる。 同じ商品でも、売価、掲載面(表の目玉か裏面か)、特売の日数が回ごとに違います。条件の近い回を探して見比べるだけで、1品目の時間の半分を使います。
(b)売り切れた店舗の実績が低く見える。 POSの数字は売れた数で、昼に売り切れた店舗も、閉店まで残った店舗も、同じ「販売数」として並びます。 売り切れを店舗に問い合わせた記録が無い回は、見分けがつきません。
(c)天気の効き方が品目ごとに違う。 気温が上がると飲料とアイスが、雨が降ると来店客そのものが変わります。どの品目がどれくらい天気で動くかは、経験の長いバイヤーしか知りません。
(d)締めの前に時間が足りない。 80品目を数日で決めるので、後半の品目ほど前回の数字をそのまま使うことになります。
(e)外れた理由が残らない。 欠品や売れ残りが出ても、発注量をどう決めたかの記録が無いので、次の特売で同じ品目を載せるときに、前回の外れを踏まえられません。 外れた理由を覚えているのは、そのときのバイヤーだけです。
- 【人】 チラシの掲載が決まったら、品目・売価・掲載面・特売の期間を掲載の記録に入れる
- 【自動】 毎週火曜の朝、Pythonのプログラムが掲載の記録とPOSの実績、天気予報を取り込む
- 【自動】 学習済みのモデルが、品目×店舗ごとに特売期間の販売数を、中央と上側の2つの値で見込む
- 【自動】 店舗の在庫と、品目の区分(日持ちする/しない)から、発注量の案を作る
- 【自動】 見込みの根拠(条件の近い過去の回、その回の売り切れの有無)を添えて、バイヤーごとの一覧にする
- 【人】 バイヤーが一覧を見て、店舗の事情(改装、近くの競合店の開店)で直し、発注システムに入れる
- 【自動】 特売の後に、見込みと実績と売り切れの有無を突き合わせ、次の学び直しに使う
6番目が、この設計の分かれ目です。 一覧は発注量の「案」で、発注システムには自動で入れません。 モデルは店舗の改装や競合店の開店を知りません。バイヤーが直した量と理由を残すことで、モデルが知らない事情が何かが見えてきます。
7番目を省くと、モデルは古くなり続けます。 特に売り切れの有無は、特売の直後でないと店舗に聞いても分からなくなります。
3番目で2つの値を出すのも、意図してのことです。 1つの数字だけを出すと、バイヤーはそれを「当たる数字」と受け取り、外れたときにモデルごと信じなくなります。幅で出せば、外れ方そのものが見込みの中に含まれます。 中央と上側の差が大きい品目は、売れ方が読みにくい品目だと一目で分かります。
02今回想定するシステム構成
チラシの掲載の記録(品目・売価・掲載面・期間) POS(単品・店舗・日別の売上、時間帯別の売上) 在庫(店舗別) 天気(過去:気象庁の過去の気象データ/今回:発注時点の予報) │ ▼【トリガー】毎週火曜の朝(定時実行) Python(社内のサーバー) ├──▶ 過去の特売の回の抽出と、売り切れの推定 ├──▶ 特徴量の作成(値引き率・掲載面・曜日・気温・降水) ▼ Python(scikit-learn の HistGradientBoostingRegressor) │ loss="quantile" quantile=0.5(中央)と 0.8(上側) ▼ Python ── 発注量の案(在庫・ケースの入数・品目の区分) ▼ バイヤーごとの一覧(根拠:条件の近い過去の回) ▼ 【人が確認して直す】── 発注システムへはバイヤーが入れる ▼ 特売の後:見込み・実績・売り切れの突き合わせ
| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 実行環境 | Python(pandas・scikit-learn の HistGradientBoostingRegressor) | R、Amazon SageMaker、BigQuery ML |
| 保管 | 社内のデータベース(特売の回・見込み・実績)、共有フォルダ(一覧) | 既存のデータ基盤 |
| 天気 | 気象庁の過去の気象データ(CSV)、発注時点の天気予報 | 民間の気象情報サービス |
予測の本体は、scikit-learn の HistGradientBoostingRegressor です。 損失に quantile(ピンボール損失)を選び、quantile に0から1の値を指定すると、その分位点を見込むモデルになります。中央(0.5)と上側(0.8)で2つのモデルを学習します。
値引きの深さと販売数の関係には、単調性の制約(monotonic_cst)を付けます。 値引き率には「増えると販売数が増える」(1)、売価には「上がると販売数が減る」(-1)を指定できます。データの少ない品目で、値引きを深くしたのに見込みが下がる、という不自然な結果を防ぎます。
欠損値(NaN)はそのまま扱えます。 学習のときに欠損のあるサンプルを左右どちらの枝に送るかを学ぶとされているので、天気のデータが欠けた日や、前回の特売の実績が無い品目も、値を埋めずに入れられます。
生成AIは使いません。 この業務で必要なのは、過去の数値から販売数の幅を出すことで、文章を読む工程がありません。数値の見込みを生成AIに頼むと、同じ入力でも答えが揺れ、外れたときに理由を追えません。 分位点回帰のモデルなら、同じ入力には同じ見込みが返り、特徴量を変えたときの動きも確かめられます。
03どうやって実装するのか
処理の起点を決める
毎週火曜の朝に、社内のサーバーで1回動かします。 チラシの掲載は2週間前に決まり、発注は特売の前週の金曜に締めます。火曜の朝に一覧が出れば、バイヤーは水曜と木曜で直し、金曜の締めに間に合います。
天気予報は、動かす時点で手に入るものを使います。 特売の木曜から日曜は、火曜から見て2〜5日先です。予報は先の日ほど外れやすいので、日曜の気温の見込みが外れることを前提に、天気で大きく動く品目には印を付けます(前処理の6番)。金曜の締めの直前にもう一度だけ動かし、天気で動く品目の見込みだけを差し替える運用もできます。
学び直しは月に1回です。 毎週の特売の結果(実績と売り切れの有無)がたまるのを待ち、月初に過去2年分で学び直します。学び直したモデルは、直近8週の特売で前のモデルと成績を比べ、良くなったときだけ入れ替えます。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| チラシの掲載の記録 | 回、品目、売価、通常の売価、掲載面(表の目玉/表/裏)、特売の期間、点数の制限(お一人様○点まで) | 掲載の記録(表計算のファイル) |
| POSの売上 | 品目・店舗・日別の販売数と売上、時間帯別の販売数 | POS |
| 在庫 | 品目・店舗別の在庫数、ケースの入数 | 発注システム |
| 天気(過去) | 店舗に近い観測地点の日別の最高気温・降水量 | 気象庁の過去の気象データ(CSV) |
| 天気(今回) | 特売期間の各日の最高気温・降水の予報 | 発注時点の天気予報 |
| 店舗の情報 | 売場面積、客数の規模、近くの競合店の有無 | 店舗の一覧 |
| 品目の区分 | 日持ちする/しない、カテゴリ、天気で動く品目か | バイヤーが付ける |
質を決めるのは、掲載の記録と時間帯別の販売数です。 掲載の記録が無ければ、どの日が特売だったかを売上の跳ね上がりから推測することになり、値引き無しで売れた日と特売の日が混ざります。 時間帯別の販売数が無ければ、売り切れを見分けられません(前処理の3番)。
品目の区分は、最初はカテゴリ単位で付けます。 「飲料は日持ちする」「刺身は日持ちしない」をカテゴリで決め、例外の品目だけをバイヤーが直します。
データの取得方法を決める
掲載の記録は、表計算のファイルからそのまま読みます。 列の名前と書き方(売価は税込みか税抜きか、期間は開始日と終了日)を決め、バイヤー全員が同じ書き方で入れるように、入力の欄を固定します。 書き方がばらばらの過去分は、最初に一度だけそろえます。
POSの売上は、POSの書き出しの機能で、品目・店舗・日別と、品目・店舗・時間帯別の2種類を書き出します。 書き出しの形はPOSの製品ごとに違うので、この部分は利用中のシステムに応じた個別の対応が要ります。
過去の天気は、気象庁の「過去の気象データ・ダウンロード」でCSVを取ります。 地点・項目・期間を選び、データを画面に表示せずにCSVファイルとしてダウンロードできます。地点は全国の気象台やアメダス、約1,500地点(観測を終えた約200地点を含む)から選べ、店舗ごとに最寄りの地点を決めます。 日別値で、日最高気温と日降水量を取ります。
CSVを読むときは、品質情報の列を必ず見ます。 表示オプションで「CSVファイルのデータ仕様はすべて数値で格納」を選ぶと、品質情報が値と別の列に入ります。品質情報が8(正常値)と5(準正常値)以外の値は使わず、欠損(NaN)として扱います。 4は資料不足値、2は疑問値、1は欠測です。
均質番号にも気をつけます。 番号の違いは観測環境の変化を表し、番号の違う値同士は単純に比べられないとされています。また、均質番号はCSVを取るたびに古いものから振り直されるので、期間の違う複数のCSVをつなぐときは、番号をそのまま比べないでください。
AIへ渡す前に整形する
- 特売の回の切り出し … 掲載の記録の期間で、品目×店舗の特売期間の販売数を合計します
- ふだんの売れ方の算出 … 特売の直前4週の、同じ曜日の平均販売数を出します。特売でどれだけ伸びたかを見るための基準です
- 売り切れの推定 … 時間帯別の販売数で、閉店の3時間以上前から販売数が0の日を売り切れの疑いとします。疑いのある回は、販売数を「少なくともこれだけ売れた」値として印を付けます
- 値引き率の計算 … (通常の売価 - 特売の売価)÷ 通常の売価。点数の制限があれば別の特徴量にします
- 天気の付け合わせ … 店舗ごとに最寄りの観測地点の日最高気温と日降水量を付けます
- 天気で動く品目の印 … 過去の特売で、気温や雨の有無で販売数が大きく違った品目に印を付けます
- 初めての品目の扱い … 過去の特売の実績が無い品目は、バイヤーが「似た品目」を1つ指定し、その品目の過去の回を参考に使います
3番目が、この構成でいちばん大事な前処理です。 売り切れた回をそのまま学ぶと、欠品した店舗ほど見込みが低くなります。 印を付けた回は、学習から外すか、上側のモデルにだけ使います。最初は学習から外すほうが分かりやすく、件数がたまってから扱い方を決め直します。
3番目の「閉店の3時間以上前」は、最初の目安です。 夕方に売れる品目と朝に売れる品目で違うので、カテゴリごとに見直します。売り切れの疑いは、たとえば次のように見えます。
| 時間帯 | A店(売り切れの疑いなし) | B店(売り切れの疑いあり) |
|---|---|---|
| 9〜12時 | 62 | 88 |
| 12〜15時 | 48 | 52 |
| 15〜18時 | 51 | 0 |
| 18〜21時 | 30 | 0 |
| 特売初日の合計 | 191 | 140 |
合計だけを見ると、B店はA店より売れていないように見えます。 実際には、午前の売れ方はB店のほうが速く、15時に売り切れています。B店の140は「少なくとも140」で、需要はA店より大きかった可能性が高いので、この日のB店の値は学習から外します。
AIに処理させる
モデル(scikit-learn)にさせるのは、品目×店舗ごとに特売期間の販売数を、中央と上側の2つの値で見込むことです。
| 特徴量 | 作り方 | 制約 |
|---|---|---|
| 値引き率 | 前処理の4番 | 増えると販売数が増える(1) |
| 特売の売価 | 税込みの売価 | 上がると販売数が減る(-1) |
| ふだんの売れ方 | 前処理の2番 | 増えると販売数が増える(1) |
| 掲載面 | 表の目玉/表/裏(Categorical 型) | なし |
| 特売の日数・曜日の構成 | 土日を何日含むか | なし |
| 最高気温・降水量 | 特売期間の平均 | なし |
| 店舗 | 店舗番号(Categorical 型) | なし |
| カテゴリ | 品目のカテゴリ(Categorical 型) | なし |
| 点数の制限 | 有無と点数 | なし |
| 前回の特売からの週数 | 同じ品目を前に載せてからの週数 | なし |
店舗とカテゴリを Categorical 型で渡すのは、categorical_features の既定値が "from_dtype" で、この型の列をカテゴリとして扱うからです。 店舗番号を数字のまま渡すと、番号の大小に意味があるものとして学びます。
発注量の案は、モデルの見込みから規則で作ります。 モデルに発注量を直接見込ませないのは、在庫やケースの入数はその週の事情で、過去の販売数からは学べないからです。
上側を0.8にしているのは、最初の目安です。 どの分位点を使うかは、1個足りなかったときの損(売り逃した粗利と、チラシを見て来た客の失望)と、1個余ったときの損(値下げと廃棄)の釣り合いで決まります。足りない損が余る損の4倍なら、見込みの8割の点で発注するのが釣り合う、という考え方です。この比率はカテゴリごとに違うので、バイヤーと一緒に決め、0.8で始めて欠品と売れ残りを見ながら動かします。 分位点ごとにモデルを学習するので、0.7や0.9を足すのは簡単です。
| 品目の区分 | 使う見込み | 発注量の案 |
|---|---|---|
| 日持ちする | 上側(0.8) | 上側の見込み - 店舗の在庫。ケースの入数で切り上げ |
| 日持ちしない | 中央(0.5) | 中央の見込み - 店舗の在庫。ケースの入数で切り捨て |
| 天気で動く印あり | 区分どおり | 同じ。一覧に「天気で動く」と印を付ける |
| させないこと | 理由 |
|---|---|
| 発注システムへの自動入力 | 店舗の改装・競合の開店をモデルは知らない |
| 掲載する品目・売価の提案 | 本記事の範囲外。売価を変えると見込みの前提が変わる |
| 売り切れた回を需要として学ぶ | 欠品した店舗ほど見込みが下がる |
| 初めての品目を推測で見込む | 似た品目をバイヤーが指定したときだけ見込む |
指示内容を固定する
この構成では生成AIを使わないので、プロンプトはありません。 代わりに、学習と見込みのプログラムの要点を示します。
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import mean_pinball_loss
FEATURES = ["discount_rate", "sale_price", "base_sales", "flyer_face",
"days_weekend", "max_temp", "precip", "store", "category",
"qty_limit", "weeks_since_last"]
MONO = {"discount_rate": 1, "sale_price": -1, "base_sales": 1}
# 売り切れの疑いのある回は学習から外す(前処理の3番)
train = rows[(rows.week < cutoff) & (~rows.stockout_suspected)]
test = rows[rows.week >= cutoff]
models = {}
for q in (0.5, 0.8):
m = HistGradientBoostingRegressor(loss="quantile", quantile=q,
monotonic_cst=MONO, max_iter=400)
m.fit(train[FEATURES], train.sales)
models[q] = m
pred = m.predict(test[FEATURES])
print(q, mean_pinball_loss(test.sales, pred, alpha=q))
成績はピンボール損失で測ります。 scikit-learn の mean_pinball_loss は分位点回帰のための損失で、alpha を0.5にすると平均絶対誤差と同じになります。上側(0.8)のモデルは alpha=0.8 で測り、さらに「実績が上側の見込み以下に収まった割合」が8割前後になっているかを見ます。 8割を大きく下回れば、上側の見込みが低すぎて欠品が出ています。
比べる相手は、バイヤーが実際に入れた発注量です。 過去8週の特売で、バイヤーの発注量とモデルの案のどちらが、欠品と売れ残りが少なかったかを品目のカテゴリごとに数えます。
出力形式を固定する
バイヤーごとに、次の形の一覧(CSV)を出します。 1行が品目×店舗です。
| 列 | 例 |
|---|---|
| 品目・店舗 | 2Lの麦茶(6本入)・〇〇店 |
| 中央の見込み・上側の見込み | 186本・232本 |
| 在庫 | 18本 |
| 発注量の案 | 216本(36ケース。日持ちする品目なので上側から) |
| 根拠の回 | 2026年7月第3週(売価・掲載面が近い):実績201本、売り切れなし |
| 印 | 天気で動く |
| バイヤーの発注量 | (空欄。バイヤーが入れる) |
| 直した理由 | (空欄。改装・競合・その他) |
根拠の回を1つ添えるのは、バイヤーが数字を確かめる手がかりにするためです。 条件の近い過去の回は、値引き率と掲載面が同じで、時期が最も近い回を規則で選びます。モデルの中身を説明するものではありませんが、バイヤーが「前回こうだった」と照らせます。
一覧のほかに、品目ごとの店舗のまとめを1枚付けます。 20店舗の案を横に並べ、中央と上側の見込みの差(幅)が大きい店舗に色を付けます。幅が大きいのは、その店舗の過去の特売の売れ方がばらついている印です。 バイヤーが店長に事情を聞くべき店舗が、ここで分かります。
「直した理由」を選択式にしているのは、後で数えるためです。 自由記述にすると集計できません。「その他」が多ければ、選択肢に足すべき理由があります。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| 掲載の記録 | ファイルの読み取り | 品目・売価・掲載面・期間 |
| POS | 書き出しのファイル(個別の対応) | 日別・時間帯別の販売数 |
| 発注システム | 書き出しのファイル(個別の対応) | 在庫、ケースの入数 |
| 気象庁の過去の気象データ | CSVのダウンロード | 過去の日最高気温・日降水量 |
| 天気予報 | 個別の取得 | 特売期間の予報 |
| 共有フォルダ | ファイルの書き出し | バイヤーごとの一覧 |
天気予報の取り方は、自社の環境で決めます。 契約している気象情報サービスがあればそこから取り、無ければ発注の担当が予報を見て、特売期間の各日の最高気温と降水の有無を入力の欄に入れます。どちらの場合も、入れた予報と入れた時刻を残します。 予報の取り方を途中で変えると、見込みの外れ方が変わるからです。
発注システムには書き込みません。 一覧からバイヤーが入れます。発注システムが一括の取り込みに対応していても、最初の半年は手で入れます。 手で入れる段階で、バイヤーがどの品目を直すかの傾向が見えます。
人が確認する
バイヤーが見るのは、印の付いた品目と、案が前回の発注量から大きく離れた品目です。
- 印の付いた品目を先に見る … 「天気で動く」「初めての品目」「売り切れの疑いが続いている店舗」
- 前回の発注量から3割以上離れた案を見る … 根拠の回を見て、理由が分かるかを確かめます
- 店舗の事情で直す … 改装、競合店の開店、地域の行事。直したら理由を選びます
- 残りは案のまま入れる … 一覧で流し見て、発注システムに入れます
2番目を省かないでください。 案が大きく離れるのは、モデルが正しく変化を拾った場合と、掲載の記録の入れ間違い(売価の桁、税込みと税抜き)の場合があります。後者はモデルでは見分けられません。
目標は、320品目をならして1品目6分です。 印の付いた品目は根拠を読んで十数分、残りは数分です。
店長が発注量を直せる運用の会社では、店長の修正も同じ一覧に残します。 バイヤーの修正と店長の修正を分けて記録すると、店舗の事情(近くの催し、改装)を誰が知っているかが分かります。
例外に対処する
| 起きること | 対応 |
|---|---|
| 過去の特売の実績が無い品目 | バイヤーが似た品目を指定するまで見込みを出さない |
| 掲載の記録の売価が通常の売価より高い | 入れ間違いとして見込みを出さず、バイヤーに戻す |
| 天気予報が取れない | 気温・降水を欠損のまま見込み、一覧に「天気なし」と印を付ける |
| 気象庁のCSVの品質情報が資料不足値・疑問値 | その日の値を欠損として扱う |
| 新しく開いた店舗 | 店舗の実績が無い。規模の近い店舗をバイヤーが指定する |
| 売り切れの疑いが同じ店舗で続く | 見込みが低すぎる可能性。上側の見込みを使うようバイヤーに知らせる |
| 特売の期間が途中で延びた・縮んだ | 掲載の記録を直してから学習に使う |
| 学び直したモデルの成績が落ちた | 入れ替えずに前のモデルを使い、原因(記録の書き方の変化など)を調べる |
1行目と5行目は、推測で埋めないでください。 実績の無い品目や店舗に全体の平均を当てると、それらしい数字が出るだけに、バイヤーが疑わずに入れてしまいます。
記録を残す
- 毎週の見込み(品目×店舗、中央・上側)と、使ったモデルの版
- 使った特徴量の値(特に、その時点の天気予報)
- 発注量の案と、バイヤーが入れた発注量・直した理由
- 特売の後の実績と、売り切れの疑いの有無
- 店舗への問い合わせで分かった売り切れの時刻
2つ目の天気予報は、実際の天気とは別に残します。 見込みを外した理由が予報の外れなのか、モデルなのかを分けるためです。学び直しには、予報ではなく実際の天気を使います。
3つ目は、モデルの改善の材料です。 同じ理由で同じ方向に直す品目が続けば、その理由を特徴量に足す候補になります。残す期間は2年以上にします。 学び直しに過去2年分を使うので、それより短いと同じ時期の特売を比べられません。
04実装レベルの3段階
半自動化で、第4章の①(過去の回を探して見比べる)がほぼ無くなります。 発注量は前回の実績を見てバイヤーが決めます。本格構成で、天気と値引き率を考えた案が出て、バイヤーは印の付いた品目を直すだけになります。 本記事の想定はこの段階です。 半自動化を2か月ほど回すと、バイヤーが「条件の近い回」をどう選んでいるかが分かります。 それが根拠の回の選び方の規則になります。 本格構成に進んでも、すべての品目を一度に移さないでください。 日持ちする飲料や日用品のように、外れても在庫で吸収できるカテゴリから始め、日持ちしない生鮮と総菜は、成績を2か月見てから案を出します。
05工数削減シミュレーション
導入後 320件 × 6分 ÷ 60 = 32 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 10〜50店舗ほどを持つ食品スーパー・ドラッグストアで、毎週チラシを出し、特売品の店舗別の発注量をバイヤーが過去の特売の表と経験で決めている会社。POSの単品・店舗・日別の売上と、過去のチラシの掲載の記録(商品・売価・掲載面)が2年分以上残っている場合。特売の後の欠品と売れ残りの両方が毎週出ている場合。
- 店舗が数店で、店長が自店の特売の発注を決めている場合。チラシの掲載の記録が残っておらず、過去のどの日が特売だったかを売上から特定できない場合。特売品の多くが毎回初めて扱う商品で、過去の実績が無い場合。なお、発注量を決める判断と、どの商品をチラシに載せるかの判断は、この構成では代替できません。
07最小構成で試す方法
- 過去1年分の特売から、よく載せる品目を10個選ぶ
- 品目ごとに、特売の回の店舗別の販売数、値引き率、掲載面を表計算に並べる
- 時間帯別の販売数を見て、売り切れの疑いのある回に印を付ける
- 値引き率と販売数の関係を、売り切れの印の有無で分けてグラフにする
- バイヤーが実際に入れた発注量と、販売数の差(欠品・売れ残り)を回ごとに並べる
ここでは機械学習を使いません。 売り切れの回を見分けられるか、値引き率で販売数が動くかを、表計算で確かめます。
| 出てきた内容 | 判断 |
|---|---|
| 値引き率で販売数がはっきり動き、売り切れの回も見分けられた | モデルを作る段階に進む |
| 売り切れの回が多すぎて、実績の多くに印が付いた | 欠品の解消が先。 モデルは需要を学べない |
| 時間帯別の販売数が取れない | POSの書き出しを確かめる。取れなければ店舗に売り切れを記録してもらう |
2行目が出たときは、構成を進めないでください。 売り切れの回ばかりのデータからは、需要の大きさを学べません。まず発注量を少し多めにした回を何度か作り、売り切れない回の実績を集めます。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
| 欠品した店舗ほど見込みが下がる | 売り切れの回を学習から外す。 時間帯別の販売数で見分ける |
| 値引きを深くしたのに見込みが下がる | 値引き率に単調性の制約(1)を付ける |
| 店舗番号の大小を学ぶ | 店舗とカテゴリを Categorical 型で渡す |
| 上側の見込みが低すぎる | 実績が上側の見込み以下に収まった割合が8割前後かを見る |
| 気象庁のCSVの値をそのまま使う | 品質情報が正常値・準正常値以外は欠損として扱う |
| 期間の違うCSVをつないで比べる | 均質番号は取得ごとに振り直される。番号で比べない |
| 掲載の記録の税込み・税抜きが混ざる | 入力の欄を固定し、過去分を一度そろえる |
| 初めての品目に平均を当てる | 似た品目をバイヤーが指定するまで見込みを出さない |
| 予報の外れとモデルの外れが混ざる | 見込みに使った予報を、実際の天気とは別に残す |
| 発注システムに自動で入れる | 最初の半年は手で入れ、直した理由を残す |
| 掲載面の効き方が回ごとに変わる | チラシのデザインの変更を掲載の記録に残す |
| 近くの競合店の特売と重なる | 重なった回に印を付け、後から効き方を確かめる |
上の2行が、この構成の失敗のほとんどです。 1行目は需要を少なく見積もる失敗、2行目はデータの少ない品目で起きる不自然な見込みです。どちらも、モデルの種類を変えるより、データの扱いと制約で直ります。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: 品目・店舗別の販売数と売上、売価と値引き、在庫、チラシの掲載の計画です。個人を特定する情報は使いません。
- チラシの掲載の計画は、公開前の営業上の秘密です … 掲載の2週間前の品目と売価は、競合店に知られると対抗される情報です。一覧の置き場所と閲覧できる人を、商品部に絞ります
- POSのデータから会員の情報を外す … POSの書き出しに会員番号が含まれる場合は、取り込む前に外します。品目・店舗・日・時間帯の集計だけを使います
- 納入する卸との共有の範囲を決める … 発注量の案を卸に先に共有すると、仕入れの準備に役立つ一方、他社の特売の計画に使われないかを取り決めておきます
- 発注の判断はバイヤーが行う … 案を自動で発注に回さず、バイヤーが入れた量と理由を残します。欠品や売れ残りが出たときに、誰がどう判断したかを後から確かめられます
- 天気のデータの出典を残す … 気象庁のデータを使った場合は、取得した日と地点を記録しておきます
- 見込みの数字を店舗の評価に使わない … 見込みより売れなかった店舗を責める材料にすると、店舗が売り切れを報告しなくなり、前処理の3番で使う記録が集まらなくなります
誤りが起きた場合のリスクは、欠品による機会損失と、売れ残りによる値下げと廃棄です。 どちらも数字で見えるので、毎週の突き合わせで、どの品目でどちらに外れたかを数え続けることが、いちばんの守りになります。
10まず何から始めるか
1週目:掲載の記録の書き方をそろえる
チラシの掲載の記録の列(品目コード、売価、通常の売価、税込みか税抜きか、掲載面、期間、点数の制限)を決め、今週の分から全員が同じ書き方で入れます。 過去1年分は、よく載せる品目から順にそろえます。
2週目:売り切れを見分ける
POSから時間帯別の販売数を書き出し、第8章の手順で売り切れの疑いの回に印を付けます。あわせて、店舗に「目玉の品目が何時に売り切れたか」を記録してもらう手順を始めます。
3週目:10品目で値引き率と販売数を見る
よく載せる10品目について、値引き率と販売数の関係を、売り切れの印の有無で分けて見ます。バイヤーの発注量と欠品・売れ残りも並べます。
4週目:条件の近い過去の回を出す
Pythonで、品目×店舗ごとに条件の近い過去の回を探し、実績を一覧にしてバイヤーに渡します。この時点では見込みは出しません。
2か月目: 過去の天気をCSVで取り込み、分位点回帰で中央と上側の見込みを出して、バイヤーの発注量と並べて比べます。3か月目以降: 発注量の案を一覧に載せ、バイヤーが直した理由を数えます。直した理由の「その他」が減り、欠品と売れ残りの件数がバイヤーの発注だけのときより減っていくのを確かめられた時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
HistGradientBoostingRegressor の loss に quantile(ピンボール損失)があり、quantile に0から1の値を指定すること。monotonic_cst で特徴量ごとに単調増加(1)・制約なし(0)・単調減少(-1)を指定でき、特徴量名をキーにした辞書も渡せること。欠損値(NaN)をそのまま扱うこと。categorical_features の既定値が from_dtype であること(scikit-learn 1.9.1) | scikit-learn: HistGradientBoostingRegressor | 2026-10-13 |
mean_pinball_loss が分位点回帰のためのピンボール損失で、alpha の既定値が0.5であり、0.5のとき平均絶対誤差と同じになること | scikit-learn: mean_pinball_loss | 2026-10-13 |
| 過去の気象データ・ダウンロードで、地点・項目・期間を選んでCSVファイルとしてダウンロードできること。地点が全国の気象台やアメダス約1,500地点(観測を終えた約200地点を含む)であること。日別値などの集計期間を選べること | 気象庁: 過去の気象データ・ダウンロードの使い方 | 2026-10-13 |
| CSVの品質情報の値(8=正常値、5=準正常値、4=資料不足値、2=疑問値、1=欠測)と、「すべて数値で格納」を選ぶと品質情報が別の列に入ること。均質番号の違いは観測環境の変化を表し、番号の違う値同士を単純に比較できないこと。均質番号がCSVの取得ごとに振り直されること | 気象庁: ダウンロードファイル(CSVファイル)の形式 | 2026-10-13 |
発注量をどう決めるか、どの品目をチラシに載せるかは、商品部で決めてください。 本記事は公式ページで確認できた範囲だけを扱っています。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-1408)についてのご相談はこちらから。
