📚 背景知識(読んでから問題へ)
| 参加チーム数 | Bronze圏内の目安 | Silver圏内の目安 | Gold圏内の目安 |
|---|---|---|---|
| 〜99チーム | 上位40% | 上位20% | 上位10%程度 |
| 100〜249チーム | 上位40% | 上位20% | 上位10チーム程度 |
| 250〜999チーム | 上位100チーム | 上位50チーム | 上位10〜数十チーム(上位2〜3%程度) |
| 1000チーム以上 | 上位10% | 上位5% | 上位1%未満 |
正式な閾値はKaggle公式Progression Systemページで確認する必要があるが、「Goldはチーム数が多いほど絶対人数ベースの狭き門になる」という傾向は共通している。
①モデル多様性でチーム不在を補う: GBDT(LightGBM/XGBoost/CatBoost)とNN(Phase5のCNN/LSTM/マルチモーダル)は誤差の出方が異なりやすく、この2系統を仕込むことがチームの代わりになる
②CVを信じ、Public LBに振り回されない: CV-LBギャップ(Day101のNestedCV)が拡大していたら危険信号
③時間配分は「安い打ち手を先に」: 特徴量エンジニアリングやCV設計の見直しはモデル追加より低コスト
④最終サブミットは2つしか選べない: CVベスト1つ+CVとの乖離が小さいLBベスト1つが定石
🎯 問題
架空のKaggleコンペ「Retail Demand & Anomaly 2026」(店舗×商品ごとの日次需要予測、評価指標はSMAPE(小さいほど良い))に、あなたはチームを組まずソロで参加しています。
| 項目 | 値 |
|---|---|
| データ形式 | 数値/カテゴリ特徴量 + 180日分の時系列 + 商品説明文(テキスト) |
| 評価指標 | SMAPE(小さいほど良い) |
| 参加チーム数 | 640チーム |
| コンペ残り日数 | 18日 |
| Gold / Silver / Bronze 圏内ライン | 上位20位 / 64位 / 128位 |
| 現在のPublic LB順位 | 54位 / 640(SMAPE=12.83) |
| 現在のCV(5-fold GroupKFold) | SMAPE=12.55 |
| 試行済み手法 | LightGBM単体、ラグ/ローリング特徴量、Optunaチューニング、5-fold CV |
| 未使用モダリティ / モデル系統 | 商品説明文(テキスト) / CatBoost・NN系 |
| チェックポイント | Public LB順位 | CVスコア | LBスコア | ギャップ(LB-CV) |
|---|---|---|---|---|
| 3週間前 | 210位 | 13.90 | 15.10 | +1.20 |
| 2週間前 | 130位 | 13.30 | 14.25 | +0.95 |
| 1週間前 | 88位 | 12.80 | 13.41 | +0.61 |
| 今日 | 54位 | 12.55 | 12.83 | +0.28 |
recommend_solo_gold_final_push(...)を実装する。残り日数3日以下は新規モデル禁止、未使用モダリティ×残り7日以上で多様化提案、GBDT単系統ならモデル系統の追加提案、CV-LBギャップ拡大時は警告、最終2サブミットの選び方は必須で含める、の5ルールを満たす📊 順位とメダル圏の可視化(640チーム中の現在地)
💡 ヒント
新しい技術要素は登場しません。「Phase4とPhase5でバラバラに学んだ武器を、限られた残り日数の中でどの順番で投入するか」を、Day120と同じ「条件分岐によるルール化」で表現する回です。タスク2では「モダリティの多様性」と「モデル系統の多様性」という2種類の多様性を区別して扱う点がポイントです。
- CV-LBギャップの推移が「拡大傾向」か「縮小傾向」かは、直近4値の差分(
gap[i] - gap[i-1])がすべて負(縮小し続けている)かどうかで機械的に判定できる - 「モダリティの多様性」は
modalities_availableとmodalities_usedの差分、「モデル系統の多様性」はtried_methodsにGBDT系以外(catboost/neural_net等)が含まれるかで判定する。この2つは独立した別の判定軸 - 順位差(
current_rank - gold_rank_threshold)が大きいほど、小手先の調整ではなく特徴量エンジニアリングのような根本的な打ち手をリストの先頭付近に置く - 最終2サブミットの提案は、状況にかかわらず必ず返り値の最後に含める
def recommend_solo_gold_final_push( days_left, current_rank, gold_rank_threshold, cv_score, lb_score, cv_lb_gap_history, tried_methods, modalities_available, modalities_used, ): actions = [] rank_gap = current_rank - gold_rank_threshold # 縮小/拡大傾向の判定(直近4値の差分がすべて負なら縮小傾向) gap_diffs = [cv_lb_gap_history[i] - cv_lb_gap_history[i-1] for i in range(1, len(cv_lb_gap_history))] gap_widening = any(d > 0 for d in gap_diffs) # ... 順位差が大きければ特徴量エンジニアリングを優先、 # 未使用モダリティ×残り日数7日以上でモデル多様性を追加、 # GBDT単系統ならモデル系統を追加、残り3日以下は新規禁止 ... actions.append({"action": "select_final_2_submissions", "priority": "must"}) return actions
✅ 模範解答
タスク1: 優先度順の打ち手リスト(残り18日・Gold圏まで34人分)
- 1特徴量エンジニアリングの深掘り(Phase3-4) — 34人分の差は小手先のチューニングでは埋まりにくい。ラグ・ローリング統計量の粒度追加や店舗×商品の交互作用特徴量を優先する
- 2テキストモダリティ用のマルチモーダルNN追加(Day124) — 未活用の商品説明文をIntermediate Fusionで取り込み、GBDT単体では拾えない誤差パターンを補う
- 3CatBoostまたはNN系モデルの追加(Phase4/5) — LightGBM単系統から脱し、アンサンブルの前提となる「誤差の相関が低い2つ目のモデル」を用意する
- 4アンサンブル重みの最適化(Day102 Averaging) — 複数モデルが揃った段階でRank Average/重み最適化を行う
- 5残り3日を切ったらシード平均のみに専念し、最終2サブミットを選定 — 新規モデル追加を凍結し、CVベスト+CVとの乖離が小さいLBベストを選ぶ
タスク2: recommend_solo_gold_final_push の実装
def recommend_solo_gold_final_push( days_left: int, current_rank: int, gold_rank_threshold: int, cv_score: float, lb_score: float, cv_lb_gap_history: list[float], tried_methods: list[str], modalities_available: list[str], modalities_used: list[str], ) -> list[dict]: """残り日数・現状のスコア/順位・試行済み手法から、ソロGoldに向けた次の一手を優先度順に返す。""" actions = [] rank_gap = current_rank - gold_rank_threshold # --- CV-LBギャップの傾向判定(直近の差分がすべて負なら縮小傾向) --- gap_diffs = [cv_lb_gap_history[i] - cv_lb_gap_history[i - 1] for i in range(1, len(cv_lb_gap_history))] gap_widening = any(d > 0 for d in gap_diffs) # --- ルール1: 残り日数3日以下なら新規モデル追加を禁止 --- freeze_new_models = days_left <= 3 # --- 順位差が大きい場合は根本的な打ち手を最優先に --- if rank_gap > 20 and not freeze_new_models: actions.append({ "action": "feature_engineering_deep_dive", "priority": "high", "reason": f"Gold圏まで{rank_gap}人分の差があり、特徴量エンジニアリング(Phase3-4)を優先する", }) # --- ルール2: 未使用モダリティ×残り日数7日以上でモデル多様性を追加 --- unused_modalities = [m for m in modalities_available if m not in modalities_used] if unused_modalities and days_left >= 7 and not freeze_new_models: target = unused_modalities[0] actions.append({ "action": f"add_multimodal_branch_for_{target}", "priority": "high", "reason": f"「{target}」が未活用。Day124のIntermediate Fusionでモデル多様性を補う", }) # --- ルール3: GBDT単系統のみならモデル系統を追加 --- gbdt_family = {"lightgbm", "xgboost", "catboost"} nn_family = {"neural_net", "cnn", "lstm", "tft", "multimodal_nn"} has_gbdt_diversity = len(gbdt_family & set(tried_methods)) >= 2 has_nn = len(nn_family & set(tried_methods)) >= 1 if not (has_gbdt_diversity or has_nn) and not freeze_new_models: actions.append({ "action": "add_second_model_family", "priority": "medium", "reason": "LightGBM単系統のみ。CatBoardかNN系を追加し誤差相関の低いモデルを揃える", }) # --- ルール4: CV-LBギャップが拡大傾向なら警告(今回は縮小傾向のため発火しない) --- if gap_widening: actions.append({ "action": "distrust_public_lb", "priority": "high", "reason": "CV-LBギャップ拡大。Public LBよりCVスコアを重視する", }) if freeze_new_models: actions.append({ "action": "seed_averaging_and_weight_tuning_only", "priority": "high", "reason": "残り日数僅少。新規モデルはリスクが高いためシード平均・重み最適化のみ", }) # --- ルール5: 最終2サブミットの選び方は必ず提案 --- actions.append({ "action": "select_final_2_submissions", "priority": "must", "reason": "1つ目はCVベスト、2つ目はCVとの乖離が小さいLBベストを選ぶ", }) return actions # --- 動作確認: 「Retail Demand & Anomaly 2026」の現在の状況 --- plan = recommend_solo_gold_final_push( days_left=18, current_rank=54, gold_rank_threshold=20, cv_score=12.55, lb_score=12.83, cv_lb_gap_history=[1.20, 0.95, 0.61, 0.28], tried_methods=["lightgbm", "feature_engineering_lag_rolling", "optuna_tuning"], modalities_available=["tabular", "timeseries", "text"], modalities_used=["tabular", "timeseries"], ) for i, a in enumerate(plan, 1): print(f"{i}. [{a['priority']}] {a['action']}") # 出力例: # 1. [high] feature_engineering_deep_dive # 2. [high] add_multimodal_branch_for_text # 3. [medium] add_second_model_family # 4. [must] select_final_2_submissions # (CV-LBギャップは1.20→0.95→0.61→0.28と一貫して縮小 → distrust_public_lb は発火しない)
タスク3: 順位・ギャップ推移の分析と最終結論
| チェックポイント | LB順位 | ギャップ | 解釈 |
|---|---|---|---|
| 3週間前 | 210位 | +1.20 | ギャップ大=初期のCV設計がまだ粗い段階 |
| 2週間前 | 130位 | +0.95 | 特徴量追加でCVも改善、ギャップも縮小 |
| 1週間前 | 88位 | +0.61 | Optunaチューニングの効果、さらに縮小 |
| 今日 | 54位 | +0.28 | ギャップ1/4程度に縮小=過学習ではなく素直な改善 |
distrust_public_lbが発火しなかった判定は妥当。今日から18日間は、①特徴量エンジニアリングの深掘り、②テキストモダリティのマルチモーダルNN投入、③CatBoost/NN系の追加でモデル多様性を確保、という順で進め、残り3日を切った時点で新規モデル追加を完全凍結し、シード平均と最終2サブミットの選定に専念するのが合理的。📉 CV-LBギャップの推移(縮小傾向=良い兆候)
distrust_public_lbは発火せず、Public LBの改善をある程度信頼してよい状況と判断できる。🪜 Step-by-Step 解説
1「モダリティの多様性」と「モデル系統の多様性」を分けて判定する
unused_modalities = [m for m in modalities_available if m not in modalities_used] ... has_gbdt_diversity = len(gbdt_family & set(tried_methods)) >= 2 has_nn = len(nn_family & set(tried_methods)) >= 1
2CV-LBギャップの「傾向」を差分の符号で判定する
gap_diffs = [cv_lb_gap_history[i] - cv_lb_gap_history[i - 1] for i in range(1, len(cv_lb_gap_history))] gap_widening = any(d > 0 for d in gap_diffs)
3残り日数3日以下では新規モデルの提案を機械的に止める
freeze_new_models = days_left <= 3 if rank_gap > 20 and not freeze_new_models: ...
freeze_new_modelsという1つのフラグで、複数の提案ルールすべてに一貫して「終盤は守りに入る」方針を反映できる。4「最終2サブミットの選び方」だけは条件によらず必ず返す
actions.append({"action": "select_final_2_submissions", "priority": "must", ...})
🧮 数学・統計の補足(文系向け)
n個の独立な推定値(誤差の分散はどれも同じσ²、誤差同士の相関係数ρ)を単純平均したときの分散は、次の式で近似できます。
Var(平均) = ρσ² + (1-ρ)σ²/nρ=0(誤差が完全に無相関)なら、モデルを増やすほど分散はσ²/nまで小さくなります。しかしρが1に近い(=どのモデルも似た間違え方をする)と、いくら増やしてもρσ²という下限から下がりません。LightGBM・XGBoost・CatBoostを3つ並べても「木を分割して予測する」という同じ仕組みのためρは高くなりがちですが、NN(Day111-124)は決定木と全く異なる仕組みで学習するためρが下がりやすく、アンサンブルの分散低減効果が大きくなります。チームの一番の価値は「ρの低い誤差源=他人の頭脳」を確保できることであり、ソロ参加者はGBDTとNNというアルゴリズムの系統を意図的に変えることで、これに近い効果を1人で再現しています。
🏆 Kaggleでの実践的な使い方
よく使われるコンペカテゴリ: ☑ 表形式データ(Tabular) / ☐ 自然言語処理(NLP) / ☐ 画像認識(CV) / ☑ 時系列(Time Series)
🛒 M5 Forecasting
GBDT数個 + 簡易NNの終盤アンサンブル
上位ソロ参加者の多くが「LightGBM系のモデル数個 + 簡易的なNN(Day121のLSTM相当)」を最終盤でアンサンブルしており、今日学んだ「GBDT×NNの多様性戦略」の実例になっている。
📈 Optiver Realized Volatility
CV-LBギャップを日次で記録
ソロGoldを獲得した参加者のsolution writeupでは「CV-LBギャップを毎日記録したスプレッドシート」を運用していたという報告が複数あり、今日のタスク3のような監視が実際に使われている。
🏭 実務での応用
モデル多様性をリスク検知に転用
需要予測・異常検知でも「統計手法+GBDT+DL」を並行運用し、予測の乖離が大きいサンプルを人間が重点レビューする「モデル多様性をリスク検知に使う」考え方に転用できる。
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| Public LBの順位が上がっていれば安心してよいと思う | 目に見える指標(順位)に安心感を覚えやすい | Public LBはtest全体のごく一部にすぎず、終了時にPrivate LBで大きく順位が変動するシェイクアップ/ダウンが起こりうる。常にCVとの乖離を確認する |
| モデルを増やすほどアンサンブル効果が大きくなると思う | 「数が多いほど良い」という直感 | 誤差の相関が高いモデルを増やしても効果は頭打ちになる。GBDT×NNのように系統の異なるモデルを混ぜる必要がある |
| 残り日数が少なくなってから慌てて新モデルを追加しようとする | 「まだ間に合うかも」という焦り | 検証不十分な新規モデルを終盤に混ぜるリスクの方が大きい。閾値をあらかじめ決め、機械的に止める判断が有効 |
| 最終2サブミットを両方ともPublic LBベストで選んでしまう | 「一番良いスコアを選べば安全」という直感 | 同じ過学習傾向を持つ2つを選ぶとPrivate LBで共倒れする。必ず1つはCVベスト(LBに寄せていない安全な選択)を残す |
| ソロGoldは単に「運が良かっただけ」だと軽視する | メダルの色だけを見て中身を評価しない | ソロGoldはモデル多様性・CV設計・時間配分のすべてを1人で判断し切った結果。分業できない分、意思決定の質がそのままスコアに直結する |
🚀 次のステップ
- 発展:
recommend_solo_gold_final_pushに、Day107(SHAP)を使い「GBDTとNNのどちらが重視している特徴量が異なるか」を定量比較するcompare_feature_attribution(gbdt_shap, nn_gradient_importance)を追加してみましょう。2つのモデルが本当に異なる情報源を見ているかを検証でき、アンサンブルの多様性を数値で裏付けられます - 次回予告: Day 126 — Phase 6突入(Grandmaster)。本日でPhase 5(テーマ20/20)が完全に完了しました。次のPhase 6ではSOTA手法の追跡・論文実装から始まり、カスタムアーキテクチャ設計、Pseudo Labeling・TTAといった高度なアンサンブル、そして最終的に「Gold 3枚達成プラン」というコンペ戦略まで、Grandmaster到達に向けた最終段階に入ります
Phase 5 の学習マップ(全20テーマ・本日完了)
Day110〜125の16日間でDL基礎・CV・時系列DL・マルチモーダル・ソロGold戦略までを一通り学び、Phase5が完了した。次はPhase6(Grandmaster)へ進む。
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: