{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ea0e3df0",
   "metadata": {},
   "source": [
    "\n",
    "# Регрессия глубокой нейросетью с весовой эволюцией и дообучением\n",
    "\n",
    "В работе автоматически выбирается ключевая зависимая переменная, строится глубокая нейросеть (**более 3 скрытых слоёв**), её веса инициализируются методом роя частиц (**PSO**), после чего модель дообучается градиентным методом. В конце сравниваются метрики модели **после PSO** и **после дообучения** на тестовой выборке.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "44e8fcfb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "device = cuda\n"
     ]
    }
   ],
   "source": [
    "\n",
    "import os\n",
    "import re\n",
    "import math\n",
    "import random\n",
    "import warnings\n",
    "from pathlib import Path\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.impute import SimpleImputer\n",
    "from sklearn.preprocessing import OneHotEncoder, StandardScaler\n",
    "from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.utils.data import TensorDataset, DataLoader\n",
    "\n",
    "warnings.filterwarnings('ignore')\n",
    "pd.set_option('display.max_columns', 200)\n",
    "pd.set_option('display.width', 200)\n",
    "\n",
    "SEED = 42\n",
    "random.seed(SEED)\n",
    "np.random.seed(SEED)\n",
    "torch.manual_seed(SEED)\n",
    "\n",
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "print('device =', device)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "1dad951b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Используемый файл: Sales Dataset.csv\n",
      "Форма датасета: (1194, 12)\n"
     ]
    },
    {
     "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>Order ID</th>\n",
       "      <th>Amount</th>\n",
       "      <th>Profit</th>\n",
       "      <th>Quantity</th>\n",
       "      <th>Category</th>\n",
       "      <th>Sub-Category</th>\n",
       "      <th>PaymentMode</th>\n",
       "      <th>Order Date</th>\n",
       "      <th>CustomerName</th>\n",
       "      <th>State</th>\n",
       "      <th>City</th>\n",
       "      <th>Year-Month</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>B-26776</td>\n",
       "      <td>9726</td>\n",
       "      <td>1275</td>\n",
       "      <td>5</td>\n",
       "      <td>Electronics</td>\n",
       "      <td>Electronic Games</td>\n",
       "      <td>UPI</td>\n",
       "      <td>2023-06-27</td>\n",
       "      <td>David Padilla</td>\n",
       "      <td>Florida</td>\n",
       "      <td>Miami</td>\n",
       "      <td>2023-06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>B-26776</td>\n",
       "      <td>9726</td>\n",
       "      <td>1275</td>\n",
       "      <td>5</td>\n",
       "      <td>Electronics</td>\n",
       "      <td>Electronic Games</td>\n",
       "      <td>UPI</td>\n",
       "      <td>2024-12-27</td>\n",
       "      <td>Connor Morgan</td>\n",
       "      <td>Illinois</td>\n",
       "      <td>Chicago</td>\n",
       "      <td>2024-12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>B-26776</td>\n",
       "      <td>9726</td>\n",
       "      <td>1275</td>\n",
       "      <td>5</td>\n",
       "      <td>Electronics</td>\n",
       "      <td>Electronic Games</td>\n",
       "      <td>UPI</td>\n",
       "      <td>2021-07-25</td>\n",
       "      <td>Robert Stone</td>\n",
       "      <td>New York</td>\n",
       "      <td>Buffalo</td>\n",
       "      <td>2021-07</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>B-26776</td>\n",
       "      <td>4975</td>\n",
       "      <td>1330</td>\n",
       "      <td>14</td>\n",
       "      <td>Electronics</td>\n",
       "      <td>Printers</td>\n",
       "      <td>UPI</td>\n",
       "      <td>2023-06-27</td>\n",
       "      <td>David Padilla</td>\n",
       "      <td>Florida</td>\n",
       "      <td>Miami</td>\n",
       "      <td>2023-06</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>B-26776</td>\n",
       "      <td>4975</td>\n",
       "      <td>1330</td>\n",
       "      <td>14</td>\n",
       "      <td>Electronics</td>\n",
       "      <td>Printers</td>\n",
       "      <td>UPI</td>\n",
       "      <td>2024-12-27</td>\n",
       "      <td>Connor Morgan</td>\n",
       "      <td>Illinois</td>\n",
       "      <td>Chicago</td>\n",
       "      <td>2024-12</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  Order ID  Amount  Profit  Quantity     Category      Sub-Category PaymentMode  Order Date   CustomerName     State     City Year-Month\n",
       "0  B-26776    9726    1275         5  Electronics  Electronic Games         UPI  2023-06-27  David Padilla   Florida    Miami    2023-06\n",
       "1  B-26776    9726    1275         5  Electronics  Electronic Games         UPI  2024-12-27  Connor Morgan  Illinois  Chicago    2024-12\n",
       "2  B-26776    9726    1275         5  Electronics  Electronic Games         UPI  2021-07-25   Robert Stone  New York  Buffalo    2021-07\n",
       "3  B-26776    4975    1330        14  Electronics          Printers         UPI  2023-06-27  David Padilla   Florida    Miami    2023-06\n",
       "4  B-26776    4975    1330        14  Electronics          Printers         UPI  2024-12-27  Connor Morgan  Illinois  Chicago    2024-12"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Типы данных:\n"
     ]
    },
    {
     "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>dtype</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Order ID</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Amount</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Profit</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Quantity</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Category</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Sub-Category</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PaymentMode</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Order Date</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CustomerName</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>State</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>City</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Year-Month</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               dtype\n",
       "Order ID      object\n",
       "Amount         int64\n",
       "Profit         int64\n",
       "Quantity       int64\n",
       "Category      object\n",
       "Sub-Category  object\n",
       "PaymentMode   object\n",
       "Order Date    object\n",
       "CustomerName  object\n",
       "State         object\n",
       "City          object\n",
       "Year-Month    object"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Поиск файла датасета\n",
    "candidate_paths = [\n",
    "    Path('Sales Dataset.csv'),\n",
    "    Path('sales_dataset.csv'),\n",
    "    Path('sales dataset.csv'),\n",
    "    Path('/mnt/data/Sales Dataset.csv'),\n",
    "    Path('/mnt/data/sales_dataset.csv'),\n",
    "    Path('/mnt/data/sales dataset.csv'),\n",
    "]\n",
    "\n",
    "csv_path = None\n",
    "for path in candidate_paths:\n",
    "    if path.exists():\n",
    "        csv_path = path\n",
    "        break\n",
    "\n",
    "if csv_path is None:\n",
    "    raise FileNotFoundError('CSV-файл не найден. Поместите файл Sales Dataset.csv рядом с ноутбуком или в /mnt/data/.')\n",
    "\n",
    "print('Используемый файл:', csv_path)\n",
    "df_raw = pd.read_csv(csv_path)\n",
    "print('Форма датасета:', df_raw.shape)\n",
    "display(df_raw.head())\n",
    "print('Типы данных:')\n",
    "display(df_raw.dtypes.to_frame('dtype'))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ef1d25bf",
   "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>original_name</th>\n",
       "      <th>normalized_name</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Order ID</td>\n",
       "      <td>order_id</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Amount</td>\n",
       "      <td>amount</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Profit</td>\n",
       "      <td>profit</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Quantity</td>\n",
       "      <td>quantity</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Category</td>\n",
       "      <td>category</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Sub-Category</td>\n",
       "      <td>sub_category</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>PaymentMode</td>\n",
       "      <td>paymentmode</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Order Date</td>\n",
       "      <td>order_date</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>CustomerName</td>\n",
       "      <td>customername</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>State</td>\n",
       "      <td>state</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>City</td>\n",
       "      <td>city</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>Year-Month</td>\n",
       "      <td>year_month</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   original_name normalized_name\n",
       "0       Order ID        order_id\n",
       "1         Amount          amount\n",
       "2         Profit          profit\n",
       "3       Quantity        quantity\n",
       "4       Category        category\n",
       "5   Sub-Category    sub_category\n",
       "6    PaymentMode     paymentmode\n",
       "7     Order Date      order_date\n",
       "8   CustomerName    customername\n",
       "9          State           state\n",
       "10          City            city\n",
       "11    Year-Month      year_month"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Нормализация названий колонок\n",
    "\n",
    "def normalize_name(col):\n",
    "    col = str(col).strip().lower()\n",
    "    col = col.replace('%', 'pct')\n",
    "    col = col.replace('&', 'and')\n",
    "    col = re.sub(r'[^a-zA-Z0-9]+', '_', col)\n",
    "    col = re.sub(r'_+', '_', col).strip('_')\n",
    "    return col\n",
    "\n",
    "rename_map = {col: normalize_name(col) for col in df_raw.columns}\n",
    "df = df_raw.rename(columns=rename_map).copy()\n",
    "\n",
    "display(pd.DataFrame({'original_name': list(rename_map.keys()), 'normalized_name': list(rename_map.values())}))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "422f8bc1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Выбранная зависимая переменная: amount\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Автоматический выбор зависимой переменной\n",
    "priority_targets = [\n",
    "    'amount', 'sales', 'sale_amount', 'revenue', 'turnover', 'profit'\n",
    "]\n",
    "\n",
    "target_col = None\n",
    "for col in priority_targets:\n",
    "    if col in df.columns:\n",
    "        target_col = col\n",
    "        break\n",
    "\n",
    "if target_col is None:\n",
    "    numeric_candidates = [c for c in df.columns if pd.api.types.is_numeric_dtype(df[c])]\n",
    "    if not numeric_candidates:\n",
    "        raise ValueError('Не найдено числовой зависимой переменной для регрессии.')\n",
    "    # Берём числовой столбец с наибольшей вариативностью, исключая явные идентификаторы\n",
    "    numeric_candidates = [c for c in numeric_candidates if not any(tok in c for tok in ['id', 'index', 'code'])]\n",
    "    if not numeric_candidates:\n",
    "        raise ValueError('Подходящая числовая зависимая переменная не найдена.')\n",
    "    target_col = df[numeric_candidates].std(numeric_only=True).sort_values(ascending=False).index[0]\n",
    "\n",
    "print('Выбранная зависимая переменная:', target_col)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "53a888d8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Удаляемые идентификаторы / несодержательные поля: ['order_id', 'customername']\n",
      "Число объектов после очистки целевой переменной: 1194\n",
      "Число исходных признаков: 14\n",
      "Названия признаков:\n",
      "['profit', 'quantity', 'category', 'sub_category', 'paymentmode', 'state', 'city', 'order_year', 'order_month', 'order_day', 'order_dayofweek', 'order_weekofyear', 'year_month_year', 'year_month_month']\n",
      "Числовые признаки: ['profit', 'quantity', 'order_year', 'order_month', 'order_day', 'order_dayofweek', 'order_weekofyear', 'year_month_year', 'year_month_month']\n",
      "Категориальные признаки: ['category', 'sub_category', 'paymentmode', 'state', 'city']\n",
      "Пропуски в признаках:\n"
     ]
    },
    {
     "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>missing_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>profit</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>quantity</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>category</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>sub_category</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>paymentmode</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>state</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>city</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>order_year</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>order_month</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>order_day</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>order_dayofweek</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>order_weekofyear</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>year_month_year</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>year_month_month</th>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  missing_count\n",
       "profit                        0\n",
       "quantity                      0\n",
       "category                      0\n",
       "sub_category                  0\n",
       "paymentmode                   0\n",
       "state                         0\n",
       "city                          0\n",
       "order_year                    0\n",
       "order_month                   0\n",
       "order_day                     0\n",
       "order_dayofweek               0\n",
       "order_weekofyear              0\n",
       "year_month_year               0\n",
       "year_month_month              0"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Предобработка и инженерия признаков\n",
    "\n",
    "df_model = df.copy()\n",
    "\n",
    "# Работа с датами\n",
    "if 'order_date' in df_model.columns:\n",
    "    dt = pd.to_datetime(df_model['order_date'], errors='coerce')\n",
    "    df_model['order_year'] = dt.dt.year\n",
    "    df_model['order_month'] = dt.dt.month\n",
    "    df_model['order_day'] = dt.dt.day\n",
    "    df_model['order_dayofweek'] = dt.dt.dayofweek\n",
    "    df_model['order_weekofyear'] = dt.dt.isocalendar().week.astype('float')\n",
    "    df_model = df_model.drop(columns=['order_date'])\n",
    "\n",
    "if 'year_month' in df_model.columns:\n",
    "    ym = pd.to_datetime(df_model['year_month'].astype(str) + '-01', errors='coerce')\n",
    "    df_model['year_month_year'] = ym.dt.year\n",
    "    df_model['year_month_month'] = ym.dt.month\n",
    "    df_model = df_model.drop(columns=['year_month'])\n",
    "\n",
    "# Явные идентификаторы и почти-бесполезные идентификаторы\n",
    "id_like = [c for c in df_model.columns if c != target_col and any(tok in c for tok in ['order_id', 'customername', 'customer_name', 'id'])]\n",
    "# Избегаем удаления потенциально содержательных признаков вроде payment_mode\n",
    "id_like = [c for c in id_like if c not in ['paymentmode', 'payment_mode']]\n",
    "print('Удаляемые идентификаторы / несодержательные поля:', id_like)\n",
    "\n",
    "df_model = df_model.drop(columns=id_like, errors='ignore')\n",
    "\n",
    "X = df_model.drop(columns=[target_col]).copy()\n",
    "y = df_model[target_col].copy()\n",
    "\n",
    "# Приведение целевой переменной к числу\n",
    "if not pd.api.types.is_numeric_dtype(y):\n",
    "    y = pd.to_numeric(y, errors='coerce')\n",
    "\n",
    "mask = y.notna()\n",
    "X = X.loc[mask].reset_index(drop=True)\n",
    "y = y.loc[mask].astype(float).reset_index(drop=True)\n",
    "\n",
    "print('Число объектов после очистки целевой переменной:', len(y))\n",
    "print('Число исходных признаков:', X.shape[1])\n",
    "print('Названия признаков:')\n",
    "print(list(X.columns))\n",
    "\n",
    "numeric_features = X.select_dtypes(include=[np.number]).columns.tolist()\n",
    "categorical_features = [c for c in X.columns if c not in numeric_features]\n",
    "\n",
    "print('Числовые признаки:', numeric_features)\n",
    "print('Категориальные признаки:', categorical_features)\n",
    "print('Пропуски в признаках:')\n",
    "display(X.isna().sum().sort_values(ascending=False).to_frame('missing_count').head(20))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ef889871",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Число признаков после кодирования: 53\n",
      "Используется log1p-преобразование целевой переменной: False\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Разбиение на обучающую, валидационную и тестовую выборки\n",
    "X_train_full, X_test, y_train_full, y_test = train_test_split(\n",
    "    X, y, test_size=0.2, random_state=SEED\n",
    ")\n",
    "\n",
    "X_train, X_val, y_train, y_val = train_test_split(\n",
    "    X_train_full, y_train_full, test_size=0.2, random_state=SEED\n",
    ")\n",
    "\n",
    "numeric_features = X_train.select_dtypes(include=[np.number]).columns.tolist()\n",
    "categorical_features = [c for c in X_train.columns if c not in numeric_features]\n",
    "\n",
    "preprocessor = ColumnTransformer(\n",
    "    transformers=[\n",
    "        ('num', Pipeline([\n",
    "            ('imputer', SimpleImputer(strategy='median')),\n",
    "            ('scaler', StandardScaler())\n",
    "        ]), numeric_features),\n",
    "        ('cat', Pipeline([\n",
    "            ('imputer', SimpleImputer(strategy='most_frequent')),\n",
    "            ('onehot', OneHotEncoder(handle_unknown='ignore'))\n",
    "        ]), categorical_features),\n",
    "    ],\n",
    "    remainder='drop'\n",
    ")\n",
    "\n",
    "X_train_proc = preprocessor.fit_transform(X_train)\n",
    "X_val_proc = preprocessor.transform(X_val)\n",
    "X_test_proc = preprocessor.transform(X_test)\n",
    "\n",
    "feature_names = preprocessor.get_feature_names_out()\n",
    "\n",
    "if hasattr(X_train_proc, 'toarray'):\n",
    "    X_train_proc = X_train_proc.toarray()\n",
    "    X_val_proc = X_val_proc.toarray()\n",
    "    X_test_proc = X_test_proc.toarray()\n",
    "\n",
    "X_train_proc = np.asarray(X_train_proc, dtype=np.float32)\n",
    "X_val_proc = np.asarray(X_val_proc, dtype=np.float32)\n",
    "X_test_proc = np.asarray(X_test_proc, dtype=np.float32)\n",
    "\n",
    "print('Число признаков после кодирования:', X_train_proc.shape[1])\n",
    "\n",
    "# Стабилизация целевой переменной\n",
    "use_log_target = (y_train.min() > -1) and (abs(pd.Series(y_train).skew()) > 1.0)\n",
    "print('Используется log1p-преобразование целевой переменной:', use_log_target)\n",
    "\n",
    "def target_forward(arr):\n",
    "    arr = np.asarray(arr, dtype=np.float32)\n",
    "    return np.log1p(arr) if use_log_target else arr\n",
    "\n",
    "def target_inverse(arr):\n",
    "    arr = np.asarray(arr, dtype=np.float32)\n",
    "    return np.expm1(arr) if use_log_target else arr\n",
    "\n",
    "y_train_t = target_forward(y_train.values)\n",
    "y_val_t = target_forward(y_val.values)\n",
    "y_test_t = target_forward(y_test.values)\n",
    "\n",
    "y_scaler = StandardScaler()\n",
    "y_train_scaled = y_scaler.fit_transform(y_train_t.reshape(-1, 1)).astype(np.float32)\n",
    "y_val_scaled = y_scaler.transform(y_val_t.reshape(-1, 1)).astype(np.float32)\n",
    "y_test_scaled = y_scaler.transform(y_test_t.reshape(-1, 1)).astype(np.float32)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "c7f2585a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Архитектура скрытых слоёв: (128, 64, 32, 16)\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Архитектура глубокой нейросети (> 3 скрытых слоя)\n",
    "class DeepRegressor(nn.Module):\n",
    "    def __init__(self, input_dim, hidden_dims=(128, 64, 32, 16)):\n",
    "        super().__init__()\n",
    "        layers = []\n",
    "        prev_dim = input_dim\n",
    "        for h in hidden_dims:\n",
    "            layers.append(nn.Linear(prev_dim, h))\n",
    "            layers.append(nn.ReLU())\n",
    "            prev_dim = h\n",
    "        layers.append(nn.Linear(prev_dim, 1))\n",
    "        self.net = nn.Sequential(*layers)\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.net(x)\n",
    "\n",
    "hidden_dims = (128, 64, 32, 16)\n",
    "print('Архитектура скрытых слоёв:', hidden_dims)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ad854600",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# Служебные функции\n",
    "\n",
    "def rmse(y_true, y_pred):\n",
    "    return float(np.sqrt(mean_squared_error(y_true, y_pred)))\n",
    "\n",
    "\n",
    "def evaluate_predictions(y_true, y_pred):\n",
    "    return {\n",
    "        'r2': float(r2_score(y_true, y_pred)),\n",
    "        'rmse': rmse(y_true, y_pred),\n",
    "        'mae': float(mean_absolute_error(y_true, y_pred))\n",
    "    }\n",
    "\n",
    "\n",
    "def scale_back_predictions(pred_scaled):\n",
    "    pred_t = y_scaler.inverse_transform(pred_scaled.reshape(-1, 1)).ravel()\n",
    "    pred_raw = target_inverse(pred_t)\n",
    "    return pred_raw\n",
    "\n",
    "\n",
    "def tensor_dataset_from_numpy(X_arr, y_arr):\n",
    "    X_tensor = torch.tensor(X_arr, dtype=torch.float32)\n",
    "    y_tensor = torch.tensor(y_arr, dtype=torch.float32)\n",
    "    return TensorDataset(X_tensor, y_tensor)\n",
    "\n",
    "\n",
    "def get_param_meta(model):\n",
    "    meta = []\n",
    "    total = 0\n",
    "    for name, p in model.named_parameters():\n",
    "        numel = p.numel()\n",
    "        meta.append((name, p.shape, numel))\n",
    "        total += numel\n",
    "    return meta, total\n",
    "\n",
    "\n",
    "def vector_to_model(model, vector):\n",
    "    pointer = 0\n",
    "    with torch.no_grad():\n",
    "        for p in model.parameters():\n",
    "            numel = p.numel()\n",
    "            block = vector[pointer:pointer + numel]\n",
    "            block_tensor = torch.tensor(block.reshape(p.shape), dtype=p.dtype, device=p.device)\n",
    "            p.copy_(block_tensor)\n",
    "            pointer += numel\n",
    "\n",
    "\n",
    "def model_to_vector(model):\n",
    "    chunks = []\n",
    "    for p in model.parameters():\n",
    "        chunks.append(p.detach().cpu().numpy().ravel())\n",
    "    return np.concatenate(chunks).astype(np.float32)\n",
    "\n",
    "\n",
    "def predict_model(model, X_arr, batch_size=512):\n",
    "    model.eval()\n",
    "    preds = []\n",
    "    with torch.no_grad():\n",
    "        for start in range(0, len(X_arr), batch_size):\n",
    "            batch = torch.tensor(X_arr[start:start+batch_size], dtype=torch.float32, device=device)\n",
    "            pred = model(batch).cpu().numpy().ravel()\n",
    "            preds.append(pred)\n",
    "    pred_scaled = np.concatenate(preds)\n",
    "    return scale_back_predictions(pred_scaled)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1014a45f",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# PSO для начальной настройки весов\n",
    "\n",
    "def mse_on_scaled_targets(model, X_arr, y_scaled_arr):\n",
    "    model.eval()\n",
    "    with torch.no_grad():\n",
    "        X_tensor = torch.tensor(X_arr, dtype=torch.float32, device=device)\n",
    "        y_tensor = torch.tensor(y_scaled_arr.ravel(), dtype=torch.float32, device=device)\n",
    "        pred = model(X_tensor).ravel()\n",
    "        loss = torch.mean((pred - y_tensor) ** 2)\n",
    "    return float(loss.item())\n",
    "\n",
    "\n",
    "def pso_initialize(\n",
    "    input_dim,\n",
    "    X_train_arr,\n",
    "    y_train_scaled_arr,\n",
    "    X_val_arr,\n",
    "    y_val_scaled_arr,\n",
    "    hidden_dims=(128, 64, 32, 16),\n",
    "    n_particles=18,\n",
    "    n_iters=35,\n",
    "    inertia=0.72,\n",
    "    c1=1.45,\n",
    "    c2=1.45,\n",
    "    position_clip=2.5,\n",
    "):\n",
    "    template_model = DeepRegressor(input_dim=input_dim, hidden_dims=hidden_dims).to(device)\n",
    "    base_vector = model_to_vector(template_model)\n",
    "    dim = len(base_vector)\n",
    "\n",
    "    positions = np.random.normal(loc=0.0, scale=0.12, size=(n_particles, dim)).astype(np.float32) + base_vector\n",
    "    velocities = np.random.normal(loc=0.0, scale=0.02, size=(n_particles, dim)).astype(np.float32)\n",
    "\n",
    "    pbest_positions = positions.copy()\n",
    "    pbest_scores = np.full(n_particles, np.inf, dtype=np.float32)\n",
    "\n",
    "    history = []\n",
    "    eval_model = DeepRegressor(input_dim=input_dim, hidden_dims=hidden_dims).to(device)\n",
    "\n",
    "    for i in range(n_particles):\n",
    "        vector_to_model(eval_model, positions[i])\n",
    "        score = 0.7 * mse_on_scaled_targets(eval_model, X_train_arr, y_train_scaled_arr) + 0.3 * mse_on_scaled_targets(eval_model, X_val_arr, y_val_scaled_arr)\n",
    "        pbest_scores[i] = score\n",
    "\n",
    "    gbest_idx = int(np.argmin(pbest_scores))\n",
    "    gbest_position = pbest_positions[gbest_idx].copy()\n",
    "    gbest_score = float(pbest_scores[gbest_idx])\n",
    "\n",
    "    for it in range(n_iters):\n",
    "        r1 = np.random.rand(n_particles, dim).astype(np.float32)\n",
    "        r2 = np.random.rand(n_particles, dim).astype(np.float32)\n",
    "        velocities = inertia * velocities + c1 * r1 * (pbest_positions - positions) + c2 * r2 * (gbest_position[None, :] - positions)\n",
    "        positions = np.clip(positions + velocities, -position_clip, position_clip)\n",
    "\n",
    "        train_scores = []\n",
    "        val_scores = []\n",
    "        objective_scores = []\n",
    "\n",
    "        for i in range(n_particles):\n",
    "            vector_to_model(eval_model, positions[i])\n",
    "            train_mse = mse_on_scaled_targets(eval_model, X_train_arr, y_train_scaled_arr)\n",
    "            val_mse = mse_on_scaled_targets(eval_model, X_val_arr, y_val_scaled_arr)\n",
    "            score = 0.7 * train_mse + 0.3 * val_mse\n",
    "\n",
    "            train_scores.append(train_mse)\n",
    "            val_scores.append(val_mse)\n",
    "            objective_scores.append(score)\n",
    "\n",
    "            if score < pbest_scores[i]:\n",
    "                pbest_scores[i] = score\n",
    "                pbest_positions[i] = positions[i].copy()\n",
    "\n",
    "        best_idx = int(np.argmin(pbest_scores))\n",
    "        if float(pbest_scores[best_idx]) < gbest_score:\n",
    "            gbest_score = float(pbest_scores[best_idx])\n",
    "            gbest_position = pbest_positions[best_idx].copy()\n",
    "\n",
    "        history.append({\n",
    "            'generation': it + 1,\n",
    "            'best_train_mse': float(np.min(train_scores)),\n",
    "            'best_val_mse': float(np.min(val_scores)),\n",
    "            'mean_val_mse': float(np.mean(val_scores)),\n",
    "        })\n",
    "\n",
    "    final_model = DeepRegressor(input_dim=input_dim, hidden_dims=hidden_dims).to(device)\n",
    "    vector_to_model(final_model, gbest_position)\n",
    "    return final_model, pd.DataFrame(history), gbest_position, gbest_score\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "af37ef16",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Размер подвыборки для PSO (train): (764, 53)\n",
      "Размер подвыборки для PSO (val): (191, 53)\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Подготовка данных для PSO и обучения\n",
    "# Для ускорения PSO используется подмножество обучающей и валидационной выборок.\n",
    "train_subset_size = min(len(X_train_proc), 1200)\n",
    "val_subset_size = min(len(X_val_proc), 600)\n",
    "\n",
    "train_idx = np.random.choice(len(X_train_proc), size=train_subset_size, replace=False)\n",
    "val_idx = np.random.choice(len(X_val_proc), size=val_subset_size, replace=False)\n",
    "\n",
    "X_train_pso = X_train_proc[train_idx]\n",
    "y_train_pso = y_train_scaled[train_idx]\n",
    "X_val_pso = X_val_proc[val_idx]\n",
    "y_val_pso = y_val_scaled[val_idx]\n",
    "\n",
    "print('Размер подвыборки для PSO (train):', X_train_pso.shape)\n",
    "print('Размер подвыборки для PSO (val):', X_val_pso.shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "78a75ba3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Лучшее значение целевой функции PSO: 0.722468\n"
     ]
    },
    {
     "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>generation</th>\n",
       "      <th>best_train_mse</th>\n",
       "      <th>best_val_mse</th>\n",
       "      <th>mean_val_mse</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>31</td>\n",
       "      <td>0.696398</td>\n",
       "      <td>0.784530</td>\n",
       "      <td>2.131233</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>32</td>\n",
       "      <td>0.700821</td>\n",
       "      <td>0.772979</td>\n",
       "      <td>1.822161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>33</td>\n",
       "      <td>0.709175</td>\n",
       "      <td>0.790722</td>\n",
       "      <td>1.857363</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>34</td>\n",
       "      <td>0.711997</td>\n",
       "      <td>0.776590</td>\n",
       "      <td>1.975633</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>35</td>\n",
       "      <td>0.704757</td>\n",
       "      <td>0.763446</td>\n",
       "      <td>1.760829</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    generation  best_train_mse  best_val_mse  mean_val_mse\n",
       "30          31        0.696398      0.784530      2.131233\n",
       "31          32        0.700821      0.772979      1.822161\n",
       "32          33        0.709175      0.790722      1.857363\n",
       "33          34        0.711997      0.776590      1.975633\n",
       "34          35        0.704757      0.763446      1.760829"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Инициализация весов методом PSO\n",
    "pso_model, pso_history, pso_best_vector, pso_best_score = pso_initialize(\n",
    "    input_dim=X_train_proc.shape[1],\n",
    "    X_train_arr=X_train_pso,\n",
    "    y_train_scaled_arr=y_train_pso,\n",
    "    X_val_arr=X_val_pso,\n",
    "    y_val_scaled_arr=y_val_pso,\n",
    "    hidden_dims=hidden_dims,\n",
    "    n_particles=18,\n",
    "    n_iters=35,\n",
    "    inertia=0.72,\n",
    "    c1=1.45,\n",
    "    c2=1.45,\n",
    "    position_clip=2.5,\n",
    ")\n",
    "\n",
    "print('Лучшее значение целевой функции PSO:', round(pso_best_score, 6))\n",
    "display(pso_history.tail())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e4a9e5ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Метрики модели после PSO на валидации: {'r2': 0.2891269768780089, 'rmse': 2450.9653119331324, 'mae': 2056.5326739406087}\n",
      "Метрики модели после PSO на тесте: {'r2': 0.3081837408675284, 'rmse': 2293.337173577302, 'mae': 1841.1816477755622}\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Оценка модели сразу после PSO\n",
    "pso_pred_val = predict_model(pso_model, X_val_proc)\n",
    "pso_pred_test = predict_model(pso_model, X_test_proc)\n",
    "\n",
    "metrics_pso_val = evaluate_predictions(y_val.values, pso_pred_val)\n",
    "metrics_pso_test = evaluate_predictions(y_test.values, pso_pred_test)\n",
    "\n",
    "print('Метрики модели после PSO на валидации:', metrics_pso_val)\n",
    "print('Метрики модели после PSO на тесте:', metrics_pso_test)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "f62126ff",
   "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>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>val_rmse</th>\n",
       "      <th>val_r2</th>\n",
       "      <th>lr</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>19</td>\n",
       "      <td>0.108917</td>\n",
       "      <td>2169.016356</td>\n",
       "      <td>0.443272</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>20</td>\n",
       "      <td>0.104012</td>\n",
       "      <td>2183.118654</td>\n",
       "      <td>0.436009</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>21</td>\n",
       "      <td>0.100108</td>\n",
       "      <td>2184.437320</td>\n",
       "      <td>0.435327</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>22</td>\n",
       "      <td>0.096943</td>\n",
       "      <td>2191.882829</td>\n",
       "      <td>0.431471</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>23</td>\n",
       "      <td>0.093665</td>\n",
       "      <td>2191.894312</td>\n",
       "      <td>0.431465</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    epoch  train_loss     val_rmse    val_r2      lr\n",
       "18     19    0.108917  2169.016356  0.443272  0.0005\n",
       "19     20    0.104012  2183.118654  0.436009  0.0005\n",
       "20     21    0.100108  2184.437320  0.435327  0.0005\n",
       "21     22    0.096943  2191.882829  0.431471  0.0005\n",
       "22     23    0.093665  2191.894312  0.431465  0.0005"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Дообучение модели после PSO\n",
    "train_ds = tensor_dataset_from_numpy(X_train_proc, y_train_scaled)\n",
    "val_ds = tensor_dataset_from_numpy(X_val_proc, y_val_scaled)\n",
    "\n",
    "train_loader = DataLoader(train_ds, batch_size=128, shuffle=True)\n",
    "val_loader = DataLoader(val_ds, batch_size=256, shuffle=False)\n",
    "\n",
    "finetuned_model = DeepRegressor(input_dim=X_train_proc.shape[1], hidden_dims=hidden_dims).to(device)\n",
    "vector_to_model(finetuned_model, pso_best_vector)\n",
    "\n",
    "criterion = nn.SmoothL1Loss()\n",
    "optimizer = torch.optim.Adam(finetuned_model.parameters(), lr=1e-3, weight_decay=1e-4)\n",
    "scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=5)\n",
    "\n",
    "best_state = None\n",
    "best_val_rmse = np.inf\n",
    "patience = 12\n",
    "wait = 0\n",
    "history_finetune = []\n",
    "\n",
    "for epoch in range(1, 81):\n",
    "    finetuned_model.train()\n",
    "    train_losses = []\n",
    "    for xb, yb in train_loader:\n",
    "        xb = xb.to(device)\n",
    "        yb = yb.to(device).view(-1)\n",
    "        optimizer.zero_grad()\n",
    "        pred = finetuned_model(xb).view(-1)\n",
    "        loss = criterion(pred, yb)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        train_losses.append(float(loss.item()))\n",
    "\n",
    "    finetuned_model.eval()\n",
    "    val_scaled_preds = []\n",
    "    with torch.no_grad():\n",
    "        for xb, yb in val_loader:\n",
    "            xb = xb.to(device)\n",
    "            pred = finetuned_model(xb).cpu().numpy().ravel()\n",
    "            val_scaled_preds.append(pred)\n",
    "    val_scaled_preds = np.concatenate(val_scaled_preds)\n",
    "    val_preds = scale_back_predictions(val_scaled_preds)\n",
    "    current_val_rmse = rmse(y_val.values, val_preds)\n",
    "    current_val_r2 = float(r2_score(y_val.values, val_preds))\n",
    "    current_train_loss = float(np.mean(train_losses)) if train_losses else np.nan\n",
    "\n",
    "    history_finetune.append({\n",
    "        'epoch': epoch,\n",
    "        'train_loss': current_train_loss,\n",
    "        'val_rmse': current_val_rmse,\n",
    "        'val_r2': current_val_r2,\n",
    "        'lr': optimizer.param_groups[0]['lr']\n",
    "    })\n",
    "\n",
    "    scheduler.step(current_val_rmse)\n",
    "\n",
    "    if current_val_rmse < best_val_rmse:\n",
    "        best_val_rmse = current_val_rmse\n",
    "        best_state = {k: v.detach().cpu().clone() for k, v in finetuned_model.state_dict().items()}\n",
    "        wait = 0\n",
    "    else:\n",
    "        wait += 1\n",
    "        if wait >= patience:\n",
    "            break\n",
    "\n",
    "if best_state is not None:\n",
    "    finetuned_model.load_state_dict(best_state)\n",
    "\n",
    "history_finetune_df = pd.DataFrame(history_finetune)\n",
    "display(history_finetune_df.tail())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "4e2834e8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Метрики модели после дообучения на валидации: {'r2': 0.45775908411868116, 'rmse': 2140.608721605118, 'mae': 1786.8976846265543}\n",
      "Метрики модели после дообучения на тесте: {'r2': 0.378612289071136, 'rmse': 2173.471042836778, 'mae': 1677.7576817468619}\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Итоговая оценка дообученной модели\n",
    "finetune_pred_val = predict_model(finetuned_model, X_val_proc)\n",
    "finetune_pred_test = predict_model(finetuned_model, X_test_proc)\n",
    "\n",
    "metrics_finetune_val = evaluate_predictions(y_val.values, finetune_pred_val)\n",
    "metrics_finetune_test = evaluate_predictions(y_test.values, finetune_pred_test)\n",
    "\n",
    "print('Метрики модели после дообучения на валидации:', metrics_finetune_val)\n",
    "print('Метрики модели после дообучения на тесте:', metrics_finetune_test)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "85e93e8e",
   "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>r2_test</th>\n",
       "      <th>rmse_test</th>\n",
       "      <th>mae_test</th>\n",
       "      <th>r2_val</th>\n",
       "      <th>rmse_val</th>\n",
       "      <th>mae_val</th>\n",
       "      <th>n_original_features</th>\n",
       "      <th>n_processed_features</th>\n",
       "      <th>hidden_layers</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Глубокая нейросеть: PSO + дообучение</td>\n",
       "      <td>0.378612</td>\n",
       "      <td>2173.471043</td>\n",
       "      <td>1677.757682</td>\n",
       "      <td>0.457759</td>\n",
       "      <td>2140.608722</td>\n",
       "      <td>1786.897685</td>\n",
       "      <td>14</td>\n",
       "      <td>53</td>\n",
       "      <td>(128, 64, 32, 16)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Глубокая нейросеть после PSO</td>\n",
       "      <td>0.308184</td>\n",
       "      <td>2293.337174</td>\n",
       "      <td>1841.181648</td>\n",
       "      <td>0.289127</td>\n",
       "      <td>2450.965312</td>\n",
       "      <td>2056.532674</td>\n",
       "      <td>14</td>\n",
       "      <td>53</td>\n",
       "      <td>(128, 64, 32, 16)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                  model   r2_test    rmse_test     mae_test    r2_val     rmse_val      mae_val  n_original_features  n_processed_features      hidden_layers\n",
       "0  Глубокая нейросеть: PSO + дообучение  0.378612  2173.471043  1677.757682  0.457759  2140.608722  1786.897685                   14                    53  (128, 64, 32, 16)\n",
       "1          Глубокая нейросеть после PSO  0.308184  2293.337174  1841.181648  0.289127  2450.965312  2056.532674                   14                    53  (128, 64, 32, 16)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Сводная таблица моделей\n",
    "results_df = pd.DataFrame([\n",
    "    {\n",
    "        'model': 'Глубокая нейросеть после PSO',\n",
    "        'r2_test': metrics_pso_test['r2'],\n",
    "        'rmse_test': metrics_pso_test['rmse'],\n",
    "        'mae_test': metrics_pso_test['mae'],\n",
    "        'r2_val': metrics_pso_val['r2'],\n",
    "        'rmse_val': metrics_pso_val['rmse'],\n",
    "        'mae_val': metrics_pso_val['mae'],\n",
    "        'n_original_features': X.shape[1],\n",
    "        'n_processed_features': X_train_proc.shape[1],\n",
    "        'hidden_layers': str(hidden_dims),\n",
    "    },\n",
    "    {\n",
    "        'model': 'Глубокая нейросеть: PSO + дообучение',\n",
    "        'r2_test': metrics_finetune_test['r2'],\n",
    "        'rmse_test': metrics_finetune_test['rmse'],\n",
    "        'mae_test': metrics_finetune_test['mae'],\n",
    "        'r2_val': metrics_finetune_val['r2'],\n",
    "        'rmse_val': metrics_finetune_val['rmse'],\n",
    "        'mae_val': metrics_finetune_val['mae'],\n",
    "        'n_original_features': X.shape[1],\n",
    "        'n_processed_features': X_train_proc.shape[1],\n",
    "        'hidden_layers': str(hidden_dims),\n",
    "    }\n",
    "]).sort_values(['r2_test', 'rmse_test'], ascending=[False, True]).reset_index(drop=True)\n",
    "\n",
    "best_model_row = results_df.iloc[0]\n",
    "\n",
    "display(results_df)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "e3a9dac1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAn8AAAJwCAYAAAD4GAcuAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA2wVJREFUeJzs3Xd8U+X+B/DPyU4zuze0ZcpesgRxoAgooqg/BJUlOFAUF3BFES9eUPDKcCDqBRQn4MAtFwdeZSl7ySzQ0t0madLsc35/hMSmSdskzWy+79fLlzQ5SZ6cnJzzzfN8n+/DcBzHgRBCCCGExAVepBtACCGEEELCh4I/QgghhJA4QsEfIYQQQkgcoeCPEEIIISSOUPBHCCGEEBJHKPgjhBBCCIkjFPwRQgghhMQRCv4IIYQQQuKIININIIQQQgiJNiaTCdXV1RAIBEhLS4t0c4KKev4IIYQQEjavvvoqNBqN6+/ly5fDYDBErkH1/Pe//8WYMWOgVqshlUqRnZ2NRx55JNLNCjqGlncLvsmTJ2PTpk3Q6/WRbgohhBASVUaMGIHLLrsMjz/+OLZv3477778fWq0WPF5k+6Nef/11PPzwwxgyZAimTp2K7OxsAEDbtm3RoUOHiLYt2Cj4C5Kqqiq8//77+PXXX7F9+3ZUVlbiuuuuQ+/evXHHHXegd+/ekW4iIYQQEnG//PILxowZA51OBx6Ph5dffhmPPvpoRNt08uRJdO/eHVOmTMHrr78OhmEi2p5Qo+AvCD766CNMnz4der0eeXl5sFqtKC0tRe/evXHgwAFYrVZMmjQJa9asgUgkinRzCSGEkIjSaDQ4duwYcnNzkZOTE+nm4OGHH8aXX36JkydPQigURro5IUc5fy3022+/4a677kJGRgZ+++03nD17FsOHD4dEIsGePXtw8eJF3HnnnVi/fj1mz57t9thly5Zh8ODBSE5OhlQqRd++fbFp0yaP12AYBs8995zrb5vNhlGjRiEpKQlHjx51bdPUf1dddRUA4OeffwbDMPj555/dXmP06NEer3PVVVe5HudUWFgIhmGwbt06t9uPHz+O2267DUlJSZBIJOjXrx+2bNni8V40Gg1mz56NvLw8iMVi5OTk4J577kFlZWWj7bt48SLy8vLQr18/11C6P+8DAIqLizF16lSkp6dDLBaja9eu+M9//uPRPm+8Pd/SpUvd9mtzj2/sv7y8PNd2zn27bNkyvPLKK2jbti2kUimGDRuGw4cPezyvr/sccKQieHv9yZMne2z77bffYtiwYVAoFFAqlbj88svxwQcfuO73dly88MIL4PF4btv9+uuvuP3229GmTRuIxWLk5uZi9uzZMBqNbo997rnn0KVLF8jlciiVSgwcOBCff/652za+PtfkyZMhl8s93tOmTZs8jperrroK3bp189h22bJlYBgGhYWFrtvy8vJw4403emzr1NjxuGvXLtxwww1QqVRISEjAsGHD8NtvvzX6PE7/+9//MGTIEKSkpEAikaCgoABz5syByWRybbNu3TowDIM//vjD7bGVlZUex+y5c+fw4IMPolOnTpBKpUhOTsbtt9/u9h4Bx/6rf0w6Bfqdcu4Xb+c1uVzudvw530/9NrEsix49eng952zatAn9+vWDQqFwO6aXLVvm8Vr1hWK/NeT8Ljf1X/33rtFo8OijjyI3NxdisRjt27fHiy++CJZl3Z6XZVmsWLEC3bt3h0QiQWpqKm644QbXe/H1OgAA5eXlmDZtGtLT0yGRSNCzZ0+sX7++yfchFAqRl5eHJ598EhaLxW3bM2fO4Pbbb0dSUhISEhIwcOBAfP31127b1P+eqNVqDBo0CDk5OY2etxtyPt75n1gsRseOHbF48WLU78d67rnnwDCM67riTV5enttnsHPnTvTt2xcPPvig65ju1q0b3nrrLY/HGgwGPP74467Pq1OnTli2bBka9qUxDIOHHnoI77//Pjp16gSJRIK+ffti+/btbts521vfTz/9BLFYjPvvv9/t9pZcy+qj2b4ttGTJErAsi48++gh9+/b1uD8lJQXvvvsujh49ijfffBMLFixwzRpasWIFxowZg4kTJ8JiseCjjz7C7bffjq+++gqjR49u9DXvvfde/Pzzz9i6dSu6dOkCAHjvvfdc9//6669Ys2YNXnnlFaSkpAAA0tPTG32+7du345tvvgno/QPAkSNHcMUVVyA7Oxtz586FTCbDJ598grFjx2Lz5s245ZZbAAB6vR5Dhw7FsWPHMHXqVPTp0weVlZXYsmULioqKXG2tT6vVYuTIkRAKhfjmm2+8Xtibex9lZWUYOHCg64uYmpqKb7/9FtOmTYNOp/N7uEGj0WDx4sV+Pea6667DPffc43bbyy+/jJqaGo9t3333XdTW1mLm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KNjtdrz66qtuj3/llVfAMIzrPO20Y8cOt1y8Cxcu4IsvvsD111/v0Rbnde/BBx/E4MGDcd9997n2dbC/d9TzFwS5ubn44osvUFJSgt9++w1Lly7F/v37sXr1avTq1Qu9evXyCBhGjx6Nf//737jhhhswYcIElJeX47XXXkP79u1x8ODBJl9vxIgRuOuuu/DUU0/hpptuQmZmpt9t/uGHH/DCCy8gOTnZ78c29Nprr2HIkCHo3r07pk+fjoKCApSVlWHHjh0oKirCgQMHADiGDjZt2oTbb78dU6dORd++fVFdXY0tW7Zg9erV6Nmzp9fnX7BgATZv3ozp06fjt99+c/tV5sv7WLJkCX766ScMGDAA06dPR5cuXVBdXY29e/fiv//9r085lD/88AOuu+66oPziak779u0xZMgQPPDAAzCbzVi+fDmSk5Pdfq36us9fe+01zJ8/H6mpqTh9+rRbfqrNZsOZM2ewdetWXHfddVAqlXjllVdw77334vLLL8eECROQmJiIAwcOoK6uzqMGmFNGRgaWLl2Ke++9F3fddRdGjRqFzp07o127dnjiiSdQXFwMpVKJzZs3e83XGzlyJEaOHImsrCxUV1fjvffeQ0lJiasXx9fnCrWKigp89913AICSkhK8+OKLUKlUuPrqq3HixAm3bXk8Ht5++22MHDkSXbt2xZQpU5CdnY3i4mL89NNPUCqVHkPT9T344IMQCoXo1KkTeDwe/ve//+GDDz7AjTfe2GyeoDc33ngj3nvvPahUKnTp0gU7duzAf//734C//8H4TjXmhx9+wPvvv99kQfwjR47gqaeewnPPPYfLL7884NdqTrD3mzdPPvkktmzZghtvvBGTJ09G3759YTAYcOjQIWzatAmFhYVISUnB1VdfjbvvvhsrV67EyZMnccMNN4BlWfz666+4+uqr8dBDD/n8mjNmzMCbb76JyZMn488//0ReXh42bdqE3377DcuXL/fIZ9uxYwcEAoFr2HfVqlXo3bu3qzds7ty5+PDDDzFy5EjMmjULSUlJWL9+Pc6ePYvNmzd75NG19PqzdetWFBUVuYZ933//fYwZM8bjmPnxxx/dhn1PnTrVaDmUadOm4Y033sDkyZPxxx9/ID8/H59//jm2bduGJUuWuNp600034eqrr8bTTz+NwsJC9OzZEz/88AO++OILPProox6TE7t1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",
      "text/plain": [
       "<Figure size 700x700 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Визуальное сравнение предсказаний лучшей модели\n",
    "best_model_name = best_model_row['model']\n",
    "if best_model_name == 'Глубокая нейросеть после PSO':\n",
    "    best_preds = pso_pred_test\n",
    "else:\n",
    "    best_preds = finetune_pred_test\n",
    "\n",
    "plt.figure(figsize=(7, 7))\n",
    "plt.scatter(y_test.values, best_preds, alpha=0.6)\n",
    "min_v = float(min(y_test.min(), best_preds.min()))\n",
    "max_v = float(max(y_test.max(), best_preds.max()))\n",
    "plt.plot([min_v, max_v], [min_v, max_v], linestyle='--')\n",
    "plt.xlabel('Фактические значения')\n",
    "plt.ylabel('Предсказанные значения')\n",
    "plt.title('Фактические и предсказанные значения на тестовой выборке')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "9c0725e8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\n",
      "Зависимая переменная: amount\n",
      "Число исходных признаков: 14\n",
      "Число признаков после кодирования: 53\n",
      "Архитектура скрытых слоёв: (128, 64, 32, 16)\n",
      "Использовано log1p-преобразование цели: False\n",
      "\n",
      "Метрики моделей на тестовой выборке:\n"
     ]
    },
    {
     "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>r2_test</th>\n",
       "      <th>rmse_test</th>\n",
       "      <th>mae_test</th>\n",
       "      <th>r2_val</th>\n",
       "      <th>rmse_val</th>\n",
       "      <th>mae_val</th>\n",
       "      <th>n_original_features</th>\n",
       "      <th>n_processed_features</th>\n",
       "      <th>hidden_layers</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Глубокая нейросеть: PSO + дообучение</td>\n",
       "      <td>0.378612</td>\n",
       "      <td>2173.471043</td>\n",
       "      <td>1677.757682</td>\n",
       "      <td>0.457759</td>\n",
       "      <td>2140.608722</td>\n",
       "      <td>1786.897685</td>\n",
       "      <td>14</td>\n",
       "      <td>53</td>\n",
       "      <td>(128, 64, 32, 16)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Глубокая нейросеть после PSO</td>\n",
       "      <td>0.308184</td>\n",
       "      <td>2293.337174</td>\n",
       "      <td>1841.181648</td>\n",
       "      <td>0.289127</td>\n",
       "      <td>2450.965312</td>\n",
       "      <td>2056.532674</td>\n",
       "      <td>14</td>\n",
       "      <td>53</td>\n",
       "      <td>(128, 64, 32, 16)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                  model   r2_test    rmse_test     mae_test    r2_val     rmse_val      mae_val  n_original_features  n_processed_features      hidden_layers\n",
       "0  Глубокая нейросеть: PSO + дообучение  0.378612  2173.471043  1677.757682  0.457759  2140.608722  1786.897685                   14                    53  (128, 64, 32, 16)\n",
       "1          Глубокая нейросеть после PSO  0.308184  2293.337174  1841.181648  0.289127  2450.965312  2056.532674                   14                    53  (128, 64, 32, 16)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Лучшая модель:\n"
     ]
    },
    {
     "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>r2_test</th>\n",
       "      <th>rmse_test</th>\n",
       "      <th>mae_test</th>\n",
       "      <th>r2_val</th>\n",
       "      <th>rmse_val</th>\n",
       "      <th>mae_val</th>\n",
       "      <th>n_original_features</th>\n",
       "      <th>n_processed_features</th>\n",
       "      <th>hidden_layers</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Глубокая нейросеть: PSO + дообучение</td>\n",
       "      <td>0.378612</td>\n",
       "      <td>2173.471043</td>\n",
       "      <td>1677.757682</td>\n",
       "      <td>0.457759</td>\n",
       "      <td>2140.608722</td>\n",
       "      <td>1786.897685</td>\n",
       "      <td>14</td>\n",
       "      <td>53</td>\n",
       "      <td>(128, 64, 32, 16)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                  model   r2_test    rmse_test     mae_test    r2_val     rmse_val      mae_val n_original_features n_processed_features      hidden_layers\n",
       "0  Глубокая нейросеть: PSO + дообучение  0.378612  2173.471043  1677.757682  0.457759  2140.608722  1786.897685                  14                   53  (128, 64, 32, 16)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Последние поколения PSO:\n"
     ]
    },
    {
     "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>generation</th>\n",
       "      <th>best_train_mse</th>\n",
       "      <th>best_val_mse</th>\n",
       "      <th>mean_val_mse</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>31</td>\n",
       "      <td>0.696398</td>\n",
       "      <td>0.784530</td>\n",
       "      <td>2.131233</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>32</td>\n",
       "      <td>0.700821</td>\n",
       "      <td>0.772979</td>\n",
       "      <td>1.822161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>33</td>\n",
       "      <td>0.709175</td>\n",
       "      <td>0.790722</td>\n",
       "      <td>1.857363</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>34</td>\n",
       "      <td>0.711997</td>\n",
       "      <td>0.776590</td>\n",
       "      <td>1.975633</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>35</td>\n",
       "      <td>0.704757</td>\n",
       "      <td>0.763446</td>\n",
       "      <td>1.760829</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    generation  best_train_mse  best_val_mse  mean_val_mse\n",
       "30          31        0.696398      0.784530      2.131233\n",
       "31          32        0.700821      0.772979      1.822161\n",
       "32          33        0.709175      0.790722      1.857363\n",
       "33          34        0.711997      0.776590      1.975633\n",
       "34          35        0.704757      0.763446      1.760829"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Последние эпохи дообучения:\n"
     ]
    },
    {
     "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>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>val_rmse</th>\n",
       "      <th>val_r2</th>\n",
       "      <th>lr</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>19</td>\n",
       "      <td>0.108917</td>\n",
       "      <td>2169.016356</td>\n",
       "      <td>0.443272</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>20</td>\n",
       "      <td>0.104012</td>\n",
       "      <td>2183.118654</td>\n",
       "      <td>0.436009</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>21</td>\n",
       "      <td>0.100108</td>\n",
       "      <td>2184.437320</td>\n",
       "      <td>0.435327</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>22</td>\n",
       "      <td>0.096943</td>\n",
       "      <td>2191.882829</td>\n",
       "      <td>0.431471</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>23</td>\n",
       "      <td>0.093665</td>\n",
       "      <td>2191.894312</td>\n",
       "      <td>0.431465</td>\n",
       "      <td>0.0005</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    epoch  train_loss     val_rmse    val_r2      lr\n",
       "18     19    0.108917  2169.016356  0.443272  0.0005\n",
       "19     20    0.104012  2183.118654  0.436009  0.0005\n",
       "20     21    0.100108  2184.437320  0.435327  0.0005\n",
       "21     22    0.096943  2191.882829  0.431471  0.0005\n",
       "22     23    0.093665  2191.894312  0.431465  0.0005"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "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>y_true</th>\n",
       "      <th>y_pred_best</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2895.0</td>\n",
       "      <td>5444.335449</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1133.0</td>\n",
       "      <td>2235.909424</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>7122.0</td>\n",
       "      <td>6902.805176</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>5047.0</td>\n",
       "      <td>6711.173828</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6139.0</td>\n",
       "      <td>3275.937744</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2962.0</td>\n",
       "      <td>4857.929199</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>4936.0</td>\n",
       "      <td>6215.627930</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>3760.0</td>\n",
       "      <td>4113.935547</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>8797.0</td>\n",
       "      <td>4577.139648</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>4932.0</td>\n",
       "      <td>4375.787109</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   y_true  y_pred_best\n",
       "0  2895.0  5444.335449\n",
       "1  1133.0  2235.909424\n",
       "2  7122.0  6902.805176\n",
       "3  5047.0  6711.173828\n",
       "4  6139.0  3275.937744\n",
       "5  2962.0  4857.929199\n",
       "6  4936.0  6215.627930\n",
       "7  3760.0  4113.935547\n",
       "8  8797.0  4577.139648\n",
       "9  4932.0  4375.787109"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# === КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\n",
    "print('=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===')\n",
    "print('Зависимая переменная:', target_col)\n",
    "print('Число исходных признаков:', X.shape[1])\n",
    "print('Число признаков после кодирования:', X_train_proc.shape[1])\n",
    "print('Архитектура скрытых слоёв:', hidden_dims)\n",
    "print('Использовано log1p-преобразование цели:', use_log_target)\n",
    "print('')\n",
    "print('Метрики моделей на тестовой выборке:')\n",
    "display(results_df[['model', 'r2_test', 'rmse_test', 'mae_test', 'r2_val', 'rmse_val', 'mae_val', 'n_original_features', 'n_processed_features', 'hidden_layers']])\n",
    "print('Лучшая модель:')\n",
    "display(best_model_row.to_frame().T)\n",
    "print('')\n",
    "print('Последние поколения PSO:')\n",
    "display(pso_history.tail())\n",
    "print('Последние эпохи дообучения:')\n",
    "display(history_finetune_df.tail())\n",
    "print('')\n",
    "if best_model_name == 'Глубокая нейросеть после PSO':\n",
    "    preds = pso_pred_test\n",
    "    col_name = 'y_pred_best'\n",
    "else:\n",
    "    preds = finetune_pred_test\n",
    "    col_name = 'y_pred_best'\n",
    "\n",
    "display(pd.DataFrame({'y_true': y_test.values[:10], col_name: preds[:10]}))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "092126e7",
   "metadata": {},
   "source": [
    "Итог\n",
    "\n",
    "Зависимой переменной выбрана amount. Построена глубокая нейросеть с архитектурой (128, 64, 32, 16), сначала обученная методом PSO, затем дополнительно дообученная градиентным методом.\n",
    "\n",
    "Лучшая модель — PSO + дообучение: на тестовой выборке получено R² = 0.379, RMSE ≈ 2173.47, MAE ≈ 1677.76. Модель только после PSO показала более слабый результат (R² = 0.308, RMSE ≈ 2293.34, MAE ≈ 1841.18).\n",
    "\n",
    "Следовательно, дообучение после весовой эволюции существенно улучшает качество, поэтому менее плохой является глубокая нейросеть PSO + fine-tuning, хотя все равно результаты неудовлетворительные, но надо как можно быстрее делать как можно больше преактик, так что даже не хочется тут сидеть опять целый день с одной задачей чтобы результат стал незначительно лучше..."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
