Spaces:
Running on Zero
Running on Zero
File size: 7,595 Bytes
917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df f4f5e62 917c2df | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | """
Run this script once to train the ensemble and save model artifacts.
Usage:
1. Download train.csv from Kaggle Housing Prices competition
2. Place it in the data/ folder
3. Run: python -m ml.export_model
"""
import os
import numpy as np
import pandas as pd
import joblib
from sklearn.model_selection import train_test_split, GridSearchCV, KFold
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import GradientBoostingRegressor, StackingRegressor
from sklearn.linear_model import SGDRegressor
from sklearn.kernel_ridge import KernelRidge
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error, r2_score
from catboost import CatBoostRegressor
from ml.preprocessing import (
CORE_FEATURES,
ManualFeatureProcessor,
build_feature_pipeline,
outlier_removal,
)
ARTIFACTS_DIR = os.path.join(os.path.dirname(__file__), "artifacts")
DATA_PATH = os.path.join(os.path.dirname(__file__), "..", "data", "train.csv")
def evaluate(preds_log, y_log, name):
rmsle = np.sqrt(mean_squared_error(preds_log, y_log))
preds, y = np.expm1(preds_log), np.expm1(y_log)
mae = mean_absolute_error(preds, y)
mape = mean_absolute_percentage_error(y, preds)
r2 = r2_score(y_log, preds_log)
print(f" {name:40s} RMSLE={rmsle:.4f} MAE=${mae:,.0f} MAPE={mape:.2%} R2={r2:.4f}")
return {"rmsle": rmsle, "mae": mae, "mape": mape, "r2": r2}
def train():
print("Loading data...")
home_data = pd.read_csv(DATA_PATH)
home_data = outlier_removal(home_data)
y = np.log1p(home_data["SalePrice"])
X = home_data[CORE_FEATURES].copy()
# ββ 80/20 split for quick validation ββββββββββββββββββββββββββββββββββββββ
train_X_raw, val_X_raw, train_y, val_y = train_test_split(X, y, random_state=1)
manual_proc_split = ManualFeatureProcessor()
manual_proc_split.fit(train_X_raw)
train_X = manual_proc_split.transform(train_X_raw)
val_X = manual_proc_split.transform(val_X_raw)
feature_pipeline = build_feature_pipeline()
# ββ Model 1: Gradient Boosting βββββββββββββββββββββββββββββββββββββββββββββ
print("\nTraining GBR...")
gbr_pipeline = Pipeline([
("features", feature_pipeline),
("regressor", GradientBoostingRegressor(random_state=1, verbose=0)),
])
gbr_grid = GridSearchCV(
gbr_pipeline,
param_grid={
"regressor__n_estimators": [5000],
"regressor__learning_rate": [0.03],
"regressor__min_samples_leaf": [1],
"regressor__min_samples_split": [2],
"regressor__max_depth": [3],
"regressor__subsample": [0.83],
"regressor__max_features": ["sqrt"],
"regressor__loss": ["huber"],
},
cv=5, scoring="neg_mean_squared_error", n_jobs=-1, verbose=0,
)
gbr_grid.fit(train_X, train_y)
gbr_best = gbr_grid.best_estimator_
metrics_gbr = evaluate(gbr_best.predict(val_X), val_y, "GBR")
# ββ Model 2: CatBoost ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
print("Training CatBoost...")
cat_pipeline = Pipeline([
("features", build_feature_pipeline()),
("regressor", CatBoostRegressor(random_state=1, verbose=0, loss_function="RMSE")),
])
cat_grid = GridSearchCV(
cat_pipeline,
param_grid={
"regressor__n_estimators": [1900],
"regressor__learning_rate": [0.02],
"regressor__depth": [6],
"regressor__l2_leaf_reg": [3],
"regressor__subsample": [0.7],
"regressor__colsample_bylevel": [0.7],
},
cv=5, scoring="neg_mean_squared_error", n_jobs=-1, verbose=0,
)
cat_grid.fit(train_X, train_y)
cat_best = cat_grid.best_estimator_
metrics_cat = evaluate(cat_best.predict(val_X), val_y, "CatBoost")
# ββ Model 3: Kernel Ridge ββββββββββββββββββββββββββββββββββββββββββββββββββ
print("Training KernelRidge...")
krr_pipeline = Pipeline([
("features", build_feature_pipeline()),
("scaler", StandardScaler()),
("krr", KernelRidge(kernel="rbf")),
])
krr_grid = GridSearchCV(
krr_pipeline,
param_grid={"krr__alpha": [0.0003], "krr__gamma": [0.0001]},
cv=5, scoring="neg_mean_squared_error", n_jobs=-1, verbose=0,
)
krr_grid.fit(train_X, train_y)
krr_best = krr_grid.best_estimator_
metrics_krr = evaluate(krr_best.predict(val_X), val_y, "KernelRidge")
# ββ Naive baseline (predict train-set mean price for everyone) βββββββββββββ
baseline_pred = np.full_like(val_y, train_y.mean())
metrics_baseline = evaluate(baseline_pred, val_y, "Baseline (mean price)")
# ββ Stacking Meta-Model ββββββββββββββββββββββββββββββββββββββββββββββββββββ
print("Training Stacking ensemble...")
kf = KFold(n_splits=5, shuffle=True, random_state=1)
estimators = [("gbr", gbr_best), ("cat", cat_best), ("krr", krr_best)]
sgd_meta = SGDRegressor(
loss="epsilon_insensitive", epsilon=0.0, penalty="l2",
learning_rate="invscaling", eta0=0.01, power_t=0.24,
alpha=0.001, random_state=1,
)
stack = StackingRegressor(
estimators=estimators,
final_estimator=make_pipeline(StandardScaler(), sgd_meta),
cv=kf, n_jobs=-1, passthrough=False, verbose=0,
)
stack.fit(train_X, train_y)
metrics_stack = evaluate(stack.predict(val_X), val_y, "Stacking (GBR + CAT + KRR)")
# ββ Retrain on full data βββββββββββββββββββββββββββββββββββββββββββββββββββ
print("\nRetraining on full dataset...")
manual_proc_full = ManualFeatureProcessor()
manual_proc_full.fit(X)
X_full = manual_proc_full.transform(X)
for name, model in estimators:
print(f" Fitting {name}...")
model.fit(X_full, y)
stack.fit(X_full, y)
# ββ Save artifacts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
os.makedirs(ARTIFACTS_DIR, exist_ok=True)
joblib.dump(manual_proc_full, os.path.join(ARTIFACTS_DIR, "manual_processor.joblib"))
joblib.dump(stack, os.path.join(ARTIFACTS_DIR, "stack.joblib"))
joblib.dump(CORE_FEATURES, os.path.join(ARTIFACTS_DIR, "core_features.joblib"))
import json
with open(os.path.join(ARTIFACTS_DIR, "metrics.json"), "w") as f:
json.dump({
"baseline_mean_price": metrics_baseline,
"gbr": metrics_gbr,
"catboost": metrics_cat,
"kernel_ridge": metrics_krr,
"stacking": metrics_stack,
}, f, indent=2)
print("\nArtifacts saved to ml/artifacts/")
print(" manual_processor.joblib")
print(" stack.joblib")
print(" core_features.joblib")
print(" metrics.json")
if __name__ == "__main__":
train()
|