ホテルの予約ごとに当日の取消と不泊のおそれを見込み、売り止めの判断と確認の連絡の優先順を出す
到着が近い予約の1件ごとに、当日の取消か不泊になって部屋が空くおそれを確率で出します。日別・部屋タイプ別に合計し、売り止めの判断材料と、確認の連絡を入れる予約の順番にします。
- 生成AI
- ChatGPT/Claude/Gemini
- 連携・自動化
- Python
- 対象業界
- その他/宿泊/飲食
- 対象部門
- カスタマーサポート/営業
- 対象業務
- 比較検討/集計・分析
- 主な課題
- データ分析に時間がかかる/判断に時間がかかる/属人化している
- AIで行う処理
- 予測
- 主な効果
- 判断支援/工数削減/機会損失防止
- 導入難易度
- ★★★★☆
- 実装レベル
- 本格構成
- 費用感
- RAG・個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- 予約担当が、翌日到着の予約の一覧を予約管理システムから書き出す
- 事前決済の無い予約、到着時刻の入力が無い予約、直前に入った予約に印を付ける
- 印を付けた予約を1件ずつ開き、予約の経路、予約からの日数、変更の回数、同じ人の過去の泊歴を見る
- 「来ないかもしれない」と思った予約を表計算のシートに書き出す
- 書き出した予約の数と残室を見比べて、残りの部屋を売り止めるか、何室まで売るかを支配人と相談する
- 確認が要ると判断した予約に、フロントの予約係が電話かメールで到着時刻を確かめる
- 翌日、来なかった予約を記録し、取消料の請求の手続きに回す
- 自動毎日15時に、翌日と翌々日に到着する予約を予約管理システムから書き出す
- 自動同じ人の過去の予約を会員番号とメールアドレスで結び付け、過去の取消と不泊の回数を数える
- 自動予約ごとに特徴量(経路、事前決済、予約からの日数、変更の回数、到着時刻の入力など)を作る
- 自動学習済みのモデルが、予約ごとに当日来ないおそれを確率で出す
- 自動確率を日別・館別・部屋タイプ別に足し合わせ、来ない見込みの室数と幅を出す
- 自動残室と見込みを並べ、支配人が決めた販売の上限の範囲で、売り止めの判断材料の表を作る
- 自動おそれの高い順に確認の連絡の一覧を作り、Claude API が到着時刻を確かめる連絡文の下書きを作る
- 人予約担当が判断材料の表を見て、売り止めるか、上限の範囲で販売を続けるかを決める
- 人フロントの予約係が、一覧の上から連絡し、結果(到着時刻の確認、取消の申し出、不通)を記録する
- 自動翌日、実際に来たかどうかを予約管理システムから取り込み、予測と結果を並べて残す
- 自動月1回、結果を足してモデルを学び直し、確率の較正をやり直す
各工程の詳しい説明を読む
- 予約担当が、翌日到着の予約の一覧を予約管理システムから書き出す
- 事前決済の無い予約、到着時刻の入力が無い予約、直前に入った予約に印を付ける
- 印を付けた予約を1件ずつ開き、予約の経路、予約からの日数、変更の回数、同じ人の過去の泊歴を見る
- 「来ないかもしれない」と思った予約を表計算のシートに書き出す
- 書き出した予約の数と残室を見比べて、残りの部屋を売り止めるか、何室まで売るかを支配人と相談する
- 確認が要ると判断した予約に、フロントの予約係が電話かメールで到着時刻を確かめる
- 翌日、来なかった予約を記録し、取消料の請求の手続きに回す
(a)判断の根拠が人によって違う。 3番目で何を重く見るかは、担当の経験で決まっています。ある担当が「来ない」とした予約を、別の担当は「来る」と見ます。 経験の長い担当がいる館といない館で、売り止めのタイミングがずれます。
(b)過去の泊歴を引くのに時間がかかる。 同じ人の過去の予約を探すには、氏名や電話番号で検索し直す必要があります。表記の違う同じ人が何件も出てきて、1件ごとに目で見分けます。 4分のうち、ここがいちばん重いところです。
(c)売り止めが早すぎるか遅すぎるかのどちらかに寄る。 来ない予約を多く見込めば、当日に満室で泊められない客を出すおそれがあり、少なく見込めば空室のまま夜を迎えます。どちらの失敗も嫌うので、担当は安全側に早めに売り止め、結果として空室が出ます。 その空室は、どの帳票にも失敗として残りません。
(d)確認の連絡が全件に届かない。 印を付けた予約すべてに電話をかける時間は無く、かける順番は担当の思いつきで決まります。 連絡がつけば来るかどうかが分かるのに、本当に確かめたい予約が後回しになることがあります。
- 【自動】 毎日15時に、翌日と翌々日に到着する予約を予約管理システムから書き出す
- 【自動】 同じ人の過去の予約を会員番号とメールアドレスで結び付け、過去の取消と不泊の回数を数える
- 【自動】 予約ごとに特徴量(経路、事前決済、予約からの日数、変更の回数、到着時刻の入力など)を作る
- 【自動】 学習済みのモデルが、予約ごとに当日来ないおそれを確率で出す
- 【自動】 確率を日別・館別・部屋タイプ別に足し合わせ、来ない見込みの室数と幅を出す
- 【自動】 残室と見込みを並べ、支配人が決めた販売の上限の範囲で、売り止めの判断材料の表を作る
- 【自動】 おそれの高い順に確認の連絡の一覧を作り、Claude API が到着時刻を確かめる連絡文の下書きを作る
- 【人】 予約担当が判断材料の表を見て、売り止めるか、上限の範囲で販売を続けるかを決める
- 【人】 フロントの予約係が、一覧の上から連絡し、結果(到着時刻の確認、取消の申し出、不通)を記録する
- 【自動】 翌日、実際に来たかどうかを予約管理システムから取り込み、予測と結果を並べて残す
- 【自動】 月1回、結果を足してモデルを学び直し、確率の較正をやり直す
8番目が、この設計の分かれ目です。売り止めるかどうかを決めるのは人です。 モデルが出すのは「来ない見込みが何室か」で、何室まで販売を続けるかは、その日の団体の到着、近隣ホテルへの振替の手当て、支配人の方針で変わります。数字だけで決めてよい判断ではありません。
02今回想定するシステム構成
予約管理システム(3館・全経路の予約)
│ 予約・変更・取消・チェックインの記録
▼【トリガー】毎日15時の定時実行
Python(pandas で予約の書き出しと名寄せ・特徴量の作成)
│ 経路/事前決済/予約からの日数/変更の回数
│ 到着時刻の入力/泊数/人数/同じ人の過去の取消・不泊の回数
▼
Python(scikit-learn の HistGradientBoostingClassifier
+ CalibratedClassifierCV で確率を較正)
│ 予約ごとの来ないおそれ(0〜1)
▼
日別・館別・部屋タイプ別の合計 ── 来ない見込みの室数と幅
│
├──▶ 売り止めの判断材料の表(残室・見込み・支配人の上限)
│
├──▶ 確認の連絡の一覧(おそれの高い順)
│ └──▶ Claude API ── 到着時刻を確かめる連絡文の下書き
▼
【人が売り止めを決め、連絡して結果を記録する】
▼
翌日の実績の取り込み ── 予測と結果の記録 ── 月1回の学び直し| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 実行環境 | Python(pandas・scikit-learn の HistGradientBoostingClassifier と CalibratedClassifierCV) | R、BigQuery ML |
| 生成AI | Claude API(確認の連絡文の下書き) | OpenAI API、Gemini API |
| データの取得元 | 予約管理システムの書き出し | 予約管理システムのAPI(提供がある場合) |
| 通知 | 予約担当とフロントへのチャット | メール |
| 保存 | 社内のデータベース | ファイルサーバー |
予約管理システムにも、予約サイトとの在庫の連携にも書き込みません。 この構成は記録を読むだけで、売り止めの操作は人が行います。予約管理システムからの書き出しの方法は製品ごとに違うため、どの項目がどの形で、どの時点の値として書き出せるかを、最初に確かめます。
モデルに HistGradientBoostingClassifier を選ぶ理由は2つあります。 1つ目は、欠けた値(NaN)をそのまま扱えることです。ドキュメントでは、学習のときに欠けた値のあるサンプルを分岐点の左右どちらへ送るかを学び、予測のときもその向きに送るとされています。予約サイトによって到着時刻や人数の内訳が届かないことがあり、「届かなかった」こと自体が来ないおそれの手がかりになるので、0で埋めずに残します。
2つ目は、経路や部屋タイプのような区分の値を扱えることです。categorical_features の既定は 'from_dtype' で、データフレームの列の型が Categorical なら区分として扱われます。
較正に CalibratedClassifierCV を使う理由は、足し算のためです。 ドキュメントでは、較正の済んだ分類器では、予測の確率が0.8に近いサンプルのおよそ80%が実際に陽性になる、と説明されています。来ない見込みの室数は確率の合計なので、この性質が無いと合計に意味がありません。
03どうやって実装するのか
処理の起点を決める
毎日15時の定時実行を起点にします。 翌日到着の予約の売り止めを決めるには、夕方の予約が動く時間帯の前に材料がそろっている必要があります。同じ処理を翌々日の到着分にも回し、2日前から見込みが動いていくのを見られるようにします。
満室に近い日だけ、21時にもう一度回します。 15時から21時のあいだに直前の予約と取消が入り、見込みが変わるからです。回すたびに結果を上書きせず、時刻付きで残します。 15時と21時で見込みがどう動いたかが、売り止めの判断に効きます。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| 到着前の予約 | 予約番号、館、部屋タイプ、到着日、泊数、人数、プラン、経路、事前決済の有無、予約日時、変更の回数、到着時刻の入力 | 予約管理システム |
| 過去の予約と結果 | 上記に加え、宿泊/当日取消/不泊/事前取消 の結果 | 予約管理システム(過去1年以上) |
| 同じ人を結び付ける鍵 | 会員番号、メールアドレス(ハッシュ化したもの) | 予約管理システム |
| 日の情報 | 曜日、祝日、近隣のイベントの有無(担当が入力) | 社内のカレンダー |
| 販売の上限 | 館・日ごとに、来ない見込みを理由に販売を続けてよい室数の上限 | 支配人が決めて表に入力 |
質を決めるのは、2行目の「結果」の記録です。 過去の予約が、宿泊したのか、当日に取り消したのか、連絡なく来なかったのかが分からなければ、学ぶものがありません。事前取消(前日までの取消)は、当日の見込みの対象から外します。 すでに部屋が戻っているからです。
3行目の鍵は、ハッシュ化して持ちます。 結び付けに使うのは「同じ人かどうか」だけで、氏名や電話番号そのものはモデルに要りません。
国籍、性別、年齢は特徴量に使いません。 来ないおそれと統計的に関係が出たとしても、属性で予約者を扱い分けることになり、連絡の順番に偏りが出ます。 予約の行動(経路、決済、日数、変更)だけで組みます。
データの取得方法を決める
予約管理システムから、到着日が翌日と翌々日の予約と、過去の予約の結果をCSVで書き出し、Python で読み込みます。書き出しは予約管理システムの定時出力の機能か、API の提供があればそれを使います。
| 取るもの | どこから | 何に使うか |
|---|---|---|
| 到着前の予約 | 15時と21時の書き出し | その時点の特徴量を作り、確率を出す |
| 過去の予約の結果 | 毎朝の書き出し(前日の到着分) | 予測と結果を並べる、学び直しに使う |
| 予約の変更の履歴 | 変更の記録 | 変更の回数、直前の変更の有無 |
| 販売の上限 | 支配人の表 | 判断材料の表で、上限を超える提案をしない |
学習用のデータは「到着の前日15時の時点で分かっていたこと」だけで作ります。 過去の予約の記録には、到着日の夜の取消や、チェックインの記録まで入っています。それを特徴量に混ぜると、学習では高い成績が出て、本番では当たらないモデルになります。 予約日時と変更の日時を見て、前日15時より後の情報を落とす処理を必ず入れます。
AIへ渡す前に整形する
- 同じ人の結び付け … 会員番号があれば会員番号で、無ければハッシュ化したメールアドレスで結び付けます。どちらも無い予約は「初めての人」として扱い、過去の回数は欠けた値にします
- 過去の回数の数え方 … 過去の取消と不泊は、その予約の予約日時より前に到着日が来た予約だけで数えます
- 予約からの日数 … 予約日時から到着日までの日数を出します。当日予約は0です
- 欠けた値の扱い … 到着時刻の入力が無い、人数の内訳が無いなどは、0で埋めずに NaN のまま渡します
- 区分の値の型 … 経路、館、部屋タイプ、プランの区分は、データフレームで
Categorical型にします - 対象外の除外 … 団体の手配、社員の利用、事前取消の済んだ予約は外します
- 目的の値の定義 … 「当日取消」と「不泊」をまとめて来なかった(1)、宿泊を来た(0)とします
7番目で当日取消と不泊をまとめるのは、売り止めの判断にとってはどちらも「部屋が空く」からです。 ただし記録には区別して残し、確認の連絡で取消の申し出を受けた件数を後から数えられるようにします。
AIに処理させる
この構成の「AI」は3つの部品に分かれます。 確率を出すのは勾配ブースティングのモデル、確率を実績に合わせるのが較正、連絡文を作るのが生成AIです。生成AIは確率も売り止めの数も作りません。
| 部品 | させること | させないこと |
|---|---|---|
| HistGradientBoostingClassifier | 予約ごとの来ないおそれの点数 | 売り止めるかどうかの答え |
| CalibratedClassifierCV | 点数を、実績に合う確率に直す | 予約の順番の入れ替え(sigmoid の場合) |
| 集計(Python) | 日別・館別・部屋タイプ別の合計と幅 | 支配人の上限を超える販売の提案 |
| Claude API | 到着時刻を確かめる連絡文の下書き | 確率や「来ないと思われている」ことを書く |
較正の方法は、まず method="sigmoid" で始めます。 ドキュメントでは、sigmoid は少ないサンプルで効きやすく、isotonic はより一般的な歪みを直せるものの、およそ1,000件を超える十分なデータが無いと過学習しやすいとされています。館ごと・部屋タイプごとに細かく分けると件数が足りなくなるので、3館をまとめて1つのモデルにし、館は区分の特徴量として入れます。 1年分がたまったら isotonic と比べます。
較正には、学習に使っていないデータを使います。 ドキュメントでは、較正の器は分類器の学習に使ったデータとは独立したデータで作るのが理想とされています。CalibratedClassifierCV は交差検証で分けて作るため、分け方には TimeSeriesSplit を渡します。 ドキュメントでは、時間順のデータにほかの分け方を使うと、未来のデータで学習して過去を評価することになるため不適切とされています。
class_weight='balanced' は使いません。 来ない予約は少数なので重みを付けたくなりますが、重みを付けると確率が実際より高く出て、合計が膨らみます。 この構成で欲しいのは順番だけでなく確率そのものなので、重みは付けず、較正で合わせます。
合計の幅は、確率から出します。 来ないおそれ p の予約が n 件あれば、来ない数の平均は p の合計、ばらつきは p×(1−p) の合計から求まります(予約どうしが独立と置いた場合)。ただし、同じ団体の手配や同じ会社の出張がまとめて取り消されることがあり、独立ではありません。 幅は「少なく見積もった幅」として表示し、支配人の上限で守ります。
| 生成AIにさせないこと | 理由 |
|---|---|
| 確率や順位を文面に書く | 予約者に「疑われている」と受け取られる |
| 取消を促す・取消料を強調する | 確認の連絡の目的は到着時刻を知ること |
| 予約の内容(プラン・料金)を書き換える | 予約管理システムの記録と食い違う |
| 予約者の名前や連絡先を扱う | 宛名は送る直前にシステムが差し込む |
指示内容を固定する
モデルの設定は次のとおりです。 学習と較正は月1回、予測は毎日15時と21時に回します。
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.calibration import CalibratedClassifierCV
from sklearn.model_selection import TimeSeriesSplit
# X は前日15時の時点の特徴量(到着日の順に並べる)、y は来なかった=1
base = HistGradientBoostingClassifier(
categorical_features="from_dtype", # 経路・館・部屋タイプ・プランは Categorical 型
max_iter=300,
learning_rate=0.05,
# class_weight は付けない(確率を合計に使うため)
)
model = CalibratedClassifierCV(
base,
method="sigmoid", # 件数が十分にたまったら isotonic と比べる
cv=TimeSeriesSplit(n_splits=5, gap=7) # 学習の末尾7件を空けて評価に漏らさない
)
model.fit(X_train, y_train)
p = model.predict_proba(X_today)[:, 1] # 予約ごとの来ないおそれ
gap を入れるのは、同じ日の予約どうしが似た動きをするからです。 ドキュメントでは、gap は学習用の末尾から評価用の前までに除くサンプルの数とされています。到着日の順に並べたとき、学習の最後と評価の最初が同じ日の予約になると、同じ日の天候やイベントの影響が両方に入り、成績が良く見えます。 実際には日の単位で空けるよう、件数を調整します。
連絡文の下書きは、Claude API に次の指示で作らせます。
あなたはホテルのフロントで、到着前日に予約者へ到着時刻を確かめる連絡文を書く立場です。
渡された予約の情報だけを使って、メールの本文と、電話で話す要点を作ってください。
【渡す情報】
- 館の名前、到着日、泊数、部屋タイプ、プラン名
- 到着時刻の入力の有無(ある場合はその時刻)
- 事前決済の有無
- 館のチェックインの時刻と、当日の連絡先
- 取消の規定の文面(館が定めたものをそのまま)
【書き方】
- 1行目は、到着日と館の名前を書いた、到着のお礼とご案内の書き出しにしてください。
- 到着時刻の入力が無い場合は、到着の予定時刻を教えてほしいとお願いしてください。
- 到着時刻の入力がある場合は、その時刻で変わりがないかを確かめてください。
- 予定が変わった場合の連絡先を書いてください。
- 取消の規定は、渡された文面をそのまま末尾に添えてください。
- 電話の要点は3行以内にしてください。
【厳守事項】
- 宛名は書かないでください。「{宛名}」とだけ書いてください。
- 来ないおそれ、確率、順位、過去の取消や不泊のことを書かないでください。
- 取消を勧める、取消料を強調する表現を使わないでください。
- 渡された情報に無いサービスや特典を書かないでください。
- 料金、プランの内容を書き換えないでください。
- 取消の規定を要約・言い換えしないでください。
- 渡された情報が足りない場合は、文面を作らず missing に足りない項目を書いてください。
【予約の情報】{reservation}
【館の情報】{property}
【取消の規定】{cancel_policy}
「過去の取消や不泊のことを書かない」を明記するのは、渡していなくても書くことがあるからです。 指示に「来ないおそれの高い予約への連絡」と目的を書くと、生成AIは丁寧に「前回のご予約ではお越しいただけなかったため」と書き添えることがあります。目的を指示に書かず、到着時刻を確かめる連絡とだけ伝えます。
出力形式を固定する
次の形のJSONを、予約ごとと日ごとの2種類で作ります。 予約ごとの p_noshow と順位は Python が埋め、contact_draft を Claude API の構造化出力(output_config.format に type: "json_schema")で受け取ります。
{
"reservation_id": "R-2026-1008-03321",
"property": "B館",
"arrival_date": "2026-10-08",
"room_type": "シングル",
"channel": "OTA-2",
"prepaid": false,
"lead_days": 1,
"p_noshow": 0.31,
"contact_rank": 4,
"model_version": "2026-10-01",
"run_at": "2026-10-07T15:00",
"contact_draft": { "email_body": "", "phone_points": [], "missing": [] },
"contact_result": { "status": null, "by": "", "at": "" },
"outcome": null
}
{
"property": "B館",
"arrival_date": "2026-10-08",
"room_type": "シングル",
"rooms_total": 180,
"rooms_booked": 178,
"expected_noshow": 6.4,
"range_low": 2.6,
"range_high": 10.2,
"manager_cap": 3,
"suggestion": "上限3室の範囲で販売継続を検討",
"decision": { "action": null, "by": "", "at": "" }
}
1つ目の理由は、予測と人の判断と結果を1行に並べられることです。 p_noshow を出した時点の値、contact_result に連絡の結果、outcome に実際の結果が入るので、後から「0.3と出た予約が本当に3割来なかったか」を数えられます。
2つ目は、manager_cap を出力に含めることです。 提案の文言は上限の範囲でしか作らず、上限が0の日は「販売継続」の提案を出しません。 上限そのものが記録に残るので、後から判断の前提を読み直せます。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| 予約管理システム | 定時の書き出し(読み取りのみ) | 到着前の予約、過去の結果、変更の履歴 |
| 支配人の上限の表 | 表の読み取り | 館・日ごとの販売の上限 |
| Claude API | API呼び出し | 確認の連絡文の下書き |
| 予約担当へのチャット | 通知 | 日別の判断材料の表 |
| フロントの連絡の一覧 | 画面の表示 | おそれの高い順の予約と下書き |
予約サイトとの在庫の連携には、つなぎません。 売り止めを自動で入れると、確率の外れがそのまま販売の停止や継続になります。この構成の出力は、人が売り止めを決めるための表までです。
人が確認する
売り止めの判断は、予約担当と支配人が必ず行います。
- 日別の表を見る … 残室、来ない見込みの室数と幅、支配人の上限を並べて見ます
- 表に無い事情を足す … 団体の到着の遅れ、近隣のイベントの中止、振替先の手当てなどを加えます
- 売り止めるか、上限の範囲で販売を続けるかを決める … 決めたことを
decisionに記録します - 連絡の一覧の上から連絡する … フロントの予約係が、下書きを直して送るか電話します
- 結果を記録する … 到着時刻の確認、取消の申し出、不通のいずれかを残します
5番目で「不通」を記録することを省かないでください。 連絡がつかなかった予約は、来ないおそれがさらに高い可能性があり、21時の見直しの材料になります。 ただし、この値はモデルの特徴量には入れません。連絡したかどうかは順位で決まっているので、入れると順位が自分を強める形になります。
目標は、1,500件をならして1件1分です。 上位の予約は連絡と記録で数分かかり、下位の予約は一覧で流し見るだけで済みます。
例外に対処する
| 起きること | 対応 |
|---|---|
| 予約管理システムの書き出しが届かない | その回は見込みを出さず「データなし」と通知。前回の数字を使い回さない |
| 同じ人を結び付けられない | 過去の回数を欠けた値にして計算する。「初めての人」として0にしない |
| 新しい予約サイトの経路 | 学習に無い区分。確率を参考値と表示し、合計から別枠にする |
| 大きなイベントの日 | 過去に同じ規模の日が少ない。幅を広く表示し、上限を支配人が見直す |
| 団体の一部が個人の予約で入る | 同じ会社の手配がまとまっていれば団体として外す |
| 連絡文の下書きに渡していない情報がある | 下書きを捨て、定型文で連絡する |
| Claude API が応答しない | 定型文で連絡する。確率と順位は止めない |
| 見込みと実績が大きくずれる日が続く | 学び直しを待たず、モデルの数字を参考値に下げる |
3行目の新しい経路は、確率が当てにならない典型です。 モデルは学習したことのない区分について、ほかの区分から推し量った数字を出します。その数字を合計に入れると、日別の見込みが根拠なく動きます。 別枠にして、件数だけを並べて見せます。
記録を残す
- 15時と21時の予約の書き出しと、そこから作った特徴量
- 予約ごとの
p_noshow、順位、model_version、run_at - 日別の見込み、幅、支配人の上限、人の判断(売り止めたか、何室販売を続けたか)
- 連絡の結果(到着時刻の確認、取消の申し出、不通)と、連絡した人と時刻
- 実際の結果(宿泊/当日取消/不泊)
- 較正の確認の記録 … 月ごとに、確率の帯ごとの実際に来なかった割合
3つ目で「人の判断」を残すのは、見込みの当たり外れと判断の良し悪しを分けて見るためです。 見込みが当たっていても、販売を続けなかった日は空室が出ます。
最後の行がいちばん大事です。 ドキュメントには、予測の確率を横軸、実際に陽性だった割合を縦軸にとる較正の曲線(calibration_curve)があります。0.3の帯で実際に3割前後が来ていなければ、合計の数字を信用してはいけません。 毎月この表を見てから、翌月も数字を使うかを決めます。
04実装レベルの3段階
半自動化で、1件4分が2分程度になります。 過去の泊歴を探す時間がなくなり、確率が並んで出てきます。ただし、確率をどこまで信じてよいかが分からないため、担当は1件ずつ見直します。本格構成で1分になり、この段階が本記事の想定です。 較正と、その確認の表があることで、合計の数字をそのまま判断材料として使えるようになります。 段階を飛ばさないでください。 半自動化の数字を2か月見ると、どの経路で確率が外れやすいか、結び付けられない予約がどれだけあるかが分かります。そこを直してから較正に進むほうが、数字の意味が早く安定します。
05工数削減シミュレーション
導入後 1,500件 × 1分 ÷ 60 = 25 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 客室数が数百室規模で、自社サイト・複数の予約サイト・電話・旅行会社など予約の経路が多く、事前決済のある予約と無い予約が混ざっているホテル。満室に近い日に、残りの部屋をいつ売り止めるか、どの予約に確認の連絡を入れるかを、予約担当の経験で決めている場合。予約管理システムから、過去1年以上の予約と、取消・不泊の結果を書き出せる場合。
- 客室が十数室で、予約の全件を担当者が把握できる宿。予約のほとんどが事前決済で、当日に来ない予約がほぼ無い場合。過去の予約の結果(取消か不泊か宿泊か)が記録に残っていない場合。なお、何室まで販売を続けるか、満室で泊められない客をどう扱うかの判断は、この構成では代替できません。
07最小構成で試す方法
- 過去3か月の到着分の予約を、結果(宿泊/当日取消/不泊)付きで書き出す(満室に近かった日を必ず含める)
- 経路、事前決済、予約からの日数、変更の回数、到着時刻の入力の5列だけに絞る
- 手元の表計算で、5列の組み合わせごとに「来なかった割合」を集計する
- 担当者に、同じ期間の満室に近かった日について、当時どの予約を「来ない」と見ていたかを聞き取る
- 集計した割合で見た「来ない予約」と、担当者の見当を突き合わせる
3か月分は必ずやってください。 モデルを作る前に、「予約の記録に、来ないおそれの手がかりがあるのか」を確かめます。
| 出てきた内容 | 判断 |
|---|---|
| 経路や事前決済で来なかった割合がはっきり違う | モデルの作成に進む |
| 割合の違いはあるが、担当者の見当とほぼ同じ | 判断をそろえる効果が中心。構成は有効 |
| 結果の記録が欠けていて割合が出せない | 記録の付け方が先。 AIの問題ではない |
3行目が出ることは珍しくありません。 当日取消と不泊を区別せずに「取消」と記録していたり、事前取消と同じ扱いにしていたりします。その場合は、まず1か月、結果の付け方をそろえて記録してください。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
| 学習では当たるのに、本番で外れる | 到着日の夜や当日の情報が特徴量に漏れている。 前日15時より後の情報を落とす |
| 合計の見込みが実績より多すぎる | class_weight='balanced' を付けていないか。付けると確率が膨らむ |
| 確率の帯と実績が合わない | 較正をやり直す。較正の器は学習と別のデータで作る |
| isotonic で較正したら数字が不安定 | およそ1,000件を超えるデータが無いと過学習しやすい。 sigmoid に戻す |
| 交差検証の成績だけが良い | 時間順に分けていない。TimeSeriesSplit と gap を使う |
| 新しい予約サイトの予約で数字が飛ぶ | 学習に無い区分。別枠にして合計に入れない |
| 同じ人が別人として数えられる | 会員番号とメールアドレスの整備。結び付けられない分は欠けた値に |
| 団体の取消で見込みが大きく外れる | 団体は外す。個人の予約と同じモデルに入れない |
| 連絡文に過去の不泊のことが書かれる | 目的を指示に書かず、到着時刻の確認とだけ伝える |
| 売り止めを自動で入れたくなる | 入れない。 判断材料の表までにする |
| 結果を取り込まずに数か月使う | 予約サイトの規定の変更で数字の意味が変わる。毎月確認の表を見る |
| 属性で連絡の順番が偏る | 国籍・性別・年齢を特徴量に使わない |
上の2行が、この構成の失敗のほとんどです。 どちらも「数字がそれらしく出る」ので気づきにくく、本番の1か月目に合計が実績と合わないことで初めて分かります。 最小構成の段階で、過去3か月を時点をそろえて作り直しておくと、早く気づけます。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: 予約者の予約の記録、過去の宿泊・取消・不泊の履歴、会員番号、メールアドレス、そして予約者ごとの「来ないおそれ」という点数です。
- 点数を予約者に知らせない … 連絡文に確率や過去の取消を書かず、到着時刻を確かめる連絡として扱います。 点数で疑っていると受け取られれば、予約者との関係に直接ひびきます
- 属性を特徴量に使わない … 国籍・性別・年齢は使いません。行動の記録だけで組み、連絡の順番が属性で偏らないようにします
- 生成AIに個人を特定する情報を渡さない … 渡すのは館、到着日、部屋タイプ、プランなどの予約の中身だけです。宛名と連絡先は、送る直前にシステムが差し込みます
- 同じ人の結び付けの鍵をハッシュ化して持つ … モデルに要るのは「同じ人かどうか」だけです。氏名や電話番号そのものを学習のデータに入れません
- 販売の上限は支配人が決める … この構成は上限を超える提案をしません。満室で泊められない客が出たときの振替の手当てまで含めて、上限は人が決めます
誤りが起きた場合のリスクは、来る予約を来ないと見込んで販売を続け、満室で泊められない客を出すことと、来ない予約を来ると見込んで空室を出すことの2つです。 前者は確率の膨らみ(重み付け・情報の漏れ)で起き、後者は早すぎる売り止めで起きます。前者の被害のほうが重いので、支配人の上限で守ります。
10まず何から始めるか
1週目:結果の記録をそろえる
過去の予約の結果が、宿泊/当日取消/不泊/事前取消 の4つに分けて残っているかを確かめます。分かれていなければ、今日から4つに分けて記録します。この記録が無いと、何も学べません。
2週目:過去3か月で試す
過去3か月の到着分を書き出し、5列の組み合わせごとに来なかった割合を集計します。満室に近かった日について、担当者の当時の見当と突き合わせます。
3週目:販売の上限を決める
館・日ごとに、来ない見込みを理由に販売を続けてよい室数の上限を、支配人と決めます。 0の日があってかまいません。ここが決まらないうちにモデルを作ると、数字は出るのに誰も使えない状態になります。あわせて、確認の連絡文の定型と、取消の規定の文面をそろえます。
4週目:前日15時の時点の特徴量を作る
Python で、過去の予約から前日15時の時点の特徴量を作り、TimeSeriesSplit で分けてモデルを作ります。この時点では較正をせず、確率の帯と実績の割合の表だけを見ます。
2か月目: 較正を足し、毎日15時の予約ごとの確率と日別の見込みを出します。予約担当は見込みを見ながら、これまでどおりに判断します。3か月目以降: 支配人の上限との突き合わせと、確認の連絡の一覧と下書きを足し、1件4分が何分になったかを実測します。毎月の較正の確認の表で、確率の帯と実績の割合が合っていると確かめられた時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
HistGradientBoostingClassifier が欠けた値(NaN)をそのまま扱い、学習時に欠けた値の送り先を学び、予測時もその向きに送ること。categorical_features の既定が 'from_dtype' であること。class_weight に 'balanced' を指定できること。predict_proba がクラスごとの確率を返すこと | scikit-learn: HistGradientBoostingClassifier | 2026-10-06 |
較正の済んだ分類器では予測の確率が0.8に近いサンプルのおよそ80%が陽性になること。CalibratedClassifierCV に sigmoid と isotonic があり、sigmoid は少ないサンプルで効きやすく、isotonic はおよそ1,000件を超えるデータが無いと過学習しやすいこと。較正の器は分類器の学習と独立したデータで作るのが理想であること。calibration_curve で予測の確率と実際の陽性の割合を比べられること | scikit-learn: Probability calibration | 2026-10-06 |
TimeSeriesSplit が時間順のデータの分け方を作り、ほかの分け方は未来のデータで学習して過去を評価することになるため不適切とされること。gap で学習用の末尾から評価用の前までのサンプルを除けること | scikit-learn: TimeSeriesSplit | 2026-10-06 |
構造化出力で output_config.format に type: "json_schema" を指定して応答をJSONスキーマに沿わせられること | Claude Docs: Structured outputs | 2026-10-06 |
販売の上限と、満室で泊められない客が出たときの扱いは、支配人と自社の方針で決めてください。 本記事は製品の公開ドキュメントで確認できた範囲だけを扱っています。予約管理システムからの書き出しの方法は製品ごとに違い、本記事では確かめていません。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-0578)についてのご相談はこちらから。
