{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "6415645b",
      "metadata": {},
      "source": [
        "# Прогнозирование заболевания по симптомам (Вариант 4)\n",
        "\n",
        "Набор данных содержит бинарные признаки — симптомы (зуд, сыпь, кашель, температура и др.) и целевую переменную — диагноз (прогноз). **Задача:** классификация — предсказание заболевания по набору симптомов."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "id": "eebe6ca9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.3\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
            "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
            "Note: you may need to restart the kernel to use updated packages.\n"
          ]
        }
      ],
      "source": [
        "%pip -q install pandas numpy matplotlib seaborn scikit-learn"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "id": "5863b24d",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import pandas as pd\n",
        "import matplotlib.pyplot as plt\n",
        "import seaborn as sns\n",
        "\n",
        "from sklearn.model_selection import train_test_split\n",
        "from sklearn.preprocessing import StandardScaler, LabelEncoder\n",
        "from sklearn.linear_model import LogisticRegression\n",
        "from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier\n",
        "from sklearn.metrics import accuracy_score, f1_score, classification_report\n",
        "from sklearn.base import clone\n",
        "\n",
        "pd.set_option(\"display.max_columns\", 30)\n",
        "sns.set_style(\"whitegrid\")\n",
        "plt.rcParams[\"figure.figsize\"] = (8, 5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "id": "91e62dbb",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>itching</th>\n",
              "      <th>skin_rash</th>\n",
              "      <th>nodal_skin_eruptions</th>\n",
              "      <th>continuous_sneezing</th>\n",
              "      <th>shivering</th>\n",
              "      <th>chills</th>\n",
              "      <th>joint_pain</th>\n",
              "      <th>stomach_pain</th>\n",
              "      <th>acidity</th>\n",
              "      <th>ulcers_on_tongue</th>\n",
              "      <th>muscle_wasting</th>\n",
              "      <th>vomiting</th>\n",
              "      <th>burning_micturition</th>\n",
              "      <th>spotting_ urination</th>\n",
              "      <th>fatigue</th>\n",
              "      <th>...</th>\n",
              "      <th>blood_in_sputum</th>\n",
              "      <th>prominent_veins_on_calf</th>\n",
              "      <th>palpitations</th>\n",
              "      <th>painful_walking</th>\n",
              "      <th>pus_filled_pimples</th>\n",
              "      <th>blackheads</th>\n",
              "      <th>scurring</th>\n",
              "      <th>skin_peeling</th>\n",
              "      <th>silver_like_dusting</th>\n",
              "      <th>small_dents_in_nails</th>\n",
              "      <th>inflammatory_nails</th>\n",
              "      <th>blister</th>\n",
              "      <th>red_sore_around_nose</th>\n",
              "      <th>yellow_crust_ooze</th>\n",
              "      <th>prognosis</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>Fungal infection</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>Fungal infection</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>Fungal infection</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>3 rows × 133 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "   itching  skin_rash  nodal_skin_eruptions  continuous_sneezing  shivering  \\\n",
              "0        1          1                     1                    0          0   \n",
              "1        0          1                     1                    0          0   \n",
              "2        1          0                     1                    0          0   \n",
              "\n",
              "   chills  joint_pain  stomach_pain  acidity  ulcers_on_tongue  \\\n",
              "0       0           0             0        0                 0   \n",
              "1       0           0             0        0                 0   \n",
              "2       0           0             0        0                 0   \n",
              "\n",
              "   muscle_wasting  vomiting  burning_micturition  spotting_ urination  \\\n",
              "0               0         0                    0                    0   \n",
              "1               0         0                    0                    0   \n",
              "2               0         0                    0                    0   \n",
              "\n",
              "   fatigue  ...  blood_in_sputum  prominent_veins_on_calf  palpitations  \\\n",
              "0        0  ...                0                        0             0   \n",
              "1        0  ...                0                        0             0   \n",
              "2        0  ...                0                        0             0   \n",
              "\n",
              "   painful_walking  pus_filled_pimples  blackheads  scurring  skin_peeling  \\\n",
              "0                0                   0           0         0             0   \n",
              "1                0                   0           0         0             0   \n",
              "2                0                   0           0         0             0   \n",
              "\n",
              "   silver_like_dusting  small_dents_in_nails  inflammatory_nails  blister  \\\n",
              "0                    0                     0                   0        0   \n",
              "1                    0                     0                   0        0   \n",
              "2                    0                     0                   0        0   \n",
              "\n",
              "   red_sore_around_nose  yellow_crust_ooze         prognosis  \n",
              "0                     0                  0  Fungal infection  \n",
              "1                     0                  0  Fungal infection  \n",
              "2                     0                  0  Fungal infection  \n",
              "\n",
              "[3 rows x 133 columns]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Количество уникальных классов: 41\n"
          ]
        }
      ],
      "source": [
        "# Загрузка данных\n",
        "train_df = pd.read_csv(\"train_disease.csv\")\n",
        "test_df = pd.read_csv(\"test_disease.csv\")\n",
        "\n",
        "# В CSV в конце каждой строки лишняя запятая\n",
        "train_df = train_df.loc[:, ~train_df.columns.str.contains(\"^Unnamed\")]\n",
        "test_df = test_df.loc[:, ~test_df.columns.str.contains(\"^Unnamed\")]\n",
        "\n",
        "# Столбец с целевой переменной\n",
        "target_col = \"prognosis\"\n",
        "feature_cols = [c for c in train_df.columns if c != target_col]\n",
        "\n",
        "display(train_df.head(3))\n",
        "print(\"Количество уникальных классов: \" + str(len(train_df[target_col].unique())))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9d852b47",
      "metadata": {},
      "source": [
        "**Сводка по данным:** \n",
        "\n",
        "Число признаков (симптомов) - 132\n",
        "\n",
        "Уникальных классов (болезней) — 41"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8f9e858",
      "metadata": {},
      "source": [
        "## Очистка и предобработка\n",
        "\n",
        "- Данные не требуют очистки или предобработки, кроме удаления лишнего столбца из-за лишних запятых"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3cb3d1f1",
      "metadata": {},
      "source": [
        "## Задание 1. Анализ исходных данных. Постановка задачи.\n",
        "\n",
        "**Требование:** не менее 3 графиков с описанием; выводы о качестве датасета."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 72,
      "id": "9644e433",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 152092 characters]",
            "text/plain": [
              "<Figure size 1200x600 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# График 1: распределение классов (болезней) в обучающей выборке\n",
        "fig, ax = plt.subplots(figsize=(12, 6))\n",
        "counts = train_df[target_col].value_counts()\n",
        "counts.plot(kind=\"bar\", ax=ax, color=\"steelblue\", edgecolor=\"gray\")\n",
        "ax.set_title(\"Распределение классов (диагнозов) в обучающей выборке\")\n",
        "ax.set_xlabel(\"Диагноз\")\n",
        "ax.set_ylabel(\"Количество наблюдений\")\n",
        "plt.xticks(rotation=45, ha=\"right\")\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d2a5bbf5",
      "metadata": {},
      "source": [
        "Видим, что все болезни встречаются одинаково часто, по ~120 раз каждая"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 73,
      "id": "2aba258c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 31388 characters]",
            "text/plain": [
              "<Figure size 800x500 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# График 2: распределение числа активных симптомов у пациента (сумма по строке)\n",
        "symptom_count = train_df[feature_cols].sum(axis=1)\n",
        "fig, ax = plt.subplots(figsize=(8, 5))\n",
        "ax.hist(symptom_count, bins=range(int(symptom_count.min()), int(symptom_count.max()) + 2), color=\"coral\", edgecolor=\"black\", alpha=0.8)\n",
        "ax.set_title(\"Распределение числа активных симптомов на одного пациента\")\n",
        "ax.set_xlabel(\"Число симптомов\")\n",
        "ax.set_ylabel(\"Количество пациентов\")\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "154093cf",
      "metadata": {},
      "source": [
        "У большинства пациентов от 4 до 7 активных симптомов; это разумно для медицинских данных."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 74,
      "id": "83e34ac4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 58748 characters]",
            "text/plain": [
              "<Figure size 900x500 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# График 3: топ-15 наиболее частых симптомов в датасете\n",
        "symptom_freq = train_df[feature_cols].sum().sort_values(ascending=True).tail(15)\n",
        "fig, ax = plt.subplots(figsize=(9, 5))\n",
        "symptom_freq.plot(kind=\"barh\", ax=ax, color=\"seagreen\", alpha=0.8)\n",
        "ax.set_title(\"Топ-15 наиболее часто встречающихся симптомов\")\n",
        "ax.set_xlabel(\"Количество пациентов с симптомом\")\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af190f9c",
      "metadata": {},
      "source": [
        "Показана частота появления каждого симптома в данных; слабость, усталость и др. встречаются чаще."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "420059dd",
      "metadata": {},
      "source": [
        "**Выводы по качеству датасета:**  \n",
        "- Пропусков нет\n",
        "- Признаки бинарные (0/1); для логистической регрессии используем StandardScaler.  "
      ]
    },
    {
      "cell_type": "markdown",
      "id": "02b51be5",
      "metadata": {},
      "source": [
        "## Задание 2. Модели прогнозирования заболевания\n",
        "\n",
        "Используем **три модели**:\n",
        "- **LogisticRegression** — линейная модель\n",
        "- **RandomForestClassifier** — ансамбль деревьев\n",
        "- **GradientBoostingClassifier** — градиентный бустинг\n",
        "\n",
        "**Метрики:** Accuracy (доля верных ответов), F1-macro (усреднение по классам без учёта размера), F1-weighted (с учётом размера класса). Для многоклассовой задачи F1 даёт более информативную оценку, чем только accuracy."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 75,
      "id": "7972925b",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Подготовка данных: обучающая и тестовая выборки (test_disease.csv — отдельный тест)\n",
        "X_train = train_df[feature_cols]\n",
        "y_train_raw = train_df[target_col]\n",
        "X_test = test_df[feature_cols]\n",
        "y_test_raw = test_df[target_col]\n",
        "\n",
        "# Кодирование меток классов (единый LabelEncoder по всем классам из train + test)\n",
        "le = LabelEncoder()\n",
        "all_labels = pd.concat([y_train_raw, y_test_raw]).unique()\n",
        "le.fit(all_labels)\n",
        "y_train = le.transform(y_train_raw)\n",
        "y_test = le.transform(y_test_raw)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c9fc832",
      "metadata": {},
      "source": [
        "Размеры: X_train (4920, 132), X_test (42, 132). Классов: 41."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 76,
      "id": "63130ff5",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Масштабирование для логистической регрессии (деревья не требуют)\n",
        "scaler = StandardScaler()\n",
        "X_train_scaled = scaler.fit_transform(X_train)\n",
        "X_test_scaled = scaler.transform(X_test)\n",
        "\n",
        "# Модели (те же семейства, что в вариантах 2–3, но классификаторы)\n",
        "models = {\n",
        "    \"LogisticRegression\": LogisticRegression(max_iter=1000, random_state=42),\n",
        "    \"RandomForest\": RandomForestClassifier(n_estimators=200, random_state=42),\n",
        "    \"GradientBoosting\": GradientBoostingClassifier(random_state=42),\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 80,
      "id": "fb2566ee",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>model</th>\n",
              "      <th>split</th>\n",
              "      <th>accuracy</th>\n",
              "      <th>f1_macro</th>\n",
              "      <th>f1_weighted</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>LogisticRegression</td>\n",
              "      <td>train</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>LogisticRegression</td>\n",
              "      <td>test</td>\n",
              "      <td>0.97619</td>\n",
              "      <td>0.98374</td>\n",
              "      <td>0.97619</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>RandomForest</td>\n",
              "      <td>train</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>RandomForest</td>\n",
              "      <td>test</td>\n",
              "      <td>0.97619</td>\n",
              "      <td>0.98374</td>\n",
              "      <td>0.97619</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>GradientBoosting</td>\n",
              "      <td>train</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "      <td>1.00000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>GradientBoosting</td>\n",
              "      <td>test</td>\n",
              "      <td>0.97619</td>\n",
              "      <td>0.98374</td>\n",
              "      <td>0.97619</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                model  split  accuracy  f1_macro  f1_weighted\n",
              "0  LogisticRegression  train   1.00000   1.00000      1.00000\n",
              "1  LogisticRegression   test   0.97619   0.98374      0.97619\n",
              "2        RandomForest  train   1.00000   1.00000      1.00000\n",
              "3        RandomForest   test   0.97619   0.98374      0.97619\n",
              "4    GradientBoosting  train   1.00000   1.00000      1.00000\n",
              "5    GradientBoosting   test   0.97619   0.98374      0.97619"
            ]
          },
          "execution_count": 80,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Обучение и оценка: для LR — масштабированные данные, для деревьев — исходные\n",
        "results = []\n",
        "for name, model in models.items():\n",
        "    if name == \"LogisticRegression\":\n",
        "        X_tr, X_te = X_train_scaled, X_test_scaled\n",
        "    else:\n",
        "        X_tr, X_te = X_train, X_test\n",
        "    model.fit(X_tr, y_train)\n",
        "    pred_train = model.predict(X_tr)\n",
        "    pred_test = model.predict(X_te)\n",
        "    results.append({\n",
        "        \"model\": name, \"split\": \"train\",\n",
        "        \"accuracy\": accuracy_score(y_train, pred_train),\n",
        "        \"f1_macro\": f1_score(y_train, pred_train, average=\"macro\"),\n",
        "        \"f1_weighted\": f1_score(y_train, pred_train, average=\"weighted\"),\n",
        "    })\n",
        "    results.append({\n",
        "        \"model\": name, \"split\": \"test\",\n",
        "        \"accuracy\": accuracy_score(y_test, pred_test),\n",
        "        \"f1_macro\": f1_score(y_test, pred_test, average=\"macro\"),\n",
        "        \"f1_weighted\": f1_score(y_test, pred_test, average=\"weighted\"),\n",
        "    })\n",
        "\n",
        "results_df = pd.DataFrame(results)\n",
        "results_df"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 78,
      "id": "3294aa94",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>accuracy</th>\n",
              "      <th>f1_macro</th>\n",
              "      <th>f1_weighted</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>model</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>LogisticRegression</th>\n",
              "      <td>0.9762</td>\n",
              "      <td>0.9837</td>\n",
              "      <td>0.9762</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>RandomForest</th>\n",
              "      <td>0.9762</td>\n",
              "      <td>0.9837</td>\n",
              "      <td>0.9762</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>GradientBoosting</th>\n",
              "      <td>0.9762</td>\n",
              "      <td>0.9837</td>\n",
              "      <td>0.9762</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                    accuracy  f1_macro  f1_weighted\n",
              "model                                              \n",
              "LogisticRegression    0.9762    0.9837       0.9762\n",
              "RandomForest          0.9762    0.9837       0.9762\n",
              "GradientBoosting      0.9762    0.9837       0.9762"
            ]
          },
          "execution_count": 78,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Сводная таблица по тестовой выборке (для наглядности)\n",
        "test_metrics = results_df[results_df[\"split\"] == \"test\"].set_index(\"model\")[[\"accuracy\", \"f1_macro\", \"f1_weighted\"]]\n",
        "test_metrics.round(4)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 79,
      "id": "1707f3bc",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "image/png": "[encoded data, 54568 characters]",
            "text/plain": [
              "<Figure size 1400x400 with 3 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Визуализация метрик на train и test\n",
        "fig, axes = plt.subplots(1, 3, figsize=(14, 4))\n",
        "for i, metric in enumerate([\"accuracy\", \"f1_macro\", \"f1_weighted\"]):\n",
        "    ax = axes[i]\n",
        "    pivot = results_df.pivot(index=\"model\", columns=\"split\", values=metric)\n",
        "    pivot.plot(kind=\"bar\", ax=ax, color=[\"steelblue\", \"coral\"])\n",
        "    ax.set_title(metric)\n",
        "    ax.set_ylabel(metric)\n",
        "    ax.legend(title=\"split\")\n",
        "    ax.set_ylim(0, 1.05)\n",
        "    plt.setp(ax.xaxis.get_majorticklabels(), rotation=15, ha=\"right\")\n",
        "plt.suptitle(\"Сравнение моделей: метрики на train и test\")\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".venv (3.14.2)",
      "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.14.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
