{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "879f8b25",
   "metadata": {},
   "source": [
    "# Классификация качества вина двумя нейросетями\n",
    "\n",
    "В работе автоматически определяется зависимая переменная, выполняется предобработка данных и сравниваются два подхода:\n",
    "\n",
    "1. классическая нейросеть;\n",
    "2. нейросеть с эволюцией весов (генетический алгоритм).\n",
    "\n",
    "Во всех текстовых частях используются краткие технические формулировки. Финального текстового вывода в ноутбуке нет."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8ea436e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import os\n",
    "import glob\n",
    "import copy\n",
    "import random\n",
    "import warnings\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.impute import SimpleImputer\n",
    "from sklearn.metrics import (\n",
    "    accuracy_score,\n",
    "    balanced_accuracy_score,\n",
    "    f1_score,\n",
    "    precision_score,\n",
    "    recall_score,\n",
    "    classification_report,\n",
    "    confusion_matrix,\n",
    ")\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.neural_network import MLPClassifier\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import OneHotEncoder, StandardScaler, LabelEncoder\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "SEED = 42\n",
    "np.random.seed(SEED)\n",
    "random.seed(SEED)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c14936a",
   "metadata": {},
   "source": [
    "## Загрузка данных"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "12b69921",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Используемый файл: cleaned_red_wine.csv\n",
      "Форма датасета: (1359, 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>fixed acidity</th>\n",
       "      <th>volatile acidity</th>\n",
       "      <th>citric acid</th>\n",
       "      <th>residual sugar</th>\n",
       "      <th>chlorides</th>\n",
       "      <th>free sulfur dioxide</th>\n",
       "      <th>total sulfur dioxide</th>\n",
       "      <th>density</th>\n",
       "      <th>pH</th>\n",
       "      <th>sulphates</th>\n",
       "      <th>alcohol</th>\n",
       "      <th>quality</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>7.4</td>\n",
       "      <td>0.70</td>\n",
       "      <td>0.00</td>\n",
       "      <td>1.9</td>\n",
       "      <td>0.076</td>\n",
       "      <td>11.0</td>\n",
       "      <td>34.0</td>\n",
       "      <td>0.9978</td>\n",
       "      <td>3.51</td>\n",
       "      <td>0.56</td>\n",
       "      <td>9.4</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>7.8</td>\n",
       "      <td>0.88</td>\n",
       "      <td>0.00</td>\n",
       "      <td>2.6</td>\n",
       "      <td>0.098</td>\n",
       "      <td>25.0</td>\n",
       "      <td>67.0</td>\n",
       "      <td>0.9968</td>\n",
       "      <td>3.20</td>\n",
       "      <td>0.68</td>\n",
       "      <td>9.8</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>7.8</td>\n",
       "      <td>0.76</td>\n",
       "      <td>0.04</td>\n",
       "      <td>2.3</td>\n",
       "      <td>0.092</td>\n",
       "      <td>15.0</td>\n",
       "      <td>54.0</td>\n",
       "      <td>0.9970</td>\n",
       "      <td>3.26</td>\n",
       "      <td>0.65</td>\n",
       "      <td>9.8</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>11.2</td>\n",
       "      <td>0.28</td>\n",
       "      <td>0.56</td>\n",
       "      <td>1.9</td>\n",
       "      <td>0.075</td>\n",
       "      <td>17.0</td>\n",
       "      <td>60.0</td>\n",
       "      <td>0.9980</td>\n",
       "      <td>3.16</td>\n",
       "      <td>0.58</td>\n",
       "      <td>9.8</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>7.4</td>\n",
       "      <td>0.66</td>\n",
       "      <td>0.00</td>\n",
       "      <td>1.8</td>\n",
       "      <td>0.075</td>\n",
       "      <td>13.0</td>\n",
       "      <td>40.0</td>\n",
       "      <td>0.9978</td>\n",
       "      <td>3.51</td>\n",
       "      <td>0.56</td>\n",
       "      <td>9.4</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   fixed acidity  volatile acidity  citric acid  residual sugar  chlorides  \\\n",
       "0            7.4              0.70         0.00             1.9      0.076   \n",
       "1            7.8              0.88         0.00             2.6      0.098   \n",
       "2            7.8              0.76         0.04             2.3      0.092   \n",
       "3           11.2              0.28         0.56             1.9      0.075   \n",
       "4            7.4              0.66         0.00             1.8      0.075   \n",
       "\n",
       "   free sulfur dioxide  total sulfur dioxide  density    pH  sulphates  \\\n",
       "0                 11.0                  34.0   0.9978  3.51       0.56   \n",
       "1                 25.0                  67.0   0.9968  3.20       0.68   \n",
       "2                 15.0                  54.0   0.9970  3.26       0.65   \n",
       "3                 17.0                  60.0   0.9980  3.16       0.58   \n",
       "4                 13.0                  40.0   0.9978  3.51       0.56   \n",
       "\n",
       "   alcohol  quality  \n",
       "0      9.4        5  \n",
       "1      9.8        5  \n",
       "2      9.8        5  \n",
       "3      9.8        6  \n",
       "4      9.4        5  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\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>dtype</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>fixed acidity</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>volatile acidity</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>citric acid</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>residual sugar</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>chlorides</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>free sulfur dioxide</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>total sulfur dioxide</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>density</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>pH</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>sulphates</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>alcohol</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>quality</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                        dtype\n",
       "fixed acidity         float64\n",
       "volatile acidity      float64\n",
       "citric acid           float64\n",
       "residual sugar        float64\n",
       "chlorides             float64\n",
       "free sulfur dioxide   float64\n",
       "total sulfur dioxide  float64\n",
       "density               float64\n",
       "pH                    float64\n",
       "sulphates             float64\n",
       "alcohol               float64\n",
       "quality                 int64"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "candidate_paths = [\n",
    "    \"cleaned_red_wine.csv\",\n",
    "    \"cleaned_white_wine.csv\",\n",
    "    \"cleaned_white_dataset.csv\",\n",
    "    \"winequality-white.csv\",\n",
    "    \"winequality-red.csv\",\n",
    "    \"data.csv\",\n",
    "    \"/mnt/data/cleaned_red_wine.csv\",\n",
    "    \"/mnt/data/cleaned_white_wine.csv\",\n",
    "    \"/mnt/data/cleaned_white_dataset.csv\",\n",
    "]\n",
    "\n",
    "csv_path = None\n",
    "for path in candidate_paths:\n",
    "    if os.path.exists(path):\n",
    "        csv_path = path\n",
    "        break\n",
    "\n",
    "if csv_path is None:\n",
    "    extra_candidates = []\n",
    "    for root in [\".\", \"/mnt/data\"]:\n",
    "        extra_candidates.extend(glob.glob(os.path.join(root, \"*.csv\")))\n",
    "    wine_like = [p for p in extra_candidates if \"wine\" in os.path.basename(p).lower() or \"cleaned\" in os.path.basename(p).lower()]\n",
    "    if wine_like:\n",
    "        csv_path = wine_like[0]\n",
    "\n",
    "if csv_path is None:\n",
    "    raise FileNotFoundError(\n",
    "        \"CSV-файл не найден. Поместите файл cleaned_red_wine.csv рядом с ноутбуком \"\n",
    "        \"или обновите список candidate_paths.\"\n",
    "    )\n",
    "\n",
    "df = pd.read_csv(csv_path)\n",
    "print(\"Используемый файл:\", csv_path)\n",
    "print(\"Форма датасета:\", df.shape)\n",
    "display(df.head())\n",
    "print(\"\\nТипы данных:\")\n",
    "display(df.dtypes.to_frame(\"dtype\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "931dc62e",
   "metadata": {},
   "source": [
    "## Нормализация названий столбцов и выбор зависимой переменной"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "23c905c7",
   "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>fixed acidity</td>\n",
       "      <td>fixed_acidity</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>volatile acidity</td>\n",
       "      <td>volatile_acidity</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>citric acid</td>\n",
       "      <td>citric_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>residual sugar</td>\n",
       "      <td>residual_sugar</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>chlorides</td>\n",
       "      <td>chlorides</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>free sulfur dioxide</td>\n",
       "      <td>free_sulfur_dioxide</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>total sulfur dioxide</td>\n",
       "      <td>total_sulfur_dioxide</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>density</td>\n",
       "      <td>density</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>pH</td>\n",
       "      <td>ph</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>sulphates</td>\n",
       "      <td>sulphates</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>alcohol</td>\n",
       "      <td>alcohol</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>quality</td>\n",
       "      <td>quality</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           original_name       normalized_name\n",
       "0          fixed acidity         fixed_acidity\n",
       "1       volatile acidity      volatile_acidity\n",
       "2            citric acid           citric_acid\n",
       "3         residual sugar        residual_sugar\n",
       "4              chlorides             chlorides\n",
       "5    free sulfur dioxide   free_sulfur_dioxide\n",
       "6   total sulfur dioxide  total_sulfur_dioxide\n",
       "7                density               density\n",
       "8                     pH                    ph\n",
       "9              sulphates             sulphates\n",
       "10               alcohol               alcohol\n",
       "11               quality               quality"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Выбранная зависимая переменная: quality\n",
      "Найденные идентификаторы / несодержательные поля: ['citric_acid']\n"
     ]
    }
   ],
   "source": [
    "\n",
    "def normalize_col(name: str) -> str:\n",
    "    name = str(name).strip().lower()\n",
    "    name = name.replace(\"%\", \"pct\")\n",
    "    name = name.replace(\"/\", \"_\")\n",
    "    name = name.replace(\"-\", \"_\")\n",
    "    name = name.replace(\" \", \"_\")\n",
    "    name = name.replace(\"(\", \"\")\n",
    "    name = name.replace(\")\", \"\")\n",
    "    name = name.replace(\".\", \"\")\n",
    "    while \"__\" in name:\n",
    "        name = name.replace(\"__\", \"_\")\n",
    "    return name.strip(\"_\")\n",
    "\n",
    "original_columns = list(df.columns)\n",
    "df.columns = [normalize_col(c) for c in df.columns]\n",
    "\n",
    "col_map = pd.DataFrame({\n",
    "    \"original_name\": original_columns,\n",
    "    \"normalized_name\": df.columns\n",
    "})\n",
    "display(col_map)\n",
    "\n",
    "preferred_targets = [\"quality\", \"wine_quality\", \"target\", \"label\", \"class\"]\n",
    "target_col = None\n",
    "for cand in preferred_targets:\n",
    "    if cand in df.columns:\n",
    "        target_col = cand\n",
    "        break\n",
    "\n",
    "if target_col is None:\n",
    "    # запасной вариант: последний дискретный столбец с малым числом уникальных значений\n",
    "    candidates = []\n",
    "    for c in df.columns:\n",
    "        nunique = df[c].nunique(dropna=True)\n",
    "        if 2 <= nunique <= min(20, max(2, int(0.1 * len(df)))):\n",
    "            candidates.append((c, nunique))\n",
    "    if candidates:\n",
    "        target_col = candidates[-1][0]\n",
    "    else:\n",
    "        target_col = df.columns[-1]\n",
    "\n",
    "print(\"Выбранная зависимая переменная:\", target_col)\n",
    "\n",
    "identifier_like = [c for c in df.columns if c.endswith(\"id\") or c in {\"id\", \"order_id\"}]\n",
    "print(\"Найденные идентификаторы / несодержательные поля:\", identifier_like)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60634b73",
   "metadata": {},
   "source": [
    "## Подготовка признаков"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fe84c055",
   "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_class</th>\n",
       "      <th>encoded_class</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>6</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>7</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>8</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  original_class  encoded_class\n",
       "0              3              0\n",
       "1              4              1\n",
       "2              5              2\n",
       "3              6              3\n",
       "4              7              4\n",
       "5              8              5"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Количество исходных признаков: 10\n",
      "Числовые признаки: ['fixed_acidity', 'volatile_acidity', 'residual_sugar', 'chlorides', 'free_sulfur_dioxide', 'total_sulfur_dioxide', 'density', 'ph', 'sulphates', 'alcohol']\n",
      "Категориальные признаки: []\n",
      "\n",
      "Распределение классов:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "quality\n",
       "3    0.007358\n",
       "4    0.038999\n",
       "5    0.424577\n",
       "6    0.393672\n",
       "7    0.122884\n",
       "8    0.012509\n",
       "Name: share, dtype: float64"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "y_raw = df[target_col].copy()\n",
    "X = df.drop(columns=[target_col] + [c for c in identifier_like if c in df.columns], errors=\"ignore\").copy()\n",
    "\n",
    "# целевая переменная в задаче классификации\n",
    "y_raw = y_raw.fillna(y_raw.mode(dropna=True).iloc[0] if not y_raw.dropna().empty else \"unknown\")\n",
    "y_raw = y_raw.astype(str)\n",
    "\n",
    "label_encoder = LabelEncoder()\n",
    "y = label_encoder.fit_transform(y_raw)\n",
    "\n",
    "class_mapping = pd.DataFrame({\n",
    "    \"original_class\": label_encoder.classes_,\n",
    "    \"encoded_class\": np.arange(len(label_encoder.classes_))\n",
    "})\n",
    "display(class_mapping)\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(\"Количество исходных признаков:\", X.shape[1])\n",
    "print(\"Числовые признаки:\", numeric_features)\n",
    "print(\"Категориальные признаки:\", categorical_features)\n",
    "print(\"\\nРаспределение классов:\")\n",
    "display(pd.Series(y_raw, name=target_col).value_counts(normalize=True).rename(\"share\").sort_index())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c7834abf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Число признаков после кодирования: 10\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>num__fixed_acidity</th>\n",
       "      <th>num__volatile_acidity</th>\n",
       "      <th>num__residual_sugar</th>\n",
       "      <th>num__chlorides</th>\n",
       "      <th>num__free_sulfur_dioxide</th>\n",
       "      <th>num__total_sulfur_dioxide</th>\n",
       "      <th>num__density</th>\n",
       "      <th>num__ph</th>\n",
       "      <th>num__sulphates</th>\n",
       "      <th>num__alcohol</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.168186</td>\n",
       "      <td>-0.886183</td>\n",
       "      <td>3.303011</td>\n",
       "      <td>-0.154895</td>\n",
       "      <td>-1.242235</td>\n",
       "      <td>-1.146691</td>\n",
       "      <td>0.762339</td>\n",
       "      <td>-0.257292</td>\n",
       "      <td>-0.448652</td>\n",
       "      <td>0.483347</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-0.332481</td>\n",
       "      <td>1.170245</td>\n",
       "      <td>1.096109</td>\n",
       "      <td>0.481179</td>\n",
       "      <td>1.762990</td>\n",
       "      <td>1.199576</td>\n",
       "      <td>-0.025076</td>\n",
       "      <td>-0.441990</td>\n",
       "      <td>-1.247285</td>\n",
       "      <td>-1.021208</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-1.111297</td>\n",
       "      <td>2.414925</td>\n",
       "      <td>-0.431747</td>\n",
       "      <td>-0.642551</td>\n",
       "      <td>-0.078922</td>\n",
       "      <td>-0.422534</td>\n",
       "      <td>-0.930860</td>\n",
       "      <td>1.774379</td>\n",
       "      <td>-1.185852</td>\n",
       "      <td>0.660354</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.168186</td>\n",
       "      <td>1.440828</td>\n",
       "      <td>-0.177104</td>\n",
       "      <td>-0.070085</td>\n",
       "      <td>-0.369750</td>\n",
       "      <td>-0.480467</td>\n",
       "      <td>0.623384</td>\n",
       "      <td>0.543063</td>\n",
       "      <td>-1.062985</td>\n",
       "      <td>-0.490189</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-1.278186</td>\n",
       "      <td>0.574963</td>\n",
       "      <td>-0.516628</td>\n",
       "      <td>-0.451729</td>\n",
       "      <td>-0.660578</td>\n",
       "      <td>-0.885994</td>\n",
       "      <td>-0.889688</td>\n",
       "      <td>1.281853</td>\n",
       "      <td>0.780015</td>\n",
       "      <td>0.129334</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   num__fixed_acidity  num__volatile_acidity  num__residual_sugar  \\\n",
       "0            0.168186              -0.886183             3.303011   \n",
       "1           -0.332481               1.170245             1.096109   \n",
       "2           -1.111297               2.414925            -0.431747   \n",
       "3            0.168186               1.440828            -0.177104   \n",
       "4           -1.278186               0.574963            -0.516628   \n",
       "\n",
       "   num__chlorides  num__free_sulfur_dioxide  num__total_sulfur_dioxide  \\\n",
       "0       -0.154895                 -1.242235                  -1.146691   \n",
       "1        0.481179                  1.762990                   1.199576   \n",
       "2       -0.642551                 -0.078922                  -0.422534   \n",
       "3       -0.070085                 -0.369750                  -0.480467   \n",
       "4       -0.451729                 -0.660578                  -0.885994   \n",
       "\n",
       "   num__density   num__ph  num__sulphates  num__alcohol  \n",
       "0      0.762339 -0.257292       -0.448652      0.483347  \n",
       "1     -0.025076 -0.441990       -1.247285     -1.021208  \n",
       "2     -0.930860  1.774379       -1.185852      0.660354  \n",
       "3      0.623384  0.543063       -1.062985     -0.490189  \n",
       "4     -0.889688  1.281853        0.780015      0.129334  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "X_trainval, X_test, y_trainval, y_test = train_test_split(\n",
    "    X, y, test_size=0.2, random_state=SEED, stratify=y\n",
    ")\n",
    "\n",
    "X_train, X_val, y_train, y_val = train_test_split(\n",
    "    X_trainval, y_trainval, test_size=0.25, random_state=SEED, stratify=y_trainval\n",
    ")\n",
    "\n",
    "numeric_transformer = Pipeline([\n",
    "    (\"imputer\", SimpleImputer(strategy=\"median\")),\n",
    "    (\"scaler\", StandardScaler()),\n",
    "])\n",
    "\n",
    "categorical_transformer = Pipeline([\n",
    "    (\"imputer\", SimpleImputer(strategy=\"most_frequent\")),\n",
    "    (\"onehot\", OneHotEncoder(handle_unknown=\"ignore\")),\n",
    "])\n",
    "\n",
    "preprocessor = ColumnTransformer([\n",
    "    (\"num\", numeric_transformer, numeric_features),\n",
    "    (\"cat\", categorical_transformer, categorical_features),\n",
    "])\n",
    "\n",
    "X_train_enc = preprocessor.fit_transform(X_train)\n",
    "X_val_enc = preprocessor.transform(X_val)\n",
    "X_test_enc = preprocessor.transform(X_test)\n",
    "X_trainval_enc = preprocessor.transform(X_trainval)\n",
    "\n",
    "feature_names = preprocessor.get_feature_names_out()\n",
    "print(\"Число признаков после кодирования:\", len(feature_names))\n",
    "\n",
    "# dense для пользовательской эволюционной модели\n",
    "X_train_dense = X_train_enc.toarray() if hasattr(X_train_enc, \"toarray\") else np.asarray(X_train_enc)\n",
    "X_val_dense = X_val_enc.toarray() if hasattr(X_val_enc, \"toarray\") else np.asarray(X_val_enc)\n",
    "X_test_dense = X_test_enc.toarray() if hasattr(X_test_enc, \"toarray\") else np.asarray(X_test_enc)\n",
    "X_trainval_dense = X_trainval_enc.toarray() if hasattr(X_trainval_enc, \"toarray\") else np.asarray(X_trainval_enc)\n",
    "\n",
    "display(pd.DataFrame(X_train_dense[:5], columns=feature_names).head())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29e7698a",
   "metadata": {},
   "source": [
    "## Вспомогательные функции оценки"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "34f96d60",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def get_metrics(y_true, y_pred):\n",
    "    return {\n",
    "        \"accuracy\": accuracy_score(y_true, y_pred),\n",
    "        \"balanced_accuracy\": balanced_accuracy_score(y_true, y_pred),\n",
    "        \"precision_macro\": precision_score(y_true, y_pred, average=\"macro\", zero_division=0),\n",
    "        \"recall_macro\": recall_score(y_true, y_pred, average=\"macro\", zero_division=0),\n",
    "        \"f1_macro\": f1_score(y_true, y_pred, average=\"macro\", zero_division=0),\n",
    "    }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cc0308c",
   "metadata": {},
   "source": [
    "## Классическая нейросеть"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "16417703",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Архитектура классической нейросети: (16,)\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>loss</th>\n",
       "      <th>train_accuracy</th>\n",
       "      <th>val_accuracy</th>\n",
       "      <th>val_f1_macro</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>36</td>\n",
       "      <td>1.249179</td>\n",
       "      <td>0.526380</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.255792</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>37</td>\n",
       "      <td>1.234877</td>\n",
       "      <td>0.530061</td>\n",
       "      <td>0.522059</td>\n",
       "      <td>0.254278</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>38</td>\n",
       "      <td>1.221207</td>\n",
       "      <td>0.534969</td>\n",
       "      <td>0.522059</td>\n",
       "      <td>0.245306</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>39</td>\n",
       "      <td>1.208166</td>\n",
       "      <td>0.537423</td>\n",
       "      <td>0.529412</td>\n",
       "      <td>0.248330</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>39</th>\n",
       "      <td>40</td>\n",
       "      <td>1.195767</td>\n",
       "      <td>0.539877</td>\n",
       "      <td>0.529412</td>\n",
       "      <td>0.247982</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    epoch      loss  train_accuracy  val_accuracy  val_f1_macro\n",
       "35     36  1.249179        0.526380      0.525735      0.255792\n",
       "36     37  1.234877        0.530061      0.522059      0.254278\n",
       "37     38  1.221207        0.534969      0.522059      0.245306\n",
       "38     39  1.208166        0.537423      0.529412      0.248330\n",
       "39     40  1.195767        0.539877      0.529412      0.247982"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Матрица ошибок на валидации:\n",
      "[[ 0  0  1  1  0  0]\n",
      " [ 0  0  6  5  0  0]\n",
      " [ 2  2 72 39  0  0]\n",
      " [ 0  0 42 59  6  0]\n",
      " [ 0  0  0 21 13  0]\n",
      " [ 0  0  0  2  1  0]]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "hidden_layers = (16,)\n",
    "baseline = MLPClassifier(\n",
    "    hidden_layer_sizes=hidden_layers,\n",
    "    activation=\"relu\",\n",
    "    solver=\"adam\",\n",
    "    alpha=1e-4,\n",
    "    learning_rate_init=1e-3,\n",
    "    max_iter=1,\n",
    "    warm_start=True,\n",
    "    random_state=SEED,\n",
    ")\n",
    "\n",
    "baseline_history = []\n",
    "best_baseline = None\n",
    "best_val_f1 = -np.inf\n",
    "\n",
    "classes_all = np.unique(y_train)\n",
    "\n",
    "for epoch in range(40):\n",
    "    baseline.fit(X_train_enc, y_train)\n",
    "    val_pred = baseline.predict(X_val_enc)\n",
    "    val_metrics = get_metrics(y_val, val_pred)\n",
    "    train_pred = baseline.predict(X_train_enc)\n",
    "    train_metrics = get_metrics(y_train, train_pred)\n",
    "\n",
    "    baseline_history.append({\n",
    "        \"epoch\": epoch + 1,\n",
    "        \"loss\": getattr(baseline, \"loss_\", np.nan),\n",
    "        \"train_accuracy\": train_metrics[\"accuracy\"],\n",
    "        \"val_accuracy\": val_metrics[\"accuracy\"],\n",
    "        \"val_f1_macro\": val_metrics[\"f1_macro\"],\n",
    "    })\n",
    "\n",
    "    if val_metrics[\"f1_macro\"] > best_val_f1:\n",
    "        best_val_f1 = val_metrics[\"f1_macro\"]\n",
    "        best_baseline = copy.deepcopy(baseline)\n",
    "\n",
    "baseline_history_df = pd.DataFrame(baseline_history)\n",
    "\n",
    "baseline_val_pred = best_baseline.predict(X_val_enc)\n",
    "baseline_test_pred = best_baseline.predict(X_test_enc)\n",
    "\n",
    "baseline_val_metrics = get_metrics(y_val, baseline_val_pred)\n",
    "baseline_test_metrics = get_metrics(y_test, baseline_test_pred)\n",
    "\n",
    "print(\"Архитектура классической нейросети:\", hidden_layers)\n",
    "display(baseline_history_df.tail())\n",
    "print(\"\\nМатрица ошибок на валидации:\")\n",
    "print(confusion_matrix(y_val, baseline_val_pred))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fbe12a2",
   "metadata": {},
   "source": [
    "## Нейросеть с эволюцией весов"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ed1f5f6a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Архитектура эволюционной нейросети: (16,)\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_loss</th>\n",
       "      <th>best_val_loss</th>\n",
       "      <th>mean_val_loss</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>31</td>\n",
       "      <td>1.162475</td>\n",
       "      <td>1.179946</td>\n",
       "      <td>1.203047</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>32</td>\n",
       "      <td>1.143788</td>\n",
       "      <td>1.178611</td>\n",
       "      <td>1.195997</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>33</td>\n",
       "      <td>1.143788</td>\n",
       "      <td>1.171975</td>\n",
       "      <td>1.189921</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>34</td>\n",
       "      <td>1.130534</td>\n",
       "      <td>1.160975</td>\n",
       "      <td>1.183672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>35</td>\n",
       "      <td>1.130534</td>\n",
       "      <td>1.156971</td>\n",
       "      <td>1.178750</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    generation  best_train_loss  best_val_loss  mean_val_loss\n",
       "30          31         1.162475       1.179946       1.203047\n",
       "31          32         1.143788       1.178611       1.195997\n",
       "32          33         1.143788       1.171975       1.189921\n",
       "33          34         1.130534       1.160975       1.183672\n",
       "34          35         1.130534       1.156971       1.178750"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Матрица ошибок на валидации:\n",
      "[[ 0  0  0  2  0  0]\n",
      " [ 0  0  7  4  0  0]\n",
      " [ 0  0 88 27  0  0]\n",
      " [ 0  0 48 59  0  0]\n",
      " [ 0  0 13 17  4  0]\n",
      " [ 0  0  1  2  0  0]]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Одинаковая архитектура для корректного сравнения методов обучения\n",
    "evo_hidden_dim = 16\n",
    "n_inputs = X_train_dense.shape[1]\n",
    "n_outputs = len(np.unique(y_train))\n",
    "\n",
    "def one_hot(y, n_classes):\n",
    "    m = np.zeros((len(y), n_classes), dtype=np.float64)\n",
    "    m[np.arange(len(y)), y] = 1.0\n",
    "    return m\n",
    "\n",
    "Y_train_oh = one_hot(y_train, n_outputs)\n",
    "Y_val_oh = one_hot(y_val, n_outputs)\n",
    "\n",
    "def relu(x):\n",
    "    return np.maximum(x, 0.0)\n",
    "\n",
    "def softmax(z):\n",
    "    z = z - np.max(z, axis=1, keepdims=True)\n",
    "    ez = np.exp(z)\n",
    "    return ez / np.clip(ez.sum(axis=1, keepdims=True), 1e-12, None)\n",
    "\n",
    "def chromosome_dim(input_dim, hidden_dim, output_dim):\n",
    "    return input_dim * hidden_dim + hidden_dim + hidden_dim * output_dim + output_dim\n",
    "\n",
    "n_params = chromosome_dim(n_inputs, evo_hidden_dim, n_outputs)\n",
    "\n",
    "def unpack_weights(chrom):\n",
    "    idx = 0\n",
    "    w1 = chrom[idx: idx + n_inputs * evo_hidden_dim].reshape(n_inputs, evo_hidden_dim)\n",
    "    idx += n_inputs * evo_hidden_dim\n",
    "    b1 = chrom[idx: idx + evo_hidden_dim]\n",
    "    idx += evo_hidden_dim\n",
    "    w2 = chrom[idx: idx + evo_hidden_dim * n_outputs].reshape(evo_hidden_dim, n_outputs)\n",
    "    idx += evo_hidden_dim * n_outputs\n",
    "    b2 = chrom[idx: idx + n_outputs]\n",
    "    return w1, b1, w2, b2\n",
    "\n",
    "def forward_probs(X_dense, chrom):\n",
    "    w1, b1, w2, b2 = unpack_weights(chrom)\n",
    "    h = relu(X_dense @ w1 + b1)\n",
    "    logits = h @ w2 + b2\n",
    "    return softmax(logits)\n",
    "\n",
    "def cross_entropy(y_onehot, probs):\n",
    "    probs = np.clip(probs, 1e-9, 1.0)\n",
    "    return -np.mean(np.sum(y_onehot * np.log(probs), axis=1))\n",
    "\n",
    "def predict_from_chromosome(X_dense, chrom):\n",
    "    probs = forward_probs(X_dense, chrom)\n",
    "    return probs.argmax(axis=1)\n",
    "\n",
    "rng = np.random.default_rng(SEED)\n",
    "population_size = 24\n",
    "generations = 35\n",
    "mutation_rate = 0.08\n",
    "mutation_scale = 0.12\n",
    "tournament_size = 3\n",
    "elite_size = 2\n",
    "\n",
    "population = rng.normal(0.0, 0.35, size=(population_size, n_params))\n",
    "best_chromosome = None\n",
    "best_val_loss = np.inf\n",
    "evo_history = []\n",
    "\n",
    "def tournament_select(pop, fitness):\n",
    "    idx = rng.choice(len(pop), size=tournament_size, replace=False)\n",
    "    best_idx = idx[np.argmax(fitness[idx])]\n",
    "    return pop[best_idx].copy()\n",
    "\n",
    "for gen in range(generations):\n",
    "    train_losses = np.array([cross_entropy(Y_train_oh, forward_probs(X_train_dense, chrom)) for chrom in population])\n",
    "    val_losses = np.array([cross_entropy(Y_val_oh, forward_probs(X_val_dense, chrom)) for chrom in population])\n",
    "    fitness = -train_losses\n",
    "\n",
    "    best_idx = np.argmin(val_losses)\n",
    "    if val_losses[best_idx] < best_val_loss:\n",
    "        best_val_loss = val_losses[best_idx]\n",
    "        best_chromosome = population[best_idx].copy()\n",
    "\n",
    "    evo_history.append({\n",
    "        \"generation\": gen + 1,\n",
    "        \"best_train_loss\": float(train_losses[np.argmin(train_losses)]),\n",
    "        \"best_val_loss\": float(val_losses[best_idx]),\n",
    "        \"mean_val_loss\": float(val_losses.mean()),\n",
    "    })\n",
    "\n",
    "    elite_indices = np.argsort(val_losses)[:elite_size]\n",
    "    new_population = [population[i].copy() for i in elite_indices]\n",
    "\n",
    "    while len(new_population) < population_size:\n",
    "        parent1 = tournament_select(population, fitness)\n",
    "        parent2 = tournament_select(population, fitness)\n",
    "\n",
    "        if rng.random() < 0.9:\n",
    "            alpha = rng.random(n_params)\n",
    "            child1 = alpha * parent1 + (1 - alpha) * parent2\n",
    "            child2 = alpha * parent2 + (1 - alpha) * parent1\n",
    "        else:\n",
    "            child1 = parent1.copy()\n",
    "            child2 = parent2.copy()\n",
    "\n",
    "        for child in (child1, child2):\n",
    "            mask = rng.random(n_params) < mutation_rate\n",
    "            if mask.any():\n",
    "                child[mask] += rng.normal(0.0, mutation_scale, size=mask.sum())\n",
    "            new_population.append(child)\n",
    "            if len(new_population) >= population_size:\n",
    "                break\n",
    "\n",
    "    population = np.array(new_population[:population_size])\n",
    "\n",
    "evo_history_df = pd.DataFrame(evo_history)\n",
    "\n",
    "evo_val_pred = predict_from_chromosome(X_val_dense, best_chromosome)\n",
    "evo_test_pred = predict_from_chromosome(X_test_dense, best_chromosome)\n",
    "\n",
    "evo_val_metrics = get_metrics(y_val, evo_val_pred)\n",
    "evo_test_metrics = get_metrics(y_test, evo_test_pred)\n",
    "\n",
    "print(\"Архитектура эволюционной нейросети:\", (evo_hidden_dim,))\n",
    "display(evo_history_df.tail())\n",
    "print(\"\\nМатрица ошибок на валидации:\")\n",
    "print(confusion_matrix(y_val, evo_val_pred))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40c88dba",
   "metadata": {},
   "source": [
    "## Сравнение моделей"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "826e5805",
   "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>accuracy</th>\n",
       "      <th>balanced_accuracy</th>\n",
       "      <th>precision_macro</th>\n",
       "      <th>recall_macro</th>\n",
       "      <th>f1_macro</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>Классическая нейросеть</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.240312</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.238758</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Нейросеть с эволюцией весов</td>\n",
       "      <td>0.533088</td>\n",
       "      <td>0.222087</td>\n",
       "      <td>0.258894</td>\n",
       "      <td>0.222087</td>\n",
       "      <td>0.209256</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                         model  accuracy  balanced_accuracy  precision_macro  \\\n",
       "0       Классическая нейросеть  0.525735           0.241258         0.240312   \n",
       "1  Нейросеть с эволюцией весов  0.533088           0.222087         0.258894   \n",
       "\n",
       "   recall_macro  f1_macro  n_original_features  n_processed_features  \\\n",
       "0      0.241258  0.238758                   10                    10   \n",
       "1      0.222087  0.209256                   10                    10   \n",
       "\n",
       "  hidden_layers  \n",
       "0         (16,)  \n",
       "1         (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>accuracy</th>\n",
       "      <th>balanced_accuracy</th>\n",
       "      <th>precision_macro</th>\n",
       "      <th>recall_macro</th>\n",
       "      <th>f1_macro</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>Классическая нейросеть</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.240312</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.238758</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    model  accuracy  balanced_accuracy  precision_macro  \\\n",
       "0  Классическая нейросеть  0.525735           0.241258         0.240312   \n",
       "\n",
       "   recall_macro  f1_macro  n_original_features  n_processed_features  \\\n",
       "0      0.241258  0.238758                   10                    10   \n",
       "\n",
       "  hidden_layers  \n",
       "0         (16,)  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "results = pd.DataFrame([\n",
    "    {\n",
    "        \"model\": \"Классическая нейросеть\",\n",
    "        **baseline_test_metrics,\n",
    "        \"n_original_features\": X.shape[1],\n",
    "        \"n_processed_features\": len(feature_names),\n",
    "        \"hidden_layers\": str(hidden_layers),\n",
    "    },\n",
    "    {\n",
    "        \"model\": \"Нейросеть с эволюцией весов\",\n",
    "        **evo_test_metrics,\n",
    "        \"n_original_features\": X.shape[1],\n",
    "        \"n_processed_features\": len(feature_names),\n",
    "        \"hidden_layers\": str((evo_hidden_dim,)),\n",
    "    },\n",
    "]).sort_values([\"f1_macro\", \"accuracy\"], ascending=False).reset_index(drop=True)\n",
    "\n",
    "display(results)\n",
    "\n",
    "best_model_row = results.iloc[[0]]\n",
    "print(\"Лучшая модель:\")\n",
    "display(best_model_row)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed0b0c9f",
   "metadata": {},
   "source": [
    "## Финальная ячейка для вывода"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d13f5429",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\n",
      "Зависимая переменная: quality\n",
      "\n",
      "Число исходных признаков: 10\n",
      "Число признаков после кодирования: 10\n",
      "Архитектура обеих моделей: (16,)\n",
      "\n",
      "Распределение классов:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "quality\n",
       "3    0.007358\n",
       "4    0.038999\n",
       "5    0.424577\n",
       "6    0.393672\n",
       "7    0.122884\n",
       "8    0.012509\n",
       "Name: share, dtype: float64"
      ]
     },
     "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>accuracy</th>\n",
       "      <th>balanced_accuracy</th>\n",
       "      <th>precision_macro</th>\n",
       "      <th>recall_macro</th>\n",
       "      <th>f1_macro</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>Классическая нейросеть</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.240312</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.238758</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Нейросеть с эволюцией весов</td>\n",
       "      <td>0.533088</td>\n",
       "      <td>0.222087</td>\n",
       "      <td>0.258894</td>\n",
       "      <td>0.222087</td>\n",
       "      <td>0.209256</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                         model  accuracy  balanced_accuracy  precision_macro  \\\n",
       "0       Классическая нейросеть  0.525735           0.241258         0.240312   \n",
       "1  Нейросеть с эволюцией весов  0.533088           0.222087         0.258894   \n",
       "\n",
       "   recall_macro  f1_macro  n_original_features  n_processed_features  \\\n",
       "0      0.241258  0.238758                   10                    10   \n",
       "1      0.222087  0.209256                   10                    10   \n",
       "\n",
       "  hidden_layers  \n",
       "0         (16,)  \n",
       "1         (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>accuracy</th>\n",
       "      <th>balanced_accuracy</th>\n",
       "      <th>precision_macro</th>\n",
       "      <th>recall_macro</th>\n",
       "      <th>f1_macro</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>Классическая нейросеть</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.240312</td>\n",
       "      <td>0.241258</td>\n",
       "      <td>0.238758</td>\n",
       "      <td>10</td>\n",
       "      <td>10</td>\n",
       "      <td>(16,)</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    model  accuracy  balanced_accuracy  precision_macro  \\\n",
       "0  Классическая нейросеть  0.525735           0.241258         0.240312   \n",
       "\n",
       "   recall_macro  f1_macro  n_original_features  n_processed_features  \\\n",
       "0      0.241258  0.238758                   10                    10   \n",
       "\n",
       "  hidden_layers  \n",
       "0         (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>epoch</th>\n",
       "      <th>loss</th>\n",
       "      <th>train_accuracy</th>\n",
       "      <th>val_accuracy</th>\n",
       "      <th>val_f1_macro</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>36</td>\n",
       "      <td>1.249179</td>\n",
       "      <td>0.526380</td>\n",
       "      <td>0.525735</td>\n",
       "      <td>0.255792</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>37</td>\n",
       "      <td>1.234877</td>\n",
       "      <td>0.530061</td>\n",
       "      <td>0.522059</td>\n",
       "      <td>0.254278</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>38</td>\n",
       "      <td>1.221207</td>\n",
       "      <td>0.534969</td>\n",
       "      <td>0.522059</td>\n",
       "      <td>0.245306</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>39</td>\n",
       "      <td>1.208166</td>\n",
       "      <td>0.537423</td>\n",
       "      <td>0.529412</td>\n",
       "      <td>0.248330</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>39</th>\n",
       "      <td>40</td>\n",
       "      <td>1.195767</td>\n",
       "      <td>0.539877</td>\n",
       "      <td>0.529412</td>\n",
       "      <td>0.247982</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    epoch      loss  train_accuracy  val_accuracy  val_f1_macro\n",
       "35     36  1.249179        0.526380      0.525735      0.255792\n",
       "36     37  1.234877        0.530061      0.522059      0.254278\n",
       "37     38  1.221207        0.534969      0.522059      0.245306\n",
       "38     39  1.208166        0.537423      0.529412      0.248330\n",
       "39     40  1.195767        0.539877      0.529412      0.247982"
      ]
     },
     "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>generation</th>\n",
       "      <th>best_train_loss</th>\n",
       "      <th>best_val_loss</th>\n",
       "      <th>mean_val_loss</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>31</td>\n",
       "      <td>1.162475</td>\n",
       "      <td>1.179946</td>\n",
       "      <td>1.203047</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>32</td>\n",
       "      <td>1.143788</td>\n",
       "      <td>1.178611</td>\n",
       "      <td>1.195997</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>33</td>\n",
       "      <td>1.143788</td>\n",
       "      <td>1.171975</td>\n",
       "      <td>1.189921</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>34</td>\n",
       "      <td>1.130534</td>\n",
       "      <td>1.160975</td>\n",
       "      <td>1.183672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>35</td>\n",
       "      <td>1.130534</td>\n",
       "      <td>1.156971</td>\n",
       "      <td>1.178750</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    generation  best_train_loss  best_val_loss  mean_val_loss\n",
       "30          31         1.162475       1.179946       1.203047\n",
       "31          32         1.143788       1.178611       1.195997\n",
       "32          33         1.143788       1.171975       1.189921\n",
       "33          34         1.130534       1.160975       1.183672\n",
       "34          35         1.130534       1.156971       1.178750"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Первые 10 фактических и предсказанных значений на тесте для классической нейросети:\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_baseline</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>5</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>5</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>4</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  y_true y_pred_baseline\n",
       "0      5               6\n",
       "1      6               6\n",
       "2      5               7\n",
       "3      8               6\n",
       "4      6               5\n",
       "5      5               5\n",
       "6      7               6\n",
       "7      4               5\n",
       "8      7               6\n",
       "9      6               6"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Первые 10 фактических и предсказанных значений на тесте для эволюционной нейросети:\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_evolution</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>4</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>7</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>6</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  y_true y_pred_evolution\n",
       "0      5                5\n",
       "1      6                6\n",
       "2      5                5\n",
       "3      8                6\n",
       "4      6                5\n",
       "5      5                5\n",
       "6      7                6\n",
       "7      4                6\n",
       "8      7                6\n",
       "9      6                6"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Матрица ошибок для классической нейросети:\n",
      "[[ 0  0  1  1  0  0]\n",
      " [ 0  0  7  4  0  0]\n",
      " [ 1  1 78 34  2  0]\n",
      " [ 1  0 36 57 13  0]\n",
      " [ 0  0  4 21  8  0]\n",
      " [ 0  0  0  3  0  0]]\n",
      "Матрица ошибок для эволюционной нейросети:\n",
      "[[ 0  0  1  1  0  0]\n",
      " [ 0  0  7  4  0  0]\n",
      " [ 0  0 89 27  0  0]\n",
      " [ 0  0 52 54  1  0]\n",
      " [ 0  0  7 24  2  0]\n",
      " [ 0  0  1  1  1  0]]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "print(\"=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\")\n",
    "print(\"Зависимая переменная:\", target_col)\n",
    "print()\n",
    "print(\"Число исходных признаков:\", X.shape[1])\n",
    "print(\"Число признаков после кодирования:\", len(feature_names))\n",
    "print(\"Архитектура обеих моделей:\", (16,))\n",
    "print()\n",
    "\n",
    "print(\"Распределение классов:\")\n",
    "display(pd.Series(y_raw, name=target_col).value_counts(normalize=True).rename(\"share\").sort_index())\n",
    "\n",
    "print(\"Метрики моделей на тестовой выборке:\")\n",
    "display(results)\n",
    "\n",
    "print(\"Лучшая модель:\")\n",
    "display(best_model_row)\n",
    "\n",
    "print(\"Последние эпохи обучения классической нейросети:\")\n",
    "display(baseline_history_df.tail())\n",
    "\n",
    "print(\"Последние поколения эволюционной нейросети:\")\n",
    "display(evo_history_df.tail())\n",
    "\n",
    "print(\"Первые 10 фактических и предсказанных значений на тесте для классической нейросети:\")\n",
    "baseline_preds_preview = pd.DataFrame({\n",
    "    \"y_true\": label_encoder.inverse_transform(y_test[:10]),\n",
    "    \"y_pred_baseline\": label_encoder.inverse_transform(baseline_test_pred[:10]),\n",
    "})\n",
    "display(baseline_preds_preview)\n",
    "\n",
    "print(\"Первые 10 фактических и предсказанных значений на тесте для эволюционной нейросети:\")\n",
    "evo_preds_preview = pd.DataFrame({\n",
    "    \"y_true\": label_encoder.inverse_transform(y_test[:10]),\n",
    "    \"y_pred_evolution\": label_encoder.inverse_transform(evo_test_pred[:10]),\n",
    "})\n",
    "display(evo_preds_preview)\n",
    "\n",
    "print(\"Матрица ошибок для классической нейросети:\")\n",
    "print(confusion_matrix(y_test, baseline_test_pred))\n",
    "\n",
    "print(\"Матрица ошибок для эволюционной нейросети:\")\n",
    "print(confusion_matrix(y_test, evo_test_pred))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8195e5e8",
   "metadata": {},
   "source": [
    "Итог\n",
    "\n",
    "Зависимой переменной выбрана quality. Сравнивались две нейросети одинаковой архитектуры (16,): классическая и модель с эволюцией весов.\n",
    "\n",
    "На тестовой выборке лучшая модель — классическая нейросеть: accuracy = 0.526, balanced accuracy = 0.241, F1-macro = 0.239. Эволюционная модель показала немного более высокий accuracy = 0.533, но уступила по balanced accuracy = 0.222 и F1-macro = 0.209.\n",
    "\n",
    "Следовательно, лучшей следует считать классическую нейросеть, так как при дисбалансе классов её качество по усреднённым метрикам выше."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
