{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6b613b05-deb3-4406-9b23-65fc548e1bf6",
   "metadata": {},
   "source": [
    "%%latex\n",
    "# Анализ объектов\n",
    "\n",
    "Возьмите датасет вашего варианта из лабораторной работы № 1. Если вы раньше применяли бинаризацию целевого признака, то сейчас этого делать не нужно.\n",
    "\n",
    "## Выступ (отступ)\n",
    "\n",
    "Выступ - это такая функция M(x), что для объектов, лежащих глубоко внутри своего класса, т.е. для эталонов она принимает большие положительные значения. Для периферийных объектов, лежащих на границе классов, M(x)≈0. Для объектов одного класса, расположенных среди объектов другого класса, выступ M(x) должен принимать отрицательные значения. Так как границы классов зачастую нельзя четко определить, то объекты последнего типа с M(x)<0 делят на две подгруппы: ошибочные, для которых алгоритм не может четко определить границу между классами и ошибается (их может быть много, они граничат с периферийными) и случайные выбросы (outliers) - редкие непонятные объекты с M(x)<<0.\n",
    "\n",
    "Для задачи классификации и некоторого алгоритма, возвращающего вероятности p(y|x) можно определить M для объекта x с правильным ответом y следующим образом: \n",
    "\n",
    "$$M(x) = p(y|x) - \\max\\limits_{s\\neq y} p(s|x)$$\n",
    "\n",
    "Для задачи регрессии можно в качестве выступа брать минус ошибку предсказания.\n",
    "\n",
    "Возмите два алгоритма древовидный (ExtraTreesClassifier/Regressor или GradientBoostingClassifier/Regressor) и ближайших соседей (KNeighborsClassifier/Regressor). С помощью cross_val_predict вычислите предсказания (для задачи склассификации - вероятности) и найдите выступы всех объектов. Постройте на одном графике две кривые (для деревьев и KNN): зависимость выступа от номера объекта в отсортированном по выступам ряду объектов. \n",
    "\n",
    "Выведите на экран 4 случайных выброса с разными значениями целевого признака и объясните эти аномалии в данных (20% баллов - за правильное объяснение). Вам помогут: важные признаки, найденные в предыдущей лаб. работе, и коэффициенты корреляции. ВАЖНО: выступ характеризует не \"абстрактную\" типичность объекта, а качество предсказания целевого признака!\n",
    "\n",
    "## Сгущения данных\n",
    "\n",
    "Найдите в ваших данных сгущения. \n",
    "* Для этого попробуйте сначала посмотреть на график рассеяния на главных компонентах. Двумерный рисунок является проекцией многомерной выборки и не позволяет качественно обнаружить сгущения. Чтобы как-то увидеть кластеры, отобразите цветом плотность точек (вычисленную для исходного многомерного пространства). Максимумы плотности покажут проекции сгущений в ваших данных. \n",
    "* Если вы не увидели сгущения с помощью PCA, примените [t-SNE](https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html) и нарисуйте аналогичный график рассеяния. Поймите и запишите в ответе физический смысл найденных сгущений данных (20% баллов). Это можно сделать, взяв наугад точки внутри кластеров в embadding (т.е. на графике рассеяния) и применив обратное преобразование. Другой хороший прием: строить графики рассеяния, перебирая в качестве цвета различные признаки. Нам нужны те, для которых сгущения красятся в разный цвет.\n",
    "* Теперь наши сгущения требуется найти точно. Примените [один из методов кластеризации sklearn](https://scikit-learn.org/stable/modules/clustering.html) к нормализованной выборке со всеми признаками без целевого (или к выборке в embadding пространстве). Отобразите на двумерном графике рассеяния на главных компонентах (или в пространстве t-SNE) разным цветом получившиеся кластеры. Нужно так подобрать параметры алгоритма, чтобы он вернул те же кластеры, которые вы наблюдали в предыдущем пункте. При выборе алгоритма будьте внимательны: многие из них основаны на близости точек, а не на связанности кластеров, поэтому при применении к равномерно распределенной на квадрате выборке возвращают фиктивные кластеры. Я вам советую применять DBSCAN. Чтобы подобрать его параметр eps, для некоторого min_samples, постройте график отсортированных расстояний до ближайшего соседа № min_samples и найдите по нему 90% квантиль\n",
    "\n",
    "Полезный код: вместо расчета плотности точек можно использовать расстояние до n-того соседа. Чтобы посчитать расстояния за разумное время лучше всего использовать пару функций:\n",
    "```\n",
    "d = scipy.spatial.distance.cdist(x, x)  # расчет расстояний от каждой точки выборки x до каждой (одна точка - одна строчка матрицы x)\n",
    "r = np.partition(d, min_samples, axis=1)[:,min_samples]  # поиск min_samples минимальных элементов\n",
    "```\n",
    "Если цвета плотности почти всех точек совпадают, попробуйте логарифмировать r: `hue=np.log(r)`\n",
    "\n",
    "На графике отсортированных расстояний до ближайшего соседа удобно включать логарифмический масштаб по оси y: `plt.yscale('log')`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5deb0216-d249-42af-9f3e-e49050fe5460",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
