{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Doctor Recommendations Quickstart\n", "\n", "This notebook shows how to get `cpd doctor` recommendations, fall back to a bundled snapshot when live CLI execution is unavailable, and run a recommended pipeline in Python." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "import subprocess\n", "from pathlib import Path\n", "\n", "import numpy as np\n", "import cpd\n", "\n", "try:\n", " import matplotlib.pyplot as plt\n", " HAS_MATPLOTLIB = True\n", "except ImportError:\n", " HAS_MATPLOTLIB = False\n", " print(\"matplotlib is optional. Install with: python -m pip install matplotlib\")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Build deterministic seasonal + trend + outlier signal and save CSV for CLI interop\n", "rng = np.random.default_rng(2028)\n", "t = np.arange(360, dtype=np.float64)\n", "seasonal = 6.0 * np.sin(2.0 * np.pi * t / 30.0)\n", "trend = 0.03 * t\n", "level_shift = np.where(t >= 190.0, 7.5, 0.0)\n", "signal = 80.0 + seasonal + trend + level_shift + rng.normal(0.0, 1.3, size=t.shape[0])\n", "for idx in (55, 140, 265, 315):\n", " signal[idx] += 10.0\n", "\n", "notebook_data_dir = Path(\"/Users/admin/Documents/Work/claude-doctor-changepoint/cpd/python/examples/notebooks/data\")\n", "notebook_data_dir.mkdir(parents=True, exist_ok=True)\n", "doctor_input_csv = notebook_data_dir / \"doctor_series.csv\"\n", "np.savetxt(doctor_input_csv, signal.reshape(-1, 1), delimiter=\",\")\n", "doctor_input_csv\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Attempt live doctor CLI recommendation generation\n", "manifest_path = Path(\"/Users/admin/Documents/Work/claude-doctor-changepoint/cpd/Cargo.toml\")\n", "live_output_path = notebook_data_dir / \"doctor_recommendations_live.json\"\n", "cmd = [\n", " \"cargo\",\n", " \"run\",\n", " \"--manifest-path\",\n", " str(manifest_path),\n", " \"-p\",\n", " \"cpd-cli\",\n", " \"--\",\n", " \"doctor\",\n", " \"--input\",\n", " str(doctor_input_csv),\n", " \"--objective\",\n", " \"balanced\",\n", " \"--min-confidence\",\n", " \"0.2\",\n", " \"--output\",\n", " str(live_output_path),\n", "]\n", "\n", "doctor_payload = None\n", "doctor_source = None\n", "doctor_error = None\n", "\n", "try:\n", " completed = subprocess.run(cmd, check=True, capture_output=True, text=True)\n", " doctor_payload = json.loads(live_output_path.read_text(encoding=\"utf-8\"))\n", " doctor_source = f\"live_cli ({live_output_path})\"\n", " print(\"Live doctor command succeeded.\")\n", " if completed.stdout.strip():\n", " print(completed.stdout.strip())\n", "except Exception as exc:\n", " doctor_error = str(exc)\n", " print(\"Live doctor command unavailable; will use fallback snapshot.\")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Fallback snapshot path when live CLI is unavailable\n", "snapshot_path = Path(\"/Users/admin/Documents/Work/claude-doctor-changepoint/cpd/python/examples/notebooks/data/doctor_recommendations_snapshot.json\")\n", "if doctor_payload is None:\n", " doctor_payload = json.loads(snapshot_path.read_text(encoding=\"utf-8\"))\n", " doctor_source = f\"snapshot ({snapshot_path})\"\n", "\n", "print(\"Recommendation source:\", doctor_source)\n", "if doctor_error:\n", " print(\"Live CLI error:\", doctor_error)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Inspect top recommendations\n", "recommendations = doctor_payload.get(\"recommendations\", [])\n", "if not recommendations:\n", " raise RuntimeError(\"Doctor output did not include any recommendations\")\n", "\n", "for rec in recommendations[:3]:\n", " print(\n", " f\"rank={rec['rank']} confidence={rec['confidence']:.3f} \"\n", " f\"detector={rec['pipeline']['detector']} cost={rec['pipeline']['cost']}\"\n", " )\n", " if rec[\"warnings\"]:\n", " print(\" warnings:\", \"; \".join(rec[\"warnings\"]))\n", " print(\" summary:\", rec[\"explanation\"][\"summary\"])\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Execute top recommended pipeline in Python\n", "top_pipeline = recommendations[0][\"pipeline\"]\n", "doctor_result = cpd.detect_offline(signal, pipeline=top_pipeline, repro_mode=\"balanced\")\n", "print(\"top pipeline breakpoints:\", doctor_result.breakpoints)\n", "print(\"algorithm:\", doctor_result.diagnostics.algorithm)\n", "print(\"cost_model:\", doctor_result.diagnostics.cost_model)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Optional: visualize the signal and selected breakpoints\n", "if HAS_MATPLOTLIB:\n", " fig, ax = plt.subplots(figsize=(12, 4))\n", " ax.plot(signal, color=\"black\", linewidth=1.2, alpha=0.85)\n", " for cp in [bp for bp in doctor_result.breakpoints if bp < len(signal)]:\n", " ax.axvline(cp, color=\"tab:red\", linestyle=\"--\", linewidth=1.5, alpha=0.9)\n", " ax.set_title(\"Doctor-selected pipeline result\")\n", " ax.set_xlabel(\"sample\")\n", " ax.set_ylabel(\"value\")\n", " plt.show()\n", "else:\n", " print(\"Skipping plot (matplotlib not installed).\")\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.9" } }, "nbformat": 4, "nbformat_minor": 5 }