📚 背景知識(読んでから問題へ)
🏆
Kaggleのコンペページには「何を・どうやって・何で評価するのか」が全て書いてあります。ページの読み方を知ることが、コンペ参加の最初の一歩です。
📋 コンペページの構成
Overview
コンペ概要・背景・評価指標・賞金・締切
Data
データの説明・ダウンロード・ファイル一覧
Notebooks
参加者が公開したノートブック(インサイトの宝庫)
Discussion
参加者の議論・有効な特徴量のヒント
Leaderboard
現在の順位 (Public LB)
Rules
参加規約・提出上限・チームサイズ制限
最初の5分でやること
- Overview タブ → 評価指標を確認(最重要)
- Data タブ → ファイル一覧・説明を確認
-
sample_submission.csvをダウンロード → 提出形式を確認 -
train.csvを shape / dtypes / describe で把握 - Rules タブ → 1日の提出上限・チームサイズを確認
📏 評価指標一覧
⚠️
評価指標を間違えると全ての努力が無駄になります。コンペ開始直後に Overview で必ず確認してください。
| 評価指標 | タスク | 意味 | 最適化の方向 | 対策 |
|---|---|---|---|---|
| RMSE | 回帰 | 予測誤差の二乗平均平方根 | 最小化 | そのまま学習 |
| RMSLE | 回帰(価格・量) | 対数変換後の RMSE | 最小化 | log1p(y) → 学習 → expm1 |
| MAE | 回帰 | 予測誤差の絶対値平均 | 最小化 | Huber Loss / Quantile |
| Log Loss | 2値分類 | 確率予測の誤差 | 最小化 | predict_proba 出力 |
| AUC-ROC | 2値分類 | ランキング精度 | 最大化 | predict_proba 出力 |
| F1 Score | 不均衡分類 | Precision × Recall のバランス | 最大化 | 閾値最適化 |
| MAP@K | 推薦 | 上位K件の精度 | 最大化 | ランキング最適化 |
📊 RMSE vs RMSLE — 誤差の捉え方の違い
住宅価格のような広範囲の値には RMSLE が適切です。なぜか可視化で確認しましょう。
RMSLE: 「10%の誤差」なら高額・低額問わず同じペナルティ。公平な評価。
RMSLE 実装
import numpy as np from sklearn.metrics import mean_squared_error def rmsle(y_true, y_pred): """Root Mean Squared Logarithmic Error""" y_pred = np.maximum(y_pred, 0) # 負の値をクリップ return np.sqrt(mean_squared_error( np.log1p(y_true), # log(1 + y_true) np.log1p(y_pred) # log(1 + y_pred) )) # RMSLE 最適化のための log1p 変換 y_log = np.log1p(y_train) # 学習時: y を変換 model.fit(X_train, y_log) preds_log = model.predict(X_test) preds_final = np.expm1(preds_log) # 予測後: 逆変換
評価指標別の RMSLE スコア感
House Prices コンペの参考スコア感(値は低いほど良い)
📄 提出形式(Submission Format)
sample_submission.csv を必ずダウンロードして確認します。これがそのまま提出フォーマットです。
典型的な提出形式
| タスク種別 | フォーマット例 | 値の種類 |
|---|---|---|
| 回帰(連続値) | Id, SalePrice |
float(例: 169000.0) |
| 2値分類 | PassengerId, Survived |
0 or 1 |
| 多クラス分類(確率) | Id, cat_0, cat_1, cat_2 |
確率値(合計≒1) |
| 推薦 Top-K | customer_id, product_ids |
スペース区切りのID列 |
正しい submission.csv の作り方
ベストプラクティス
import pandas as pd import numpy as np # ① sample_submission を読み込む sample_sub = pd.read_csv('sample_submission.csv') print(sample_sub.head()) # フォーマットを把握 print(sample_sub.columns.tolist()) # カラム名を確認 # ② test['Id'] を使って作成(行インデックスは使わない) submission = pd.DataFrame({ 'Id': test['Id'], # ← 必ず Id 列を使う 'SalePrice': preds_final # ← 予測値 }) # ③ バリデーション assert len(submission) == len(sample_sub), "行数が違います" assert not submission.isnull().any().any(), "NaN が含まれています" # ④ 保存 submission.to_csv('submission.csv', index=False) # index=False 必須 print(f"保存完了: {len(submission)} 行")
🏅 Public LB vs Private LB
| Public LB | Private LB | |
|---|---|---|
| 見えるタイミング | コンペ期間中(リアルタイム) | コンペ終了後(最終順位) |
| 使用データ | testデータの 約20〜50% | testデータの残り 約50〜80% |
| 信頼性 | 低(サンプルが少ない) | 高(これが本当の実力) |
| 注意点 | 過学習・シェイクアップの罠 | CVスコアと相関することが多い |
Public LB を追いすぎると Private LB で大幅ダウンする。CV スコアを信頼するのが鉄則。
🎯 問題
📝
シナリオ: House Prices コンペに参加。評価指標 = RMSLE、提出形式 =
Id, SalePrice(連続値)問題1: RMSLEとRMSEの違いを直感的に説明する
なぜ住宅価格にRMSLEが使われるのか、RMSEとの違いを直感的な言葉で説明してください。
問題2: submission.csv を作成する
import pandas as pd import numpy as np from sklearn.linear_model import Ridge train = pd.read_csv('train.csv') test = pd.read_csv('test.csv') sample_sub = pd.read_csv('sample_submission.csv') features = ['GrLivArea', 'BedroomAbvGr', 'FullBath'] X_train = train[features].fillna(0) y_train = train['SalePrice'] X_test = test[features].fillna(0) model = Ridge() model.fit(X_train, y_train) preds = model.predict(X_test) # ここから: submission.csv を作成してください
問題3: RMSLE 最適化のための log1p 変換
RMSLE を最適化するには、目的変数を log1p 変換してから学習し、予測後に逆変換します。コードを完成させてください。
# 問題3: log1p 変換を使って RMSLE を最適化するコードを書いてください # ヒント: np.log1p() でlog変換、np.expm1() で逆変換
💡 ヒント
ヒント1 — 方向性
RMSLEの「L」はLogarithmicの意味です。対数を取ることで、高額物件と低額物件の誤差を「割合」ベースで評価するようになります。「1000円の定食を100円外す」のと「10万円の宿泊費を1万円外す」のが同等(どちらも10%の誤差)という直感です。
ヒント2 — アプローチ
- 問題2:
sample_submission.csvと同じ形式のDataFrameを作成し、test['Id']と予測値を結合する - 問題3:
np.log1p(y_train)でlog変換し、予測後にnp.expm1(preds)で逆変換する
ヒント3 — コード骨格
# 問題2 submission = pd.DataFrame({ 'Id': test['Id'], 'SalePrice': preds }) submission.to_csv('submission.csv', index=False) # 問題3 y_log = np.log1p(y_train) # log変換 model.fit(X_train, y_log) preds_log = model.predict(X_test) preds_final = np.expm1(preds_log) # 逆変換
✅ 模範解答
問題1: RMSLEとRMSEの違い
💬
RMSE: 予測値と実際値の差の大きさを直接測る。高額物件(5000万円の誤差)と低額物件(500万円の誤差)を同等に扱わず、大きな絶対誤差がスコアを支配する。
RMSLE: 予測値と実際値を対数変換してからRMSEを計算。「相対誤差(割合)」ベースで評価するため、高額・低額問わず10%の誤差は同じペナルティ。
住宅価格にRMSLEが適切な理由: 住宅価格は数百万〜数億円と広範囲にわたるため、RMSEだと高額物件の大きな絶対誤差がスコアを支配してしまう。RMSLEなら「相対的な精度」を公平に評価できる。
RMSLE: 予測値と実際値を対数変換してからRMSEを計算。「相対誤差(割合)」ベースで評価するため、高額・低額問わず10%の誤差は同じペナルティ。
住宅価格にRMSLEが適切な理由: 住宅価格は数百万〜数億円と広範囲にわたるため、RMSEだと高額物件の大きな絶対誤差がスコアを支配してしまう。RMSLEなら「相対的な精度」を公平に評価できる。
問題2: submission.csv の作成
問題2 解答
正解パターン
# ... (上のコードの続き) # submission.csv の作成 submission = pd.DataFrame({ 'Id': test['Id'], # test の Id 列をそのまま使う 'SalePrice': preds # 予測値 }) # 確認 print(submission.shape) # (1459, 2) print(submission.head()) print(f"予測値の範囲: {preds.min():.0f} 〜 {preds.max():.0f}") # 負の値チェック(住宅価格が負はあり得ない) assert (preds > 0).all(), "負の予測値が含まれています!" submission.to_csv('submission.csv', index=False) print("submission.csv を保存しました")
問題3: RMSLE 最適化(log1p 変換)
問題3 解答
log1p 変換パターン
import numpy as np from sklearn.metrics import mean_squared_error def rmsle(y_true, y_pred): y_pred = np.maximum(y_pred, 0) return np.sqrt(mean_squared_error(np.log1p(y_true), np.log1p(y_pred))) # ─── RMSE で学習(基準)─── model_rmse = Ridge() model_rmse.fit(X_train, y_train) preds_rmse = model_rmse.predict(X_test) # ─── log1p 変換で学習(RMSLE 最適化)─── y_log = np.log1p(y_train) # log(1 + y) ← y=0 でも安全 model_rmsle = Ridge() model_rmsle.fit(X_train, y_log) preds_log = model_rmsle.predict(X_test) preds_final = np.expm1(preds_log) # exp(pred) - 1 ← log1p の逆変換 # 訓練データで効果確認 preds_train_rmse = model_rmse.predict(X_train) preds_train_log = np.expm1(model_rmsle.predict(X_train)) print(f"RMSE モデルの RMSLE: {rmsle(y_train, preds_train_rmse):.4f}") print(f"RMSLE モデルの RMSLE: {rmsle(y_train, preds_train_log):.4f}") # → log変換モデルの方がRMSLEスコアが低い(良い)はず # 提出 submission = pd.DataFrame({'Id': test['Id'], 'SalePrice': preds_final}) submission.to_csv('submission.csv', index=False)
🪜 Step-by-Step: 初回提出までの流れ
1
コンペページを読む(10分)
Overview → 評価指標 / Rules → 提出上限・チームサイズ / Data → ファイル一覧確認
Overview → 評価指標 / Rules → 提出上限・チームサイズ / Data → ファイル一覧確認
↓
2
データを探索する(30分)
train/test の shape / dtypes / describe / 欠損値の確認 / 目的変数の分布確認
train/test の shape / dtypes / describe / 欠損値の確認 / 目的変数の分布確認
↓
3
ベースラインを作る(1時間)
シンプルなモデルで初回提出 → Public LB スコアを把握(改善の基準点)
シンプルなモデルで初回提出 → Public LB スコアを把握(改善の基準点)
↓
4
公開Notebookを読む(1時間)
高スコアのノートブックを精読 → 有効な特徴量・前処理のアイデアを収集
高スコアのノートブックを精読 → 有効な特徴量・前処理のアイデアを収集
↓
5
Discussion を確認(30分)
リーク・EDA・有効な特徴量のヒントを拾う。上位の人の考え方を学ぶ
リーク・EDA・有効な特徴量のヒントを拾う。上位の人の考え方を学ぶ
🔍 提出前バリデーション
def validate_submission(sub_df, sample_sub_df): """提出ファイルの検証""" # カラム名チェック assert list(sub_df.columns) == list(sample_sub_df.columns), \ f"カラム名が違います: {sub_df.columns.tolist()}" # 行数チェック assert len(sub_df) == len(sample_sub_df), \ f"行数が違います: {len(sub_df)} vs {len(sample_sub_df)}" # Id の一致チェック assert (sub_df['Id'].values == sample_sub_df['Id'].values).all(), \ "Id の順序・内容が sample_submission と一致しません" # NaN チェック assert not sub_df.isnull().any().any(), "NaN が含まれています" print("✅ 提出ファイルの検証OK") validate_submission(submission, sample_sub)
⚡ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| RMSE でチューニングして RMSLE で提出 | 評価指標を後から気付く | コンペ開始直後に Overview で確認。log1p 変換で揃える |
| submission.csv の列順を間違える | sample_submission を確認しない | sample_submission と全く同じカラム名・順序で作成 |
| テストデータの Id に行インデックスを使う | Id は連番だと思い込む | 必ず test['Id'] を使う(行インデックスでなくId列) |
| Public LB スコアだけを信じる | 見えるスコアを最適化したくなる | Private LB で大幅ダウンする危険。CV スコアを重視 |
| 提出ファイルに NaN が混入する | 前処理で欠損値が残る | 提出前に submission.isnull().sum() で確認 |
to_csv で index=True のまま保存 |
デフォルト値を意識しない | 必ず index=False を指定する |
🚀 次のステップ
- 発展: Kaggle Notebooks タブで上位ノートブックを精読する手順(Day 079)
- 実践: House Prices コンペに実際に登録し、ベースラインを提出してみる
- 次回予告 (Day 079): Kaggle ノートブックの読み方 — 上位ノートブック精読の手順