from __future__ import annotations import json from pathlib import Path import joblib from sklearn.datasets import load_iris from sklearn.model_selection import GridSearchCV from sklearn.neighbors import KNeighborsClassifier from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler ARTIFACT_PATH = Path(__file__).with_name("model.joblib") METRICS_PATH = Path(__file__).with_name("metrics.json") def train_and_save(artifact_path: Path = ARTIFACT_PATH) -> dict: iris = load_iris(as_frame=True) X = iris.data y = iris.target target_names = [str(name) for name in iris.target_names] feature_names = [str(name) for name in iris.feature_names] pipeline = Pipeline( steps=[ ("scaler", StandardScaler()), ("knn", KNeighborsClassifier()), ] ) param_grid = { "knn__n_neighbors": list(range(1, 21)), "knn__weights": ["uniform", "distance"], "knn__p": [1, 2], } search = GridSearchCV( estimator=pipeline, param_grid=param_grid, cv=5, scoring="accuracy", n_jobs=-1, refit=True, ) search.fit(X, y) best_model = search.best_estimator_ joblib.dump( { "model": best_model, "target_names": target_names, "feature_names": feature_names, }, artifact_path, ) metrics = { "cv_best_accuracy": float(search.best_score_), "best_params": search.best_params_, } METRICS_PATH.write_text(json.dumps(metrics, indent=2), encoding="utf-8") return metrics if __name__ == "__main__": metrics = train_and_save() print(f"Saved model to: {ARTIFACT_PATH}") print(json.dumps(metrics, indent=2))