食品スーパーが惣菜・日配品の時間帯ごとの売れ方から、Python で見切り(値引き)の時刻と率の案を作り、売れ残りの廃棄と値引きの損を比べる
惣菜・日配品の15分ごとの売れ方と、値引きした時刻と率の記録から、値引きを入れたときの売れ方を見込みます。見切りの時刻と率の組み合わせごとに廃棄の損と値引きの損を試算し、翌月の見切りの表の案にします。
- 連携・自動化
- Python
- 対象業界
- 小売
- 対象部門
- 経営企画
- 対象業務
- 比較検討/集計・分析
- 主な課題
- データ分析に時間がかかる/判断に時間がかかる/属人化している
- AIで行う処理
- 予測
- 主な効果
- 判断支援/品質標準化/機会損失防止
- 導入難易度
- ★★★★★
- 実装レベル
- 本格構成
- 費用感
- 個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- 担当者が、店舗の品目群の前月の売上、値引きの額、廃棄の額を表計算に集める
- POS の記録から、値引きの1回目と2回目の時刻ごとの販売数を拾う
- 製造の記録と廃棄の記録から、品目群の売り切りの割合を出す
- 前月の表と、同じ規模の他の店舗の表を見比べる
- 時刻を早めるか遅らせるか、率を深くするか浅くするかを決め、理由を一行書く
- 翌月の表を店舗に配る
- 自動毎月1日、POS の15分ごとの販売と値引きの記録、製造の記録、廃棄の記録を前月まで書き出す
- 自動Python が、店舗 × 品目群 × 日 × 15分ごとに、販売数・その時点の残りの数・効いていた値引きの率をそろえる
- 自動売り切れた後の15分を外し、暦と天気の記録を足す
- 自動モデルが、値引きの率・時刻・残りの割合・曜日・天気から、15分ごとの販売数を見込む
- 自動見切りの時刻と率の組み合わせごとに、閉店までの売れ方をなぞって、値引きの損・廃棄の損・粗利を試算する
- 自動粗利が最も残る組み合わせと、いまの表の組み合わせを並べて、品目群ごとの案にする
- 人担当者が案を見て、店舗の事情と品目の扱いを確かめ、翌月の表を決める
- 人店舗の責任者に表を配り、変えた理由を伝える
- 自動翌月が過ぎたら、試算と実際の値引きの額・廃棄の額を突き合わせて記録する
各工程の詳しい説明を読む
- 担当者が、店舗の品目群の前月の売上、値引きの額、廃棄の額を表計算に集める
- POS の記録から、値引きの1回目と2回目の時刻ごとの販売数を拾う
- 製造の記録と廃棄の記録から、品目群の売り切りの割合を出す
- 前月の表と、同じ規模の他の店舗の表を見比べる
- 時刻を早めるか遅らせるか、率を深くするか浅くするかを決め、理由を一行書く
- 翌月の表を店舗に配る
(a)値引きと廃棄の損を同じ物差しで見ていない。 値引きの額は売価で、廃棄の額は原価で集計されています。2つを足して比べると、売価と原価が混ざった数字になります。 「値引きを1割増やして廃棄を2割減らした」が得だったのかが、分かりません。
(b)値引きしなかったらどうだったかが分からない。 17時に2割引にした弁当が17時台に売れたのは、値引きのおかげか、夕方の客が増えたからかが、記録だけでは分かりません。値引きの効き方の見当は、担当者ごとに違います。
(c)責任者の調整が見えない。 店舗の責任者は、売れ残りそうな日に表より早く値引きしています。表の効き目を見ているつもりで、責任者の調整の効き目を見ていることがあります。 早めた日と表どおりの日を分けて集計していないからです。
(d)見比べるだけで時間がかかる。 180件の1件ごとに、POS と製造と廃棄の記録を開き、時刻ごとに拾い直します。毎月同じ集計を一から作っていて、決める時間がほとんど残りません。
- 【自動】 毎月1日、POS の15分ごとの販売と値引きの記録、製造の記録、廃棄の記録を前月まで書き出す
- 【自動】 Python が、店舗 × 品目群 × 日 × 15分ごとに、販売数・その時点の残りの数・効いていた値引きの率をそろえる
- 【自動】 売り切れた後の15分を外し、暦と天気の記録を足す
- 【自動】 モデルが、値引きの率・時刻・残りの割合・曜日・天気から、15分ごとの販売数を見込む
- 【自動】 見切りの時刻と率の組み合わせごとに、閉店までの売れ方をなぞって、値引きの損・廃棄の損・粗利を試算する
- 【自動】 粗利が最も残る組み合わせと、いまの表の組み合わせを並べて、品目群ごとの案にする
- 【人】 担当者が案を見て、店舗の事情と品目の扱いを確かめ、翌月の表を決める
- 【人】 店舗の責任者に表を配り、変えた理由を伝える
- 【自動】 翌月が過ぎたら、試算と実際の値引きの額・廃棄の額を突き合わせて記録する
7番目が、この設計の分かれ目です。 案は出しますが、表を決めるのは担当者です。 閉店の間際に来る常連の客の多い店舗、近くに競合の店がある店舗、値引きしない方針の品目は、記録だけでは分かりません。
5番目で「売れ方をなぞる」のが、損を比べる要です。 1回目の値引きで売れた分だけ、2回目の時点の残りが減ります。見切りの組み合わせの損は、時刻の順に残りの数を減らしていかないと計算できません。
02今回想定するシステム構成
POS(15分ごとの販売・値引きのシールの率)/製造の記録(製造数・時刻)/廃棄の記録 │ 毎月1日に前月までを書き出し ▼【トリガー】定時実行 Python(pandas) ├──▶ 店舗 × 品目群 × 日 × 15分の、販売数・残りの数・値引きの率 ├──▶ 売り切れた後の15分を外す ▼ scikit-learn(HistGradientBoostingRegressor:loss="poisson"、値引きの率に単調の制約) │ 15分ごとの販売数の見込み ▼ Python ── 見切りの組み合わせごとに閉店までをなぞる/値引きの損・廃棄の損・粗利 ▼ 品目群ごとの見切りの表の案(いまの表と並べて) ▼ 【担当者が確かめて翌月の表を決め、店舗へ配る】
| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 実行環境 | Python(pandas・scikit-learn の HistGradientBoostingRegressor) | R、BigQuery ML、LightGBM |
| データの取得元 | POS・製造の記録・廃棄の記録の書き出し | POS のAPI(提供されている場合) |
| 案の出力先 | 共有フォルダの店舗ごとの表 | 社内のダッシュボード |
| 定時実行 | 社内のジョブ管理の仕組み | OSのタスクスケジューラ |
生成AIは使いません。 この構成で行うのは、記録から販売数を見込み、組み合わせごとに損を計算することです。店舗ごとの売上と原価を外部の生成AIに渡す場面を、最初から作りません。
POS の売価の設定には書き込みません。 見切りの表は、いまと同じく担当者が店舗に配り、値引きのシールは店舗の責任者が貼ります。
モデルに HistGradientBoostingRegressor を選ぶのは、件数の見込みに向いた損失と、向きの制約の両方を使えるからです。 公式の説明では、loss="poisson" は0以上の値を求め、内部で対数のつなぎ方を使うとされています。15分の販売数は0が多い件数で、二乗の誤差より合います。monotonic_cst で、列ごとに増える向き(1)・減る向き(-1)の制約を付けられるともされています。
03どうやって実装するのか
処理の起点を決める
毎月1日の定時実行を起点にします。 前月までの記録で学ばせ直し、180件の案をまとめて作ります。案は月の5営業日目までに担当者の手元にそろえ、20日までに翌月の表を店舗に配ります。 表を変えるときは、責任者が値引きのシールの準備と、パートの従業員への伝え方を考える時間が要るからです。
学ばせる記録は直近18か月です。 1年より長くとるのは、夏の弁当と冬の煮物のように、品目群の売れ方の季節の違いを含めるためです。前のモデルより当たっているかを確かめてから入れ替えます。
新しい店舗を開いたときや、売場の配置を大きく変えたときは、その店舗の記録が3か月たまるまで案を出しません。 案の代わりに、同じ規模の店舗の表をそのまま使うと一覧に書きます。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| 販売の記録 | 店舗、商品のコード、品目群、販売の時刻(15分にまとめる)、販売数、売価、値引きの率(シールのバーコード) | POS |
| 製造の記録 | 店舗、商品のコード、製造数、製造の時刻(出した時刻) | 惣菜の製造の記録 |
| 廃棄の記録 | 店舗、商品のコード、廃棄数、廃棄の日 | 廃棄の記録 |
| 原価 | 商品のコードごとの原価(材料と包材) | 商品のマスタ |
| 見切りの表の履歴 | 店舗 × 品目群の、月ごとの1回目と2回目の時刻と率 | 本部の表計算 |
| 暦 | 曜日、祝日、連休、給料日、月末 | 担当者が作る表 |
| 天気の記録 | 1時間ごとの降水の有無と量、気温 | 契約している気象情報の提供元 |
| 営業時間 | 店舗ごとの閉店の時刻 | 店舗の台帳 |
質を決めるのは、値引きのシールのバーコードです。 シールに率が入っていれば、どの商品がいつ何割引で売れたかが POS に残ります。手書きの値引きや、レジで手打ちする値引きは、率が残らないことがあります。書き始める前に、各店の値引きの何割がシールで記録されているかを数えてください。
原価は、商品のコードごとに持ちます。 廃棄の損は原価で、値引きの損は売価との差で出るので、同じ物差しにそろえるには、商品ごとの原価が要ります。 原価が無い商品は、品目群の平均の原価率で代えます。
データの取得方法を決める
POS、製造の記録、廃棄の記録から、前月までを書き出します。書き出しの列の名前と数は、毎月の処理の最初に決めたとおりかを照らし、違えばそこで止めます。
| 取るもの | どこから | 何に使うか |
|---|---|---|
| 15分ごとの販売数と値引きの率 | POS | 学ばせる答えと、効いていた率 |
| 製造数と出した時刻 | 製造の記録 | その時点の残りの数 |
| 廃棄数 | 廃棄の記録 | 閉店時の残りの数の確かめ |
| 原価 | 商品のマスタ | 廃棄の損と値引きの損 |
| 見切りの表の履歴 | 本部の表計算 | いまの表の組み合わせ |
その時点の残りの数は、製造数から販売数を引いて作ります。 製造は1日に何回かに分かれるので、出した時刻の15分から製造数を足し、販売のたびに引きます。 閉店の時刻の残りの数と、廃棄の記録の廃棄数を照らし、大きく違う日は記録の欠けとして学ばせる記録から外します。 違いは、製造の記録の漏れか、従業員の買い取りか、廃棄の記録の漏れです。
AIへ渡す前に整形する
- 15分にまとめる … 店舗 × 品目群 × 日 × 15分ごとに、販売数を合計します。品目群の中の商品は、売価が近いものだけを束ねます
- 残りの数と残りの割合を作る … 15分の始まりの時点の残りの数と、その日の製造数に対する割合を作ります
- 効いていた値引きの率を作る … その15分に売れた商品のシールの率を、販売数で重みを付けて平均します。値引きしていない15分は0です
- 売り切れた後を外す … 残りの数が0になった15分より後は、学ばせる記録から外します
- 閉店までの時間を作る … 閉店の時刻までの分を列にします。店舗ごとに閉店の時刻が違うので、時刻そのものより閉店までの時間のほうが効きます
- 記録の欠けた日を外す … 閉店時の残りと廃棄数が大きく違う日、POS が止まった日を外します
学ばせる記録の1行は、次のような形にします。1行が「ある店舗の、ある品目群の、ある日の15分」です。
{
"store_id": "S07",
"item_group": "bento",
"date": "2026-09-18",
"slot": "17:15",
"weekday": "fri",
"holiday_flag": "none",
"rain_class": "light",
"temp_c": 24.5,
"minutes_to_close": 225,
"produced_today": 120,
"remaining_at_start": 46,
"remaining_ratio": 0.38,
"discount_rate": 0.2,
"minutes_since_discount": 15,
"sold": 9
}
sold は学ばせるときの答えです。 remaining_ratio が、この構成でいちばん大事な列です。責任者が「残りが多いから早めに値引きした」日を、残りの割合で見分けられるようにするためです。この列が無いと、値引きの率の列が「残りが多い日」の印として学ばれます。
4番目を省くと、夕方の売れ方を低く見ます。 人気の弁当ほど早く売り切れ、売り切れた後の15分は0が並びます。それを学ばせると、値引きしなくても売れるはずの時間帯に、売れないと見込みます。
AIに処理させる
させるのは、店舗 × 品目群 × 15分ごとの販売数を、値引きの率と残りの割合から見込むことだけです。 見切りの組み合わせのなぞり方、損の計算、案の選び方は、見込みを受け取った後の Python の側で決まった規則で行います。
| 見るもの | 扱い方 | 判断できないときの扱い |
|---|---|---|
| 店舗・品目群 | カテゴリの型 | マスタに無ければ見込まない |
| 値引きの率 | 数値の列(0〜0.5)。増える向きの制約 | シールで記録されていなければ欠けた値 |
| 閉店までの時間 | 数値の列 | 台帳に無ければ見込まない |
| 残りの割合 | 数値の列 | 製造の記録が無ければ見込まない |
| 曜日・祝日・天気 | 暦と天気の記録から | 天気が取れなければ欠けた値 |
値引きの率の列に monotonic_cst で 1 を付けます。 他の列が同じなら、率が深いほど売れ方が上がる向きです。公式の説明では、カテゴリの列には単調の制約を付けられないとされているので、値引きの率は数値の列のまま渡します。 また、制約は効き方を限られた形でしか縛らないとされています。率と時刻の組み合わせのすべてで向きがそろうことまでは保証されないので、試算の後で確かめます(例外処理の表の5行目)。
見切りの組み合わせのなぞり方は、決まった手順で行います。
組み合わせ = 1回目の時刻(16:00〜19:00、30分おき)× 1回目の率(1割・2割・3割)
× 2回目の時刻(1回目の2時間後〜閉店の1時間前)× 2回目の率(3割・半額)
各組み合わせについて、ある日の製造数から始めて15分ずつ:
その15分の率 = 組み合わせで決まる率
見込みの販売数 = min(モデルの見込み, 残りの数)
残りの数 ← 残りの数 − 見込みの販売数
閉店時の残りの数 = 廃棄の見込み
値引きの損 = Σ(見込みの販売数 × 売価 × 率)
廃棄の損 = 閉店時の残りの数 × 原価
粗利 = Σ(見込みの販売数 × 売価 ×(1 − 率))− 製造数 × 原価
これを、前月の同じ曜日の区分の日ごとに行い、平均します。 平日・土曜・日祝の区分ごとに、粗利の平均が最も大きい組み合わせを案にします。同じ区分でも、雨の日と晴れの日で案が違えば、両方を出します。
| させないこと | 理由 |
|---|---|
| 製造数を決める | 製造の計画は別の判断。この構成は作った後の売り方だけを見る |
| 売価を決める | 値引きの前の売価は商品の担当が決める |
| その日の値引きの指示 | 当日の判断は店舗の責任者。表は下敷き |
| 値引きしない品目の判断 | 方針で値引きしない品目は、担当者が案から外す |
1行目が大事です。 損の計算を見ると、製造数を減らせば廃棄の損も値引きの損も減る、という結論にすぐ行きます。しかし製造数を減らせば、夕方に棚が空く時間が増えます。 棚が空いていた時間の客の取りこぼしは記録に出ないので、この構成では比べられません。製造数は別に決めてください。
当たり方は、学ばせる期間の後の期間で見ます。 TimeSeriesSplit で分けます。公式の説明では、時刻の順に並んだ記録で、前の期間で学ばせて後の期間で確かめる分け方とされています。品目群ごとの1日の販売数の合計と、閉店時の残りの数の見込みの誤差を毎月の一覧に出します。
指示内容を固定する
この構成は生成AIを使わないため、プロンプトはありません。 代わりに、学ばせ方・組み合わせの範囲・損の計算・案の選び方を、ひとつの設定ファイルにまとめます。
【見込む先】
sold: 店舗 × 品目群 × 日 × 15分の販売数(売り切れた後の15分は除く)
学習期間: 前月までの18か月(全12店舗・15品目群をまとめて1つのモデル)
検証: TimeSeriesSplit(日付の単位で4つに分ける)
【モデル】
HistGradientBoostingRegressor(loss="poisson", categorical_features="from_dtype")
monotonic_cst: {"discount_rate": 1}
入れ替えの条件: 検証の期間で、閉店時の残りの数の見込みの誤差が前のモデルより小さいこと
【組み合わせの範囲】
1回目: 16:00〜19:00(30分おき)× 0.1 / 0.2 / 0.3
2回目: 1回目の2時間後〜閉店の1時間前(30分おき)× 0.3 / 0.5
値引きしない品目: 担当者が一覧で指定(案を出さない)
【損の計算】
値引きの損: 売価 × 率 × 販売数
廃棄の損: 原価 × 閉店時の残り(+廃棄の処理の単価 × 重さ。設定する場合)
比べる物差し: 粗利(売上 − 製造数 × 原価)
【案の選び方】
曜日の区分(平日・土曜・日祝)ごとに、前月の日ごとの粗利の平均が最大の組み合わせ
いまの表との粗利の差が、1日あたり品目群の売上の1%未満なら「据え置き」とする
雨の日と晴れの日で組み合わせが違えば、両方を出す
【一覧に載せる内容】
- いまの表と案の、1日あたりの値引きの損・廃棄の損・粗利の見込み
- 案の組み合わせと、2番目・3番目に粗利の大きい組み合わせ
- 店舗の責任者が表より早めた日の割合(前月)
「差が小さければ据え置き」を入れるのが大事です。 粗利の差がわずかな案を毎月採ると、表が毎月少しずつ変わり、店舗の責任者とパートの従業員が覚えられません。 表が変わるのは、はっきり得になるときだけにします。
「2番目・3番目」も出すのは、担当者が選べるようにするためです。 1番目の案が「16時に3割」のような、店舗の客層から見て早すぎる値引きのことがあります。粗利がほとんど同じで、より遅い組み合わせがあれば、そちらを選べます。
出力形式を固定する
案は店舗ごとの表で出し、同じ内容を JSON でも残します。 表は担当者と店舗の責任者が読むため、JSON は翌月以降の突き合わせのためです。
{
"run_at": "2026-10-01T06:00:00+09:00",
"store_id": "S07",
"item_group": "bento",
"target_month": "2026-11",
"day_type": "weekday",
"weather": "any | rain | dry",
"current_rule": { "first": ["17:00", 0.2], "second": ["19:30", 0.5] },
"proposed_rule": { "first": ["17:30", 0.2], "second": ["19:30", 0.5] },
"alternatives": [ { "first": ["", 0.0], "second": ["", 0.0], "gross_profit": 0 } ],
"per_day_estimate": {
"current": { "discount_loss": 0, "waste_loss": 0, "gross_profit": 0 },
"proposed": { "discount_loss": 0, "waste_loss": 0, "gross_profit": 0 }
},
"early_markdown_share": 0.0,
"status": "propose | keep | insufficient_data",
"model_version": "",
"decided_rule": null,
"decided_by": "",
"reason": ""
}
1つ目の理由は、いまの表と案の損を同じ形で並べられることです。 値引きの損と廃棄の損と粗利が並べば、「値引きの損が増えて廃棄の損がそれ以上に減る」という案の中身が読めます。
2つ目は、early_markdown_share で責任者の調整が見えることです。 表より早めた日が多い店舗は、表がその店舗の売れ方に合っていないおそれがあります。案の確かめで、まず見る列です。
3つ目は、decided_rule と reason で、案と決定の違いが残ることです。 翌月が過ぎた後、案どおりにしていたらどうだったか、決めた表でどうだったかを比べられます。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| POS | データの書き出し(読み取りのみ) | 15分ごとの販売と値引きの率 |
| 惣菜の製造の記録 | 読み取りのみ | 製造数と出した時刻 |
| 廃棄の記録 | 読み取りのみ | 廃棄数 |
| 商品のマスタ | 読み取りのみ | 原価、品目群の区分 |
| 気象情報の提供元 | 契約に基づく取得 | 1時間ごとの天気の記録 |
| 共有フォルダ | 案の書き出し | 店舗ごとの表 |
POS の売価の設定へは書き込みません。 値引きを POS で自動にすると、シールの率とレジの率が食い違う時間ができます。 客にとっては、貼ってある値引きと違う金額になります。
店舗へ配る表は、担当者が決めた後に作ります。 案をそのまま店舗に送る経路は作りません。決まっていない案が売場に出ると、店舗の責任者が2つの表を見比べることになります。
人が確認する
early_markdown_shareを見る … 責任者が表より早めた日が多い店舗は、表のほうを見直す理由があるかを考えます- 案の時刻が店舗の客層に合うかを見る … 閉店の間際の客が多い店舗、近くに競合がある店舗は、案と2番目・3番目を見比べます
- 値引きしない品目を外す … 方針で値引きしない品目(季節の目玉など)は、案から外します
- 決めた表と理由を書く …
decided_ruleとreasonを埋め、店舗に配る表を作ります
1番目を省かないでください。 責任者が毎日早めている店舗で、表を記録どおりに直すと、責任者の調整の分だけ値引きが二重に早まることがあります。表を変えたら、責任者に「表どおりで様子を見てください」と伝えます。
目標は、180件をならして1件10分です。 「据え置き」の品目群は流し見て終わり、表を変える品目群は2番目・3番目の案と店舗の事情を見るので時間がかかります。その配分でならすと10分です。
例外に対処する
| 起きること | 対応 |
|---|---|
| 書き出しが届かない・列が違う | 処理を止め、案を作らずに担当に知らせる |
| 値引きのシールで記録された割合が低い店舗 | 案を出さず「記録が足りない」と出す。シールの運用を先にそろえる |
| 閉店時の残りと廃棄数が大きく違う日が多い | 製造と廃棄の記録の付け方を店舗に確かめる |
| 新しい店舗、売場を大きく変えた店舗 | 3か月たまるまで案を出さず、同じ規模の店舗の表を使うと書く |
| 試算で、率を深くしたのに販売数が減る組み合わせがある | 制約が効き切っていない。その品目群の案を出さず、担当者が確かめる |
| 新しい品目群・新商品 | 品目群に当てはめ、売価の近い商品の傾向で見込むと書く |
| 学び直したモデルが前より当たらない | 入れ替えず、前のモデルを使い続けて知らせる |
| 天気の記録が取れない | 天気の列を欠けた値にして見込み、案に「天気なし」と出す |
2行目で案を出さないのは、誤りの向きを決めるためです。 シールで記録されていない値引きは、POS では値引きしていない販売に見えます。その記録で学ばせると、値引きしなくても夕方によく売れる、と見込みます。
記録を残す
- 毎月の書き出しと、15分ごとの販売数・残りの数・値引きの率
- 見込みと、使ったモデルの版
- 組み合わせごとの試算と、案と2番目・3番目
- 担当者が決めた表と理由
- 翌月の実際の値引きの額・廃棄の額・粗利と、責任者が早めた日の割合
- 設定ファイルの変更の履歴(組み合わせの範囲、据え置きの線)
4つ目と5つ目を並べて残すのが、この構成の振り返りの土台です。 数か月たまると、案どおりにした品目群と、担当者が変えた品目群で、実際の粗利がどうだったかが見えます。
04実装レベルの3段階
最小構成では、組み合わせを試せません。 記録にある組み合わせしか比べられず、試していない時刻と率の損は分かりません。 確かめるための段階です。 半自動化で、1件30分が18分程度になります。 集計はそろいますが、時刻と率をどう変えるかの見当が担当者に残ります。本格構成で10分になり、この段階が本記事の想定です。 差が大きいのは、組み合わせごとの損を頭の中で比べていた時間が無くなるからです。 段階を飛ばさないでください。 半自動化の集計を2か月見ると、シールの記録が足りない店舗と、製造と廃棄の記録が合わない店舗が先に分かります。
05工数削減シミュレーション
導入後 180件 × 10分 ÷ 60 = 30 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 惣菜を店内で製造し、弁当・揚げ物・寿司・サラダや、豆腐・パン・生菓子などの日配品を毎日見切りで売り切っている、10店舗以上の食品スーパー。見切りの時刻と率を店舗の惣菜の責任者の経験で決めていて、店舗ごとに廃棄と値引きの額の差が大きい場合。POS で値引きのシールを読み取って、値引きした時刻と率が記録に残っている場合。本部が毎月、見切りの決まりを見直している場合。
- 値引きのシールに率のバーコードが無く、POS で値引きした商品と率が分からない店舗。店舗が数店で、責任者が毎日の売場を見て決めるほうが早い場合。惣菜を外から仕入れて、製造数の記録が無い場合。なお、売価の設定、製造数の計画、消費期限の表示、どの商品を値引きの対象にしないかの判断は、この構成では代替できません。
07最小構成で試す方法
- 1つの店舗の弁当の品目群について、POS から前月の15分ごとの販売数と値引きの率を書き出す
- 製造の記録から、日ごとの製造数を写す
- 表計算で、日ごとに「値引きの1回目の時刻の残りの割合」と「閉店時の廃棄数」を並べる
- 責任者が表どおりに値引きした日と、早めた日を分ける
- 2つの日の組で、値引きの額(売価との差)と廃棄の額(原価)を足した損を比べる
1か月分は必ずやってください。 モデルを作る前に、「値引きの損と廃棄の損を同じ物差しにすると、表どおりの日と早めた日でどちらが得か」を確かめます。
| 出てきた内容 | 判断 |
|---|---|
| 早めた日のほうが損が小さい | モデルに進む。 表の時刻に見直す余地がある |
| どちらもほとんど同じ | 時刻より率の見直しの余地を見る。組み合わせの試算に進む |
| 値引きの率が記録に残っていない日が多い | シールの運用が先。 率のバーコードの付いたシールにそろえる |
3行目が出ることは珍しくありません。 失敗ではなく、見切りの表の効き目を確かめる記録が無かったことが分かったということです。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
| 値引きした日ほど売れていないと学ぶ | 残りの割合を列に入れる。 値引きの率に増える向きの制約を付ける |
| 売り切れた後の0を学んで、夕方の売れ方を低く見る | 売り切れた後の15分を外す |
| 値引きの損と廃棄の損を別の物差しで足す | 売価との差と原価にそろえ、粗利で比べる |
| シールで記録されない値引きが混ざる | 記録の割合が低い店舗は案を出さない |
| 製造の記録の漏れで残りの数がずれる | 閉店時の残りと廃棄数を照らし、合わない日を外す |
| 制約を付けても、率を深くして販売数が減る組み合わせが出る | 試算の後で確かめ、その品目群の案を出さない |
| 案を毎月採って表が毎月変わる | 粗利の差が小さければ据え置きにする |
| 損の計算から製造数を減らす結論に行く | 製造数は別に決める。棚が空く時間は比べられない |
| 表を変えた後も責任者が早め続ける | 表を変えたら「表どおりで様子を見る」と伝える |
| 案がそのまま売場に出る | 担当者が決めた表だけを配る |
上の3行が、この構成の失敗のほとんどです。 どれも、記録の売れ方が、値引きで動く売れ方とは限らないという同じところから出ています。
下の2行は、店舗の運用が始まってから効いてきます。 案と表と責任者の判断が重なると、どれが効いたのかが分からなくなります。 表を変えた月は、責任者の調整を控えてもらうよう伝えてください。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: 店舗ごとの販売と値引きの記録、製造数、廃棄数、商品ごとの原価です。POS の記録には、会員カードの番号が入っていることがあります。
- 会員カードの番号を書き出さない … 見込みに要るのは15分ごとの販売数だけです。誰が値引きの商品を買ったかは要りません
- 原価を見られる人を限る … 商品ごとの原価は、取引先との条件が分かる情報です。案の表は本部の担当と店舗の店長だけが開ける場所に置きます
- 値引きの表示を正しく行う … 消費者庁の価格表示の考え方では、生鮮食料品等について売れ残りを回避するために一定の営業時間経過後に価格の引下げを行う場合に、当初の表示価格を比較対照価格とする二重価格表示は、通常は不当表示に該当するおそれはないとされています。シールに書く「当初の価格」は、その日にその商品を売っていた価格にします
- 値引きは人が指示する … この構成は表の案を出すだけです。当日の値引きの指示は、いまと同じく店舗の責任者が出します
- 消費期限の扱いを変えない … 見切りの表は、消費期限の内側で売り切るためのものです。値引きのシールで期限の表示を隠さない貼り方を、店舗の決まりにします
- 生成AIに記録を渡さない … この構成は生成AIを使いません。理由の文を作るために表をチャットのAIに貼り付けることも、運用の決まりで禁じます
誤りが起きた場合のリスクは、値引きの効き目を取り違えて損の大きい表を配ることと、値引きの表示が実際と食い違うことの2つです。 前者は粗利と廃棄にひびき、後者は客の信頼にひびきます。だから案はいまの表と並べて損を見せ、POS の売価には書き込みません。
10まず何から始めるか
1週目:値引きのシールの記録を数える
各店の値引きのうち、率のバーコードの付いたシールで記録されている割合を数えます。ここが最初の分かれ目です。 あわせて、閉店時の残りの数と廃棄数が合うかを、2〜3店舗で1週間分確かめます。
2週目:1店舗の弁当で試す
1つの店舗の弁当について、表どおりの日と早めた日の損を、売価との差と原価にそろえて比べます。同じ物差しにすると、どちらが得かが見えるかを確かめます。
3週目:品目群と原価をそろえる
15の品目群に商品を当てはめ、商品ごとの原価を商品のマスタから引けるようにします。組み合わせの範囲と、据え置きの線を設定ファイルに書きます。
4週目:15分ごとの集計を作る
Python で、全店舗・全品目群の15分ごとの販売数・残りの数・値引きの率を作るところまで作ります。この時点ではモデルを作らず、1日の販売数の合計が POS の日報と合うかを確かめます。
2か月目: 販売数のモデルを学ばせ、いまの表の損の試算が実際の値引きの額・廃棄の額と合うかを確かめます。3か月目以降: 組み合わせのなぞりと案を足し、担当者は従来どおり決めながら案と並べます。案どおりにした品目群と変えた品目群の粗利を3か月分比べ、据え置きの線を見直した時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
HistGradientBoostingRegressor の loss に poisson があり、0以上の値を求め、内部で対数のつなぎ方を使うこと。monotonic_cst で列ごとに増える向き(1)・減る向き(-1)・制約なし(0)を付けられ、列の名前の辞書でも指定できること(ページは scikit-learn 1.9.1) | scikit-learn: HistGradientBoostingRegressor | 2026-10-15 |
| 単調の制約は効き方を限られた形でしか縛らず、他の列の値が違う組み合わせまでの向きは保証しないこと。カテゴリの列には単調の制約を付けられないこと | scikit-learn: Ensembles(Histogram-Based Gradient Boosting の Monotonic Constraints) | 2026-10-15 |
| TimeSeriesSplit が、前の期間で学ばせて後の期間で確かめる分け方で、通常の交差検証では未来の記録で学んで過去で確かめてしまうこと | scikit-learn: TimeSeriesSplit | 2026-10-15 |
| 「不当な価格表示についての景品表示法上の考え方」(平成28年4月1日 消費者庁改定)で、特定の商品について一定の営業時間に限り価格の引下げを行ったり、生鮮食料品等について売れ残りを回避するために一定の営業時間経過後に価格の引下げを行ったりする場合に、当初の表示価格を比較対照価格とする二重価格表示は、通常は不当表示に該当するおそれはないとされること(PDF の原文で確認) | 消費者庁: 不当な価格表示についての景品表示法上の考え方(PDF) | 2026-10-15 |
売価、製造数、値引きの対象にしない品目、値引きの表示のしかたは、自社の商品と店舗運営の担当が決めてください。 本記事は上記の公式情報で確認できた範囲だけを扱っています。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-1668)についてのご相談はこちらから。
