📚 背景知識(読んでから問題へ)
🤖
Day 086 で AutoML(AutoGluon・PyCaret)を学びました。今日はKaggle APIを使い、データダウンロードから提出・実験ログ記録まで完全自動化するパイプラインを構築します。Expert 以上のプレイヤーは全員これを使っています。
Kaggle API でできること
ブラウザ操作を Python スクリプト1行に置き換えられます。
| 作業 | 手動(ブラウザ) | API(1行) |
|---|---|---|
| データダウンロード | 数クリック + 解凍 (2〜5分) | kaggle competitions download -c titanic |
| 予測ファイルの提出 | ブラウザ操作 3分 | kaggle competitions submit -f submission.csv -m "memo" |
| スコア確認 | ブラウザで確認 | kaggle competitions submissions -c titanic |
| 上位ノートブック取得 | 手動検索 + クリック | kaggle kernels list --competition titanic |
| データセット取得 | 検索 + ダウンロード | kaggle datasets download user/dataset |
💡
Expert への境界線: ブラウザを使わずにコマンドで全操作できるようになると、実験のサイクルが劇的に速くなります。「1日10回試行」も苦にならなくなります。
API キーの取得方法
# 1. Kaggle にログイン後
# 2. 右上アイコン → Account → API セクション
# 3. "Create New Token" → kaggle.json がダウンロードされる
$ mkdir -p ~/.kaggle
$ mv kaggle.json ~/.kaggle/kaggle.json
$ chmod 600 ~/.kaggle/kaggle.json # セキュリティ必須
# 2. 右上アイコン → Account → API セクション
# 3. "Create New Token" → kaggle.json がダウンロードされる
$ mkdir -p ~/.kaggle
$ mv kaggle.json ~/.kaggle/kaggle.json
$ chmod 600 ~/.kaggle/kaggle.json # セキュリティ必須
⚙️ API セットアップ — 環境別の手順
| 環境 | kaggle.json の配置方法 | 注意点 |
|---|---|---|
| ローカル(Mac / Linux) | ~/.kaggle/kaggle.json に配置 + chmod 600 |
一度設定すれば恒久的 |
| Google Colab | files.upload() でアップロード → ~/.kaggle/ に移動 |
セッションごとに必要 |
| Kaggle Notebooks | Settings → Add-ons → Environment Variables に設定 | セッション間で保持 |
| GitHub Actions / CI | Secrets に KAGGLE_USERNAME / KAGGLE_KEY を設定 |
セキュアな自動化が可能 |
🗂️ データスキーマ — Titanic(API でダウンロードした後のファイル構成)
| ファイル名 | 行数 | 目的 | API後の配置 |
|---|---|---|---|
train.csv | 891行 | 学習データ(Survived ラベルあり) | ./data/titanic/train.csv |
test.csv | 418行 | テストデータ(Survived なし) | ./data/titanic/test.csv |
gender_submission.csv | 418行 | 提出フォーマットのサンプル | ./data/titanic/gender_submission.csv |
特徴量一覧(モデルに投入するカラム)
| カラム名 | 型 | 説明 | 前処理 |
|---|---|---|---|
Survived | int | 生存フラグ(目的変数) | target に指定 |
Pclass | int | 客室クラス (1/2/3) | そのまま |
Sex | str | 性別 male/female | male=0, female=1 |
Age | float | 年齢(欠損 ~20%) | 中央値で補完 |
Fare | float | 運賃 | 中央値で補完 |
SibSp | int | 兄弟・配偶者の同乗数 | そのまま |
Parch | int | 親・子の同乗数 | そのまま |
Embarked | str | 乗船港 C/Q/S | One-Hot エンコード |
FamilySize | int | 新規: SibSp + Parch + 1 | 派生特徴量 |
IsAlone | int | 新規: FamilySize==1 → 1 | 派生特徴量 |
🎯 問題
⚠️
Kaggle API の実行には
~/.kaggle/kaggle.json が必要です。まず Kaggle アカウントで API キーを取得してください。データダウンロード以外の部分は JSON キーがなくてもコードを読んで理解できます。タスク1: Kaggle API のセットアップと動作確認
1
kaggle パッケージをインストールして接続テストを実行する
kaggle competitions list --search titanic でエラーが出なければ OK
2
Titanic データを API でダウンロードして内容を確認する
-p ./data/titanic/ --unzip オプションを使う
タスク2: モデル学習・予測・提出
1
train.csv を読み込み、特徴量工学(FamilySize / IsAlone 追加)を実施する
2
LightGBM で 5-Fold CV を実行し CV AUC を表示する
3
test.csv に対して予測し submission.csv を作成する
必須カラム: PassengerId / Survived(0 か 1)
必須カラム: PassengerId / Survived(0 か 1)
4
kaggle competitions submit コマンドで自動提出する
タスク3: 提出履歴の取得と実験ログ記録
1
提出スコアを API で取得して表示する
2
実験結果を JSONL ファイルに追記して記録する
📊 5-Fold CV AUC — 目標スコア感(参考値)
今回の特徴量(FamilySize / IsAlone 追加)で期待される各フォールドの AUC スコア
Fold 1
0.87
Fold 2
0.86
Fold 3
0.88
Fold 4
0.85
Fold 5
0.87
CV Mean (目標)
0.866
🏆
CV AUC 0.86 以上は Titanic の 上位25%圏内(Silverメダル圏)の目安です。FamilySize / IsAlone を追加することで Day 081 のベースライン(約 0.83)からスコアが改善します。
🗺️ 完全自動提出パイプライン図
Python スクリプト1本で「データ取得 → 学習 → 提出 → ログ記録」を完結させる
💡 ヒント
ヒント1
方向性
kaggle パッケージは pip install kaggle でインストール。~/.kaggle/kaggle.json が正しく配置されていれば kaggle competitions list でコンペ一覧が取得できます。Colab では from google.colab import files; files.upload() で JSON をアップロードできます。
ヒント2
アプローチ
- ダウンロード:
kaggle competitions download -c titanic -p ./data/ --unzip - 提出:
kaggle competitions submit -c titanic -f submission.csv -m "message" - Python から:
subprocess.run(["kaggle", "competitions", "submit", ...]) - FamilySize:
df['SibSp'] + df['Parch'] + 1
ヒント3
コード骨格
import subprocess, os os.makedirs('./data/titanic', exist_ok=True) # データダウンロード subprocess.run(['kaggle', 'competitions', 'download', '-c', 'titanic', '-p', './data/titanic/', '--unzip']) # FamilySize 特徴量 df['FamilySize'] = df['SibSp'] + df['Parch'] + 1 df['IsAlone'] = (df['FamilySize'] == 1).astype(int) # 自動提出 subprocess.run(['kaggle', 'competitions', 'submit', '-c', 'titanic', '-f', './submission.csv', '-m', 'lgbm-baseline-day087'])
✅ 模範解答
# ===== インストール(Colabでは実行が必要) ===== # !pip install kaggle lightgbm -q import os, subprocess, warnings, json import numpy as np import pandas as pd from sklearn.model_selection import StratifiedKFold from sklearn.metrics import roc_auc_score warnings.filterwarnings('ignore') # ━━━ タスク1: データダウンロード ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ os.makedirs('./data/titanic', exist_ok=True) subprocess.run([ 'kaggle', 'competitions', 'download', '-c', 'titanic', '-p', './data/titanic/', '--unzip' ], check=True) train = pd.read_csv('./data/titanic/train.csv') test = pd.read_csv('./data/titanic/test.csv') print(f"train: {train.shape}, test: {test.shape}") # ━━━ タスク2: 特徴量工学 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ def feature_engineering(df): df = df.copy() df['Sex'] = df['Sex'].map({'male': 0, 'female': 1}) df['Age'] = df['Age'].fillna(df['Age'].median()) df['Fare'] = df['Fare'].fillna(df['Fare'].median()) df['Embarked'] = df['Embarked'].fillna('S') df = pd.get_dummies(df, columns=['Embarked'], prefix='Emb') df['FamilySize'] = df['SibSp'] + df['Parch'] + 1 df['IsAlone'] = (df['FamilySize'] == 1).astype(int) return df features = ['Pclass', 'Sex', 'Age', 'Fare', 'SibSp', 'Parch', 'FamilySize', 'IsAlone', 'Emb_C', 'Emb_Q', 'Emb_S'] train_fe = feature_engineering(train) test_fe = feature_engineering(test) for col in features: if col not in test_fe.columns: test_fe[col] = 0 X = train_fe[features].values y = train['Survived'].values X_test = test_fe[features].values # ━━━ LightGBM 5-Fold CV ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import lightgbm as lgb params = { 'objective': 'binary', 'metric': 'auc', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.9, 'bagging_fraction': 0.8, 'bagging_freq': 5, 'verbosity': -1, 'random_state': 42, } skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) oof_preds = np.zeros(len(X)) test_preds = np.zeros(len(X_test)) fold_scores = [] for fold, (tr_idx, val_idx) in enumerate(skf.split(X, y)): X_tr, X_val = X[tr_idx], X[val_idx] y_tr, y_val = y[tr_idx], y[val_idx] model = lgb.train( params, lgb.Dataset(X_tr, label=y_tr), num_boost_round=500, valid_sets=[lgb.Dataset(X_val, label=y_val)], callbacks=[lgb.early_stopping(50, verbose=False), lgb.log_evaluation(period=-1)], ) val_pred = model.predict(X_val, num_iteration=model.best_iteration) oof_preds[val_idx] = val_pred test_preds += model.predict(X_test, num_iteration=model.best_iteration) / 5 auc = roc_auc_score(y_val, val_pred) fold_scores.append(auc) print(f" Fold {fold+1}: AUC = {auc:.4f}") cv_mean = np.mean(fold_scores) oof_auc = roc_auc_score(y, oof_preds) print(f"\nCV AUC: {cv_mean:.4f} | OOF AUC: {oof_auc:.4f}") # ━━━ submission.csv 作成 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ submission = pd.DataFrame({ 'PassengerId': test['PassengerId'], 'Survived': (test_preds >= 0.5).astype(int) }) submission.to_csv('./submission.csv', index=False) print(f"\nsubmission.csv: {submission.shape}") print(f"生存予測率: {submission['Survived'].mean():.2%}") # ━━━ 自動提出(実際に提出する場合はコメントを外す) ━━━━━━━━━━━━━ # subprocess.run(['kaggle', 'competitions', 'submit', # '-c', 'titanic', '-f', './submission.csv', # '-m', f'lgbm-5fold-cv{cv_mean:.4f}-day087']) # ━━━ 実験ログ記録 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ log = { 'date': '2026-07-07', 'day': 87, 'model': 'LightGBM', 'cv_auc': round(cv_mean, 4), 'oof_auc': round(oof_auc, 4), 'n_feat': len(features), 'message': f'lgbm-5fold-cv{cv_mean:.4f}', } with open('./experiment_log.jsonl', 'a') as f: f.write(json.dumps(log, ensure_ascii=False) + '\n') print("\n実験ログ:", json.dumps(log, indent=2, ensure_ascii=False))
🪜 Step-by-Step 解説
1Kaggle API の設定とデータ取得
$ pip install kaggle
$ mkdir -p ~/.kaggle
$ mv kaggle.json ~/.kaggle/
$ chmod 600 ~/.kaggle/kaggle.json # セキュリティ必須
# データダウンロード(-p: 保存先, --unzip: 自動解凍)
$ kaggle competitions download -c titanic -p ./data/titanic/ --unzip
$ mkdir -p ~/.kaggle
$ mv kaggle.json ~/.kaggle/
$ chmod 600 ~/.kaggle/kaggle.json # セキュリティ必須
# データダウンロード(-p: 保存先, --unzip: 自動解凍)
$ kaggle competitions download -c titanic -p ./data/titanic/ --unzip
📂
なぜ
--unzip が必要か? → Kaggle は ZIP 形式で配信します。--unzip がないと titanic.zip が残り、別途 unzip コマンドが必要になります。2FamilySize と IsAlone の意味
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1 # +1 は自分自身 df['IsAlone'] = (df['FamilySize'] == 1).astype(int)
| FamilySize | 意味 | 生存率の傾向 |
|---|---|---|
| 1(IsAlone=1) | 一人旅 | △ 中程度(孤立しやすい) |
| 2〜4 | 小家族 | ↑ 高い(助け合える) |
| 5〜7 | 大家族 | ↓ 低い(全員を避難させるのが困難) |
| 8+ | 超大家族 | ↓↓ 非常に低い |
この非線形な関係を LightGBM は木構造で自然に捉えます。線形回帰では表現が難しい特徴量です。
3OOF(Out-of-Fold)予測の仕組み
4提出コマンドとメッセージの書き方
$ kaggle competitions submit \
-c titanic \
-f ./submission.csv \
-m "lgbm-5fold-familysize-cv0.8660-day087"
-c titanic \
-f ./submission.csv \
-m "lgbm-5fold-familysize-cv0.8660-day087"
| フラグ | 意味 | ベストプラクティス |
|---|---|---|
-c | コンペ ID(URL の末尾) | titanic, house-prices-advanced 等 |
-f | 提出ファイルパス | 提出前に行数・カラムを必ずチェック |
-m | 提出メモ(Public LB に表示) | モデル名 + CV スコア + 何を試したかを含める |
5実験ログを JSONL で記録する
with open('./experiment_log.jsonl', 'a') as f: f.write(json.dumps(log) + '\n') # 後から DataFrame として読める df_log = pd.read_json('./experiment_log.jsonl', lines=True) df_log.sort_values('cv_auc', ascending=False)
💡
JSONL は「1行 = 1実験」の形式。後から
pd.read_json('log.jsonl', lines=True) で読み込めば「どの特徴量が効いたか」「CV と LB のギャップはどれくらいか」を比較できます。🧮 OOF(Out-of-Fold)の直感(文系向け)
📐
OOF とは:
5-Fold CV で「自分が学習に使われていないときに予測された値」を全フォールドで集めたものです。全 891 件について「自分自身を学習に使わずに予測した確率」が得られるので、より現実に近いスコアを計算できます。
5-Fold CV で「自分が学習に使われていないときに予測された値」を全フォールドで集めたものです。全 891 件について「自分自身を学習に使わずに予測した確率」が得られるので、より現実に近いスコアを計算できます。
| 評価方法 | 意味 | Kaggleでの用途 |
|---|---|---|
| CV AUC(各フォールドの平均) | 5回の検証の平均スコア | モデル改善の判断基準 |
| OOF AUC | 全データを疑似テストとして評価 | CV より安定した評価。LBとの相関が高い |
| Public LB スコア | Kaggle が評価する実際のスコア | 30% のテストデータで計算 |
| Private LB スコア | 最終的なランキングスコア | 残り 70% で計算(コンペ終了後公開) |
OOF AUC と Public LB の相関イメージ(Expert 以上が重視する理由)
🏆 Kaggleでの実践的な使い方
提出回数の戦略的な使い方
Titanic は1日5回まで提出できます。Expert 以上はこう使います:
| 提出回数 | 目的 | 何を確認するか |
|---|---|---|
| 1回目(早期) | ベースラインの把握 | CV との乖離を確認(0.02 以内なら CV 信頼 OK) |
| 2〜3回目(中盤) | 特徴量の効果検証 | 追加した特徴量が LB を改善しているか |
| 4〜5回目(終盤) | ファイナル選択 | CV が高い版 vs 安定版の2本を最終選択に残す |
自動提出スクリプト(再利用テンプレート)
# run_submit.py — コンペを変えても使い回せるテンプレート import subprocess, sys COMPETITION = "titanic" # コンペIDだけ変える SUBMISSION = "./submission.csv" MESSAGE = sys.argv[1] if len(sys.argv) > 1 else "auto-submit" result = subprocess.run([ 'kaggle', 'competitions', 'submit', '-c', COMPETITION, '-f', SUBMISSION, '-m', MESSAGE, ], capture_output=True, text=True) print(result.stdout) if result.returncode != 0: print("エラー:", result.stderr)
使い方: python run_submit.py "lgbm-cv0.87-familysize"
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
kaggle.json の配置場所を間違える |
パスの大文字・隠しディレクトリを見落とす | ~/.kaggle/kaggle.json(.kaggle ディレクトリが必要) |
chmod 600 を忘れる |
Unix のパーミッション設定を知らない | 600 = 自分だけ読み書き可。APIキー流出防止に必須 |
| test データでエンコード列が増減する | pd.get_dummies がデータ依存で列数が変わる |
全カラムを reindex か align で揃える |
| LB を提出して過学習させる | LB スコアを見て特徴量を選び続ける | CV を優先。LB への最適化は Private LB 崩れの原因 |
| 実験ログを取らない | 「覚えているはず」と思う | 3日後には何が効いたか必ず忘れる。JSONL で自動記録 |
🚀 次のステップ
- 発展:
kaggle kernels list --competition titanic --sort-by voteCountで上位ノートブックをダウンロードし、自分のモデルと比較する - 次回予告: Phase 3 最終テーマ「コンペ選定基準 — 自分に合ったコンペの見つけ方」(Day 088)
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: