{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dd36cef2-4feb-44ed-900e-0fa6f75d74bd",
   "metadata": {},
   "source": [
    "**Цель задачи:**  \n",
    "Продемонстрировать применение метода **Comparing anomaly detection algorithms for outlier detection on toy datasets** для обнаружения аномалий в данных на основе их локальной плотности.  \n",
    "\n",
    "1. **Использовать** несколько алгоритмов из scikit-learn (`LocalOutlierFactor, IsolationForest, OneClassSVM, EllipticEnvelope.`).  \n",
    "2. **Протестировать** на двух типах данных:  \n",
    "   - **Сгенерированный датасет**: `make_moons` плюс сгенерированные вбросы. \n",
    "   - **Реальный датасет**: annthyroid (аномалии в медицинских данных) из openml.org.  \n",
    "3. **Сравнить** результаты работы алгоритмов (визуализация границ решений для 2D‑случая, метрики классификации), проанализировать, какие типы выбросов лучше обнаруживает каждый метод, и интерпретировать причины различий.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "00c0181a-607d-4eca-a7b9-dc316986de79",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 681240 characters]",
      "text/plain": [
       "<Figure size 1400x1250 with 25 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Authors: The scikit-learn developers\n",
    "# SPDX-License-Identifier: BSD-3-Clause\n",
    "\n",
    "import time\n",
    "\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "from sklearn import svm\n",
    "from sklearn.covariance import EllipticEnvelope\n",
    "from sklearn.datasets import make_blobs, make_moons\n",
    "from sklearn.ensemble import IsolationForest\n",
    "from sklearn.kernel_approximation import Nystroem\n",
    "from sklearn.linear_model import SGDOneClassSVM\n",
    "from sklearn.neighbors import LocalOutlierFactor\n",
    "from sklearn.pipeline import make_pipeline\n",
    "\n",
    "matplotlib.rcParams[\"contour.negative_linestyle\"] = \"solid\"\n",
    "\n",
    "# Example settings\n",
    "n_samples = 300\n",
    "outliers_fraction = 0.15\n",
    "n_outliers = int(outliers_fraction * n_samples)\n",
    "n_inliers = n_samples - n_outliers\n",
    "\n",
    "# define outlier/anomaly detection methods to be compared.\n",
    "# the SGDOneClassSVM must be used in a pipeline with a kernel approximation\n",
    "# to give similar results to the OneClassSVM\n",
    "anomaly_algorithms = [\n",
    "    (\n",
    "        \"Robust covariance\",\n",
    "        EllipticEnvelope(contamination=outliers_fraction, random_state=42),\n",
    "    ),\n",
    "    (\"One-Class SVM\", svm.OneClassSVM(nu=outliers_fraction, kernel=\"rbf\", gamma=0.1)),\n",
    "    (\n",
    "        \"One-Class SVM (SGD)\",\n",
    "        make_pipeline(\n",
    "            Nystroem(gamma=0.1, random_state=42, n_components=150),\n",
    "            SGDOneClassSVM(\n",
    "                nu=outliers_fraction,\n",
    "                shuffle=True,\n",
    "                fit_intercept=True,\n",
    "                random_state=42,\n",
    "                tol=1e-6,\n",
    "            ),\n",
    "        ),\n",
    "    ),\n",
    "    (\n",
    "        \"Isolation Forest\",\n",
    "        IsolationForest(contamination=outliers_fraction, random_state=42),\n",
    "    ),\n",
    "    (\n",
    "        \"Local Outlier Factor\",\n",
    "        LocalOutlierFactor(n_neighbors=35, contamination=outliers_fraction),\n",
    "    ),\n",
    "]\n",
    "\n",
    "# Define datasets\n",
    "blobs_params = dict(random_state=0, n_samples=n_inliers, n_features=2)\n",
    "datasets = [\n",
    "    make_blobs(centers=[[0, 0], [0, 0]], cluster_std=0.5, **blobs_params)[0],\n",
    "    make_blobs(centers=[[2, 2], [-2, -2]], cluster_std=[0.5, 0.5], **blobs_params)[0],\n",
    "    make_blobs(centers=[[2, 2], [-2, -2]], cluster_std=[1.5, 0.3], **blobs_params)[0],\n",
    "    4.0\n",
    "    * (\n",
    "        make_moons(n_samples=n_samples, noise=0.05, random_state=0)[0]\n",
    "        - np.array([0.5, 0.25])\n",
    "    ),\n",
    "    14.0 * (np.random.RandomState(42).rand(n_samples, 2) - 0.5),\n",
    "]\n",
    "\n",
    "# Compare given classifiers under given settings\n",
    "xx, yy = np.meshgrid(np.linspace(-7, 7, 150), np.linspace(-7, 7, 150))\n",
    "\n",
    "plt.figure(figsize=(len(anomaly_algorithms) * 2 + 4, 12.5))\n",
    "plt.subplots_adjust(\n",
    "    left=0.02, right=0.98, bottom=0.001, top=0.96, wspace=0.05, hspace=0.01\n",
    ")\n",
    "\n",
    "plot_num = 1\n",
    "rng = np.random.RandomState(42)\n",
    "\n",
    "for i_dataset, X in enumerate(datasets):\n",
    "    # Add outliers\n",
    "    X = np.concatenate([X, rng.uniform(low=-6, high=6, size=(n_outliers, 2))], axis=0)\n",
    "\n",
    "    for name, algorithm in anomaly_algorithms:\n",
    "        t0 = time.time()\n",
    "        algorithm.fit(X)\n",
    "        t1 = time.time()\n",
    "        plt.subplot(len(datasets), len(anomaly_algorithms), plot_num)\n",
    "        if i_dataset == 0:\n",
    "            plt.title(name, size=18)\n",
    "\n",
    "        # fit the data and tag outliers\n",
    "        if name == \"Local Outlier Factor\":\n",
    "            y_pred = algorithm.fit_predict(X)\n",
    "        else:\n",
    "            y_pred = algorithm.fit(X).predict(X)\n",
    "\n",
    "        # plot the levels lines and the points\n",
    "        if name != \"Local Outlier Factor\":  # LOF does not implement predict\n",
    "            Z = algorithm.predict(np.c_[xx.ravel(), yy.ravel()])\n",
    "            Z = Z.reshape(xx.shape)\n",
    "            plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors=\"black\")\n",
    "\n",
    "        colors = np.array([\"#377eb8\", \"#ff7f00\"])\n",
    "        plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[(y_pred + 1) // 2])\n",
    "\n",
    "        plt.xlim(-7, 7)\n",
    "        plt.ylim(-7, 7)\n",
    "        plt.xticks(())\n",
    "        plt.yticks(())\n",
    "        plt.text(\n",
    "            0.99,\n",
    "            0.01,\n",
    "            (\"%.2fs\" % (t1 - t0)).lstrip(\"0\"),\n",
    "            transform=plt.gca().transAxes,\n",
    "            size=15,\n",
    "            horizontalalignment=\"right\",\n",
    "        )\n",
    "        plot_num += 1\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26c122e3-d017-494a-abd7-afc63fa33021",
   "metadata": {},
   "source": [
    "Интерпретация результатов:\n",
    "\n",
    "Для данных с мультимодальной структурой и невыпуклыми кластерами (полумесяцы, два смещённых кластера) Isolation Forest и One-Class SVM дают наилучшие результаты.\n",
    "\n",
    "EllipticEnvelope применим только к унимодальным, близким к нормальным данным.\n",
    "\n",
    "LOF эффективен для локальных аномалий, но чувствителен к глобальной плотности.\n",
    "\n",
    "One-Class SVM (SGD) — хороший компромисс между качеством и скоростью на больших выборках."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
