{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LizyML Widget Tutorial — Regression\n",
    "\n",
    "This tutorial demonstrates using LizyML Widget for a **regression** task\n",
    "with the [California Housing](https://scikit-learn.org/stable/datasets/real_world.html#california-housing-dataset) dataset.\n",
    "\n",
    "You will learn:\n",
    "1. Loading real-world data into the widget\n",
    "2. Reviewing auto-detected settings\n",
    "3. Configuring and running Fit\n",
    "4. Reviewing regression-specific metrics and plots\n",
    "5. Hyperparameter tuning\n",
    "6. Running inference on new data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0. Installation\n",
    "\n",
    "```bash\n",
    "pip install lizyml-widget lizyml[plots,tuning,calibration,explain]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Load the California Housing Dataset\n",
    "\n",
    "This dataset contains 20,640 samples with 8 features describing California\n",
    "housing block groups. The target is the median house value (in $100,000s)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sklearn.datasets import fetch_california_housing\n",
    "\n",
    "data = fetch_california_housing(as_frame=True)\n",
    "df = data.frame\n",
    "print(f\"Shape: {df.shape}\")\n",
    "print(f\"Target: MedHouseVal (median house value in $100k)\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Launch the Widget\n",
    "\n",
    "Create a widget instance, load the data, and display it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from lizyml_widget import LizyWidget\n",
    "\n",
    "w = LizyWidget()\n",
    "w.load(df, target=\"MedHouseVal\")\n",
    "w"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Data Tab — Auto-Detection\n",
    "\n",
    "The widget auto-detects:\n",
    "- **Task**: `regression` (continuous target values)\n",
    "- **CV**: `kfold` (default for regression)\n",
    "- **Columns**: All 8 features included"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"Task:     {w.task}\")\n",
    "print(f\"CV:       {w.cv_method} ({w.cv_n_splits} folds)\")\n",
    "print(f\"Shape:    {w.df_shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Config — Model Configuration\n",
    "\n",
    "Set model hyperparameters. For regression, we use typical LightGBM settings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.set_config({\n",
    "    \"model\": {\n",
    "        \"name\": \"lgbm\",\n",
    "        \"params\": {\n",
    "            \"n_estimators\": 500,\n",
    "            \"learning_rate\": 0.05,\n",
    "            \"max_depth\": 6,\n",
    "        },\n",
    "    },\n",
    "    \"training\": {\n",
    "        \"seed\": 42,\n",
    "        \"early_stopping\": {\"enabled\": True, \"rounds\": 50},\n",
    "    },\n",
    "    \"evaluation\": {\n",
    "        \"metrics\": [\"rmse\", \"mae\", \"r2\"],\n",
    "    },\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Run Fit\n",
    "\n",
    "Train the model with cross-validation. Progress is displayed in the widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.fit()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Results — Regression Metrics & Plots\n",
    "\n",
    "After fitting, view metrics in the Results tab. Key regression metrics:\n",
    "- **RMSE** — Root Mean Squared Error\n",
    "- **MAE** — Mean Absolute Error\n",
    "- **R²** — Coefficient of Determination\n",
    "\n",
    "Regression-specific plots:\n",
    "- **Residuals** — Predicted vs actual residuals\n",
    "- **OOF Distribution** — Out-of-fold prediction distribution\n",
    "- **Feature Importance** — Split, Gain, and SHAP variants"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "summary = w.get_fit_summary()\n",
    "if summary:\n",
    "    print(f\"Fold count: {summary.fold_count}\")\n",
    "    print(f\"Metrics:    {summary.metrics}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Tune — Hyperparameter Optimization\n",
    "\n",
    "Use Optuna to search for optimal hyperparameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.tune()\n",
    "\n",
    "tune_summary = w.get_tune_summary()\n",
    "if tune_summary:\n",
    "    print(f\"Best score:  {tune_summary.best_score:.4f}\")\n",
    "    print(f\"Metric:      {tune_summary.metric_name} ({tune_summary.direction})\")\n",
    "    print(f\"Best params: {tune_summary.best_params}\")\n",
    "    print(f\"Trials:      {len(tune_summary.trials)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. Inference — Predict on New Data\n",
    "\n",
    "Use the trained model to predict housing values for new samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use a subset of the original data as \"new\" data for demonstration\n",
    "df_test = df.drop(columns=[\"MedHouseVal\"]).tail(10)\n",
    "\n",
    "result = w.predict(df_test)\n",
    "if result:\n",
    "    print(f\"Predictions shape: {result.predictions.shape}\")\n",
    "    result.predictions.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 9. Save & Load Config\n",
    "\n",
    "Save the current configuration for reproducibility."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Save config\n",
    "w.save_config(\"regression_config.yaml\")\n",
    "\n",
    "# To load in another session:\n",
    "# w2 = LizyWidget()\n",
    "# w2.load(df, target=\"MedHouseVal\")\n",
    "# w2.load_config(\"regression_config.yaml\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 10. Export Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Export standalone training code (no LizyML dependency needed)\n",
    "export_path = w.export_code(\"./exported_code\")\n",
    "print(f\"Code exported to: {export_path}\")\n",
    "print(\"Generated files:\")\n",
    "for f in sorted(export_path.rglob(\"*\")):\n",
    "    if f.is_file():\n",
    "        print(f\"  {f.relative_to(export_path)}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
