忍者ブログ
統計、機械学習、AIを学んでいきたいと思います。 お役に立てば幸いです。

【Kaggle挑戦記】House Prices #1:予測対象は「価格」。回帰モデルによる住宅見積もり

1. 新たな戦場:House Prices - Advanced Regression Techniques

Spaceship Titanicを終え、次に挑むのは「住宅価格予測」です。 アイオワ州エイムズにある住宅のスペックから、その販売価格(SalePrice)を予測します。 前回の「転送されたか否か(0/1)」の分類とは異なり、今回は具体的な数値を当てる「回帰(Regression)」問題に挑みます。

2. 「分類」と「回帰」の決定的な違い

エンジニアとして、まずは評価指標を頭に叩き込みます。出力型が根本から変わるため、デバッグの指標も切り替える必要があります。

  • ターゲット: Boolean(生存/死亡)から Float(住宅価格)へ。 「0か1か」のラベルではなく、連続的な数値を予測します。
  • 評価指標: RMSE(Root Mean Squared Error:平均平方二乗誤差)。 「何人当たったか」ではなく、予測価格と実際の価格の「ズレ(誤差)」を評価します。
  • モデル: LGBMClassifier ではなく、回帰専用の LGBMRegressor を使用します。

3. 設計思想:なぜ「最小二乗法」ではなく「決定木」なのか

回帰といえば「最小二乗法(線形回帰)」で一本の直線を引くイメージが強いですが、本攻略では現代的なLightGBM(決定木モデル)を採用します。

  • 伝統的な回帰(最小二乗法): 「面積が2倍なら価格も2倍」といった単純な比例関係に強いが、市場の複雑な歪みに弱い。
  • 現代的な回帰(LightGBM): 「築年数が古くても、リフォーム済みなら高値」といった、条件の組み合わせ(非線形な関係)を数千もの分岐でデバッグし、多角形的に価格を近似していきます。

住宅市場の「不連続な境界線(このエリアに入った瞬間に価格が跳ね上がる、など)」を捉えるには、決定木によるアプローチが極めて有効です。

4. 本アプローチの設計図

■ 今回使う特徴量(数値データに限定)

79個のカラムのうち、初回は「数値データ(int/float)」のみを抽出して投入します。 敷地面積(LotArea)、築年(YearBuilt)、1階の広さ(1stFlrSF)、バスルームの数(FullBath)などが含まれます。文字列(立地など)は一旦除外します。

■ 指標:二乗誤差の最小化

本コンペのゴールは、二乗誤差(の平均)を最小化することです。 誤差(予測 - 実測)を二乗することで、大きな予測ミスに対して指数関数的に厳しいペナルティを課し、モデルに「大外れを出すな」と教育します。 ※最終スコアは「対数をとった後のRMSE」になりますが、まずは生の数値で誤差を削ります。

5. 【初陣】回帰ベースライン・ソースコード

import pandas as pd
import numpy as np
import lightgbm as lgb

# 1. データの読み込み
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# 2. ターゲットの設定
y_train = train['SalePrice']
# 数値データのみを抽出し、IDとターゲットを除外
X_train = train.select_dtypes(include=[np.number]).drop(['Id', 'SalePrice'], axis=1)
X_test = test.select_dtypes(include=[np.number]).drop(['Id'], axis=1)

# 3. 欠損値の補完
# 回帰問題の初期デバッグとして中央値(median)で埋める
X_train = X_train.fillna(X_train.median())
X_test = X_test.fillna(X_test.median())

# 4. 回帰モデルの構築
# 二乗誤差の最小化(regression)を目的関数に設定
model = lgb.LGBMRegressor(
    objective='regression',
    n_estimators=1000, 
    learning_rate=0.05,
    random_state=1
)

# 5. 学習
model.fit(X_train, y_train)

# 6. 予測(出力は具体的なドル建て価格の配列)
predictions = model.predict(X_test)

# 7. 提出用ファイルの作成
output = pd.DataFrame({'Id': test['Id'], 'SalePrice': predictions})
output.to_csv('submission_v1_baseline.csv', index=False)

print("✅ LightGBM Regressor baseline trained.")
print(f"Sample Predictions: {predictions[:5]}")

6. 実行結果のデバッグ:スコア 0.14679 の意味

Macのターミナルに出力された結果を解読します。

[LightGBM] [Info] Start training from score 180921.195890
Sample Predictions: [124527.61, 154677.30, 183652.70, ...]
Score: 0.14679

この 0.14679 というスコアは、ざっくり言うと「平均して14〜15%程度の見積もり誤差がある」状態を指します。

  • 0.14〜0.15(現在): 数値データのみの「とりあえず動くシステム」。
  • 0.12付近: 文字列データ(カテゴリ変数)を適切に処理した「実用レベル」。
  • 0.10以下: 上位ランカー。高度な特徴量生成とアンサンブルが必要な「プロの仕事」。

文字列データを一切使わず、数値のみでこの数値が出たのは、かなり幸先の良いスタートと言えます。

7. まとめ:次なる一歩

数値データだけで土俵に立ちましたが、まだ以下の「伸び代」が残っています。

  1. 無視された文字列データ: 立地(Neighborhood)などの、価格に直結する重要な情報がまだ「コメントアウト」されている状態です。
  2. 価格の歪み: 100万ドルの家と10万ドルの家では、同じ1万ドルのミスでも意味が違います。これを比率で評価させる「対数変換」の導入が必要です。

一本の直線を引くのではなく、数千の分岐で見積もりを研ぎ澄ます。15%の誤差を削る、新たな戦いの始まり。


PR