{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6d28f4ac",
   "metadata": {},
   "source": [
    "# Прототипная нейросеть для задачи регрессии\n",
    "\n",
    "В работе автоматически определяется зависимая переменная, выполняется предобработка данных, обучается прототипная нейросеть для регрессии и анализируются основные прототипы.\n",
    "\n",
    "Под **прототипной нейросетью** далее понимается RBF-сеть:\n",
    "- сначала выделяются прототипы объектов методом `KMeans`,\n",
    "- затем по расстояниям до прототипов строятся радиально-базисные активации,\n",
    "- по этим активациям обучается линейный регрессионный выходной слой.\n",
    "\n",
    "В конце ноутбука есть отдельная ячейка, которая печатает все ключевые результаты для итогового вывода."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c927c6f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import re\n",
    "import glob\n",
    "import math\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.base import BaseEstimator, RegressorMixin\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.impute import SimpleImputer\n",
    "from sklearn.cluster import KMeans\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.linear_model import Ridge\n",
    "from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import OneHotEncoder, StandardScaler\n",
    "from sklearn.metrics import pairwise_distances\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "SEED = 42\n",
    "random.seed(SEED)\n",
    "np.random.seed(SEED)\n",
    "\n",
    "pd.set_option(\"display.max_columns\", 200)\n",
    "pd.set_option(\"display.width\", 200)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ebaa2660",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Используемый файл: ./housing_price_dataset.csv\n",
      "Форма датасета: (50000, 6)\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>SquareFeet</th>\n",
       "      <th>Bedrooms</th>\n",
       "      <th>Bathrooms</th>\n",
       "      <th>Neighborhood</th>\n",
       "      <th>YearBuilt</th>\n",
       "      <th>Price</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2126</td>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>Rural</td>\n",
       "      <td>1969</td>\n",
       "      <td>215355.283618</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2459</td>\n",
       "      <td>3</td>\n",
       "      <td>2</td>\n",
       "      <td>Rural</td>\n",
       "      <td>1980</td>\n",
       "      <td>195014.221626</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1860</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>Suburb</td>\n",
       "      <td>1970</td>\n",
       "      <td>306891.012076</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2294</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>Urban</td>\n",
       "      <td>1996</td>\n",
       "      <td>206786.787153</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2130</td>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>Suburb</td>\n",
       "      <td>2001</td>\n",
       "      <td>272436.239065</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   SquareFeet  Bedrooms  Bathrooms Neighborhood  YearBuilt          Price\n",
       "0        2126         4          1        Rural       1969  215355.283618\n",
       "1        2459         3          2        Rural       1980  195014.221626\n",
       "2        1860         2          1       Suburb       1970  306891.012076\n",
       "3        2294         2          1        Urban       1996  206786.787153\n",
       "4        2130         5          2       Suburb       2001  272436.239065"
      ]
     },
     "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>SquareFeet</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Bedrooms</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Bathrooms</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Neighborhood</th>\n",
       "      <td>object</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>YearBuilt</th>\n",
       "      <td>int64</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Price</th>\n",
       "      <td>float64</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                dtype\n",
       "SquareFeet      int64\n",
       "Bedrooms        int64\n",
       "Bathrooms       int64\n",
       "Neighborhood   object\n",
       "YearBuilt       int64\n",
       "Price         float64"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def find_csv_file():\n",
    "    candidates = [\n",
    "        \"housing_price_dataset.csv\",\n",
    "        \"Housing price dataset.csv\",\n",
    "        \"Housing Price Dataset.csv\",\n",
    "        \"Housing Price dataset.csv\",\n",
    "        \"housing.csv\",\n",
    "        \"data.csv\",\n",
    "    ]\n",
    "    search_dirs = [\".\", \"/mnt/data\", os.getcwd()]\n",
    "\n",
    "    for d in search_dirs:\n",
    "        for name in candidates:\n",
    "            path = os.path.join(d, name)\n",
    "            if os.path.exists(path):\n",
    "                return path\n",
    "\n",
    "    patterns = [\n",
    "        \"*.csv\",\n",
    "        \"/mnt/data/*.csv\",\n",
    "    ]\n",
    "    files = []\n",
    "    for p in patterns:\n",
    "        files.extend(glob.glob(p))\n",
    "\n",
    "    # Ищем наиболее подходящий файл по имени\n",
    "    priority_tokens = [\"housing\", \"price\", \"dataset\"]\n",
    "    scored = []\n",
    "    for f in files:\n",
    "        base = os.path.basename(f).lower()\n",
    "        score = sum(tok in base for tok in priority_tokens)\n",
    "        scored.append((score, f))\n",
    "    scored.sort(reverse=True)\n",
    "    if scored and scored[0][0] > 0:\n",
    "        return scored[0][1]\n",
    "    if files:\n",
    "        return files[0]\n",
    "    raise FileNotFoundError(\"CSV-файл не найден. Поместите housing_price_dataset.csv рядом с ноутбуком.\")\n",
    "\n",
    "csv_path = find_csv_file()\n",
    "print(\"Используемый файл:\", csv_path)\n",
    "\n",
    "df_raw = pd.read_csv(csv_path)\n",
    "print(\"Форма датасета:\", df_raw.shape)\n",
    "display(df_raw.head())\n",
    "print(\"\\nТипы данных:\")\n",
    "display(df_raw.dtypes.rename(\"dtype\").to_frame())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2ef5eeb1",
   "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>SquareFeet</td>\n",
       "      <td>squarefeet</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Bedrooms</td>\n",
       "      <td>bedrooms</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Bathrooms</td>\n",
       "      <td>bathrooms</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Neighborhood</td>\n",
       "      <td>neighborhood</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>YearBuilt</td>\n",
       "      <td>yearbuilt</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Price</td>\n",
       "      <td>price</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  original_name normalized_name\n",
       "0    SquareFeet      squarefeet\n",
       "1      Bedrooms        bedrooms\n",
       "2     Bathrooms       bathrooms\n",
       "3  Neighborhood    neighborhood\n",
       "4     YearBuilt       yearbuilt\n",
       "5         Price           price"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Выбранная зависимая переменная: price\n",
      "Найденные идентификаторы / служебные поля: []\n",
      "Размер после удаления пропусков по целевой переменной: (50000, 5)\n",
      "\n",
      "Числовые признаки: ['squarefeet', 'bedrooms', 'bathrooms', 'yearbuilt']\n",
      "Категориальные признаки: ['neighborhood']\n"
     ]
    }
   ],
   "source": [
    "def normalize_col_name(col):\n",
    "    col = str(col).strip().lower()\n",
    "    col = col.replace(\"/\", \"_\").replace(\"-\", \"_\")\n",
    "    col = re.sub(r\"[^a-z0-9_]+\", \"_\", col)\n",
    "    col = re.sub(r\"_+\", \"_\", col).strip(\"_\")\n",
    "    return col\n",
    "\n",
    "original_columns = list(df_raw.columns)\n",
    "normalized_columns = [normalize_col_name(c) for c in original_columns]\n",
    "\n",
    "column_map_df = pd.DataFrame({\n",
    "    \"original_name\": original_columns,\n",
    "    \"normalized_name\": normalized_columns\n",
    "})\n",
    "display(column_map_df)\n",
    "\n",
    "df = df_raw.copy()\n",
    "df.columns = normalized_columns\n",
    "\n",
    "possible_targets = [\n",
    "    \"price\", \"target\", \"y\", \"saleprice\", \"amount\", \"cost\"\n",
    "]\n",
    "\n",
    "target_col = None\n",
    "for c in possible_targets:\n",
    "    if c in df.columns:\n",
    "        target_col = c\n",
    "        break\n",
    "\n",
    "if target_col is None:\n",
    "    numeric_candidates = df.select_dtypes(include=[np.number]).columns.tolist()\n",
    "    if not numeric_candidates:\n",
    "        raise ValueError(\"Не удалось автоматически определить числовую зависимую переменную.\")\n",
    "    target_col = numeric_candidates[-1]\n",
    "\n",
    "print(\"Выбранная зависимая переменная:\", target_col)\n",
    "\n",
    "# Удаляем явные идентификаторы\n",
    "id_like = [c for c in df.columns if c != target_col and (\"id\" in c or c in {\"name\"})]\n",
    "print(\"Найденные идентификаторы / служебные поля:\", id_like)\n",
    "\n",
    "X = df.drop(columns=[target_col] + id_like, errors=\"ignore\").copy()\n",
    "y = pd.to_numeric(df[target_col], errors=\"coerce\").copy()\n",
    "\n",
    "valid_mask = y.notna()\n",
    "X = X.loc[valid_mask].reset_index(drop=True)\n",
    "y = y.loc[valid_mask].reset_index(drop=True)\n",
    "\n",
    "print(\"Размер после удаления пропусков по целевой переменной:\", X.shape)\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(\"\\nЧисловые признаки:\", numeric_features)\n",
    "print(\"Категориальные признаки:\", categorical_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "158aea3b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Размеры выборок:\n",
      "train: (30000, 5) (30000,)\n",
      "validation: (10000, 5) (10000,)\n",
      "test: (10000, 5) (10000,)\n",
      "Число исходных признаков: 5\n",
      "Число признаков после кодирования: 7\n",
      "Первые обработанные признаки: ['num__squarefeet', 'num__bedrooms', 'num__bathrooms', 'num__yearbuilt', 'cat__neighborhood_Rural', 'cat__neighborhood_Suburb', 'cat__neighborhood_Urban']\n"
     ]
    }
   ],
   "source": [
    "X_train_full, X_test, y_train_full, y_test = train_test_split(\n",
    "    X, y, test_size=0.20, 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.25, random_state=SEED\n",
    ")\n",
    "\n",
    "print(\"Размеры выборок:\")\n",
    "print(\"train:\", X_train.shape, y_train.shape)\n",
    "print(\"validation:\", X_val.shape, y_val.shape)\n",
    "print(\"test:\", X_test.shape, y_test.shape)\n",
    "\n",
    "num_pipe = Pipeline([\n",
    "    (\"imputer\", SimpleImputer(strategy=\"median\")),\n",
    "    (\"scaler\", StandardScaler()),\n",
    "])\n",
    "\n",
    "try:\n",
    "    ohe = OneHotEncoder(handle_unknown=\"ignore\", sparse_output=False)\n",
    "except TypeError:\n",
    "    ohe = OneHotEncoder(handle_unknown=\"ignore\", sparse=False)\n",
    "\n",
    "cat_pipe = Pipeline([\n",
    "    (\"imputer\", SimpleImputer(strategy=\"most_frequent\")),\n",
    "    (\"onehot\", ohe),\n",
    "])\n",
    "\n",
    "preprocessor = ColumnTransformer([\n",
    "    (\"num\", num_pipe, numeric_features),\n",
    "    (\"cat\", cat_pipe, categorical_features),\n",
    "], remainder=\"drop\")\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_processed = preprocessor.get_feature_names_out()\n",
    "\n",
    "print(\"Число исходных признаков:\", X.shape[1])\n",
    "print(\"Число признаков после кодирования:\", X_train_proc.shape[1])\n",
    "print(\"Первые обработанные признаки:\", list(feature_names_processed[:20]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a4f4c3c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "class PrototypeRBFRegressor(BaseEstimator, RegressorMixin):\n",
    "    def __init__(self, n_prototypes=8, alpha=1.0, random_state=42):\n",
    "        self.n_prototypes = n_prototypes\n",
    "        self.alpha = alpha\n",
    "        self.random_state = random_state\n",
    "\n",
    "    def _rbf_features(self, X):\n",
    "        d2 = pairwise_distances(X, self.prototypes_, metric=\"euclidean\") ** 2\n",
    "        gamma = 1.0 / max(2.0 * (self.sigma_ ** 2), 1e-12)\n",
    "        return np.exp(-gamma * d2)\n",
    "\n",
    "    def fit(self, X, y):\n",
    "        X = np.asarray(X, dtype=float)\n",
    "        y = np.asarray(y, dtype=float)\n",
    "\n",
    "        n_clusters = int(min(max(2, self.n_prototypes), len(X)))\n",
    "        self.kmeans_ = KMeans(n_clusters=n_clusters, random_state=self.random_state, n_init=10)\n",
    "        self.kmeans_.fit(X)\n",
    "        self.prototypes_ = self.kmeans_.cluster_centers_\n",
    "\n",
    "        assigned = self.kmeans_.predict(X)\n",
    "        dist_to_center = np.linalg.norm(X - self.prototypes_[assigned], axis=1)\n",
    "        self.sigma_ = float(np.median(dist_to_center))\n",
    "        if not np.isfinite(self.sigma_) or self.sigma_ <= 1e-8:\n",
    "            all_d = pairwise_distances(self.prototypes_)\n",
    "            self.sigma_ = float(np.median(all_d[all_d > 0])) if np.any(all_d > 0) else 1.0\n",
    "\n",
    "        Phi = self._rbf_features(X)\n",
    "        self.ridge_ = Ridge(alpha=self.alpha, random_state=self.random_state)\n",
    "        self.ridge_.fit(Phi, y)\n",
    "        return self\n",
    "\n",
    "    def predict(self, X):\n",
    "        X = np.asarray(X, dtype=float)\n",
    "        Phi = self._rbf_features(X)\n",
    "        return self.ridge_.predict(Phi)\n",
    "\n",
    "    @property\n",
    "    def prototype_weights_(self):\n",
    "        return np.asarray(self.ridge_.coef_, dtype=float).ravel()\n",
    "\n",
    "def regression_metrics(y_true, y_pred):\n",
    "    return {\n",
    "        \"r2\": r2_score(y_true, y_pred),\n",
    "        \"rmse\": float(np.sqrt(mean_squared_error(y_true, y_pred))),\n",
    "        \"mae\": mean_absolute_error(y_true, y_pred),\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d0be083a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Лучшие конфигурации по validation RMSE:\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>n_prototypes</th>\n",
       "      <th>alpha</th>\n",
       "      <th>train_r2</th>\n",
       "      <th>train_rmse</th>\n",
       "      <th>train_mae</th>\n",
       "      <th>val_r2</th>\n",
       "      <th>val_rmse</th>\n",
       "      <th>val_mae</th>\n",
       "      <th>sigma</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>1.0000</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.396943</td>\n",
       "      <td>42622.246003</td>\n",
       "      <td>0.512792</td>\n",
       "      <td>53050.567712</td>\n",
       "      <td>42496.273011</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>8</td>\n",
       "      <td>0.1000</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382961</td>\n",
       "      <td>42622.409768</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.785337</td>\n",
       "      <td>42496.636716</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0100</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382822</td>\n",
       "      <td>42622.426438</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.808397</td>\n",
       "      <td>42496.674121</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0010</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382820</td>\n",
       "      <td>42622.428105</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.810716</td>\n",
       "      <td>42496.677861</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0001</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382820</td>\n",
       "      <td>42622.428272</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.810948</td>\n",
       "      <td>42496.678236</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>10</td>\n",
       "      <td>1.0000</td>\n",
       "      <td>0.508774</td>\n",
       "      <td>53485.439965</td>\n",
       "      <td>42675.452322</td>\n",
       "      <td>0.511822</td>\n",
       "      <td>53103.355012</td>\n",
       "      <td>42523.583938</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>10</td>\n",
       "      <td>0.1000</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424887</td>\n",
       "      <td>42675.636545</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.553508</td>\n",
       "      <td>42523.824404</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0100</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424736</td>\n",
       "      <td>42675.655797</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.574743</td>\n",
       "      <td>42523.848507</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0010</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424734</td>\n",
       "      <td>42675.657723</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.576880</td>\n",
       "      <td>42523.850918</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0001</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424734</td>\n",
       "      <td>42675.657915</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.577094</td>\n",
       "      <td>42523.851159</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   n_prototypes   alpha  train_r2    train_rmse     train_mae    val_r2      val_rmse       val_mae     sigma\n",
       "0             8  1.0000  0.510170  53409.396943  42622.246003  0.512792  53050.567712  42496.273011  1.410672\n",
       "1             8  0.1000  0.510170  53409.382961  42622.409768  0.512788  53050.785337  42496.636716  1.410672\n",
       "2             8  0.0100  0.510170  53409.382822  42622.426438  0.512788  53050.808397  42496.674121  1.410672\n",
       "3             8  0.0010  0.510170  53409.382820  42622.428105  0.512788  53050.810716  42496.677861  1.410672\n",
       "4             8  0.0001  0.510170  53409.382820  42622.428272  0.512788  53050.810948  42496.678236  1.410672\n",
       "5            10  1.0000  0.508774  53485.439965  42675.452322  0.511822  53103.355012  42523.583938  1.364013\n",
       "6            10  0.1000  0.508775  53485.424887  42675.636545  0.511818  53103.553508  42523.824404  1.364013\n",
       "7            10  0.0100  0.508775  53485.424736  42675.655797  0.511818  53103.574743  42523.848507  1.364013\n",
       "8            10  0.0010  0.508775  53485.424734  42675.657723  0.511818  53103.576880  42523.850918  1.364013\n",
       "9            10  0.0001  0.508775  53485.424734  42675.657915  0.511818  53103.577094  42523.851159  1.364013"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Лучшая конфигурация:\n",
      "n_prototypes = 8\n",
      "alpha = 1.0\n",
      "sigma = 1.410672\n"
     ]
    }
   ],
   "source": [
    "prototype_grid = [4, 6, 8, 10, 12]\n",
    "alpha_grid = [1e-4, 1e-3, 1e-2, 1e-1, 1.0]\n",
    "\n",
    "search_rows = []\n",
    "best_model = None\n",
    "best_key = None\n",
    "best_val_rmse = np.inf\n",
    "\n",
    "for n_prototypes in prototype_grid:\n",
    "    for alpha in alpha_grid:\n",
    "        model = PrototypeRBFRegressor(\n",
    "            n_prototypes=n_prototypes,\n",
    "            alpha=alpha,\n",
    "            random_state=SEED\n",
    "        )\n",
    "        model.fit(X_train_proc, y_train)\n",
    "\n",
    "        pred_train = model.predict(X_train_proc)\n",
    "        pred_val = model.predict(X_val_proc)\n",
    "\n",
    "        train_m = regression_metrics(y_train, pred_train)\n",
    "        val_m = regression_metrics(y_val, pred_val)\n",
    "\n",
    "        row = {\n",
    "            \"n_prototypes\": n_prototypes,\n",
    "            \"alpha\": alpha,\n",
    "            \"train_r2\": train_m[\"r2\"],\n",
    "            \"train_rmse\": train_m[\"rmse\"],\n",
    "            \"train_mae\": train_m[\"mae\"],\n",
    "            \"val_r2\": val_m[\"r2\"],\n",
    "            \"val_rmse\": val_m[\"rmse\"],\n",
    "            \"val_mae\": val_m[\"mae\"],\n",
    "            \"sigma\": model.sigma_,\n",
    "        }\n",
    "        search_rows.append(row)\n",
    "\n",
    "        if val_m[\"rmse\"] < best_val_rmse:\n",
    "            best_val_rmse = val_m[\"rmse\"]\n",
    "            best_model = model\n",
    "            best_key = (n_prototypes, alpha)\n",
    "\n",
    "search_df = pd.DataFrame(search_rows).sort_values([\"val_rmse\", \"val_mae\", \"val_r2\"], ascending=[True, True, False]).reset_index(drop=True)\n",
    "\n",
    "print(\"Лучшие конфигурации по validation RMSE:\")\n",
    "display(search_df.head(10))\n",
    "\n",
    "best_n_prototypes, best_alpha = best_key\n",
    "print(\"Лучшая конфигурация:\")\n",
    "print(\"n_prototypes =\", best_n_prototypes)\n",
    "print(\"alpha =\", best_alpha)\n",
    "print(\"sigma =\", round(best_model.sigma_, 6))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "77eb02e8",
   "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>split</th>\n",
       "      <th>r2</th>\n",
       "      <th>rmse</th>\n",
       "      <th>mae</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>train</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.396943</td>\n",
       "      <td>42622.246003</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>validation</td>\n",
       "      <td>0.512792</td>\n",
       "      <td>53050.567712</td>\n",
       "      <td>42496.273011</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>test</td>\n",
       "      <td>0.521061</td>\n",
       "      <td>52431.735115</td>\n",
       "      <td>41934.625581</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        split        r2          rmse           mae\n",
       "0       train  0.510170  53409.396943  42622.246003\n",
       "1  validation  0.512792  53050.567712  42496.273011\n",
       "2        test  0.521061  52431.735115  41934.625581"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAArIAAAGGCAYAAACHemKmAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAgDpJREFUeJzt3XdYU9cbB/BvwggIAqIioAhutKK4imhrtfoTt7Zq6xbrqFbrrKt1t9ZVZ3HUatU66mitdc/W1ipWRcWBUhcuwC0oysz5/WFzJSaMhITk4vfzPDyae0/ee3Jvcnm5Ofc9CiGEABERERGRzCgt3QEiIiIiImMwkSUiIiIiWWIiS0RERESyxESWiIiIiGSJiSwRERERyRITWSIiIiKSJSayRERERCRLTGSJiIiISJaYyBIR6aFWq3H//n1cvXrV0l0hIqIsMJF9zcTExEChUGDlypXSskmTJkGhUOTq+QqFApMmTTJpnxo2bIiGDRuaNCaRMeLj4zF06FD4+vrC3t4exYsXR5UqVZCYmGjprtFr5unTp5g3b570+PHjx1i4cKHlOkQmde7cOWzZskV6fPr0aezYscNyHZIxJrJWrE2bNihUqBCePHmSZZuuXbvC3t4eDx48yMeeGS4qKgqTJk1CTEyMpbsiOXjwIBQKhfRjY2MDDw8PdOjQARcuXNBpHxoaCoVCARcXFzx//lxn/aVLl6RY33zzjda6mJgY9OrVC+XKlYODgwM8PT3RoEEDTJw4Uatdw4YNtfqU+cff39+0O4C0XL58GXXq1MH69evx8ccfY/v27di3bx8OHDgAJycnS3dPNpydnREaGmrpbsieo6Mjxo0bh7Vr1+LmzZuYNGkStm3bZulukYk8efIEH3/8MY4ePYpLly5hyJAhOHv2rKW7JUu2lu4AZa1r167Ytm0bfv31V/To0UNn/bNnz/Dbb7+hWbNmKFq0qNHbGTduHMaMGZOXruYoKioKkydPRsOGDeHn56e1bu/evWbddk4GDx6MOnXqIC0tDWfOnMGSJUtw8OBBnDt3Dp6enlptbW1t8ezZM2zbtg0ffPCB1rq1a9fCwcEBycnJWss1CZKjoyM++ugj+Pn5IS4uDidPnsSMGTMwefJkrfalSpXCtGnTdPrp6upqoldM+nz88cewt7fH0aNHUbJkSUt3h15zNjY2mDx5Mnr06AG1Wg0XFxdesStAgoODpR8AqFixIvr27WvhXskTE1kr1qZNGxQuXBjr1q3Tm8j+9ttvSEpKQteuXfO0HVtbW9jaWu6tYG9vb7FtA8Dbb7+NDh06SI8rVaqEAQMG4Mcff8SoUaO02qpUKtSvXx8//fSTTiK7bt06tGzZEr/88ovW8rlz5+Lp06c4ffo0fH19tdbdvXtXpz+urq7o1q1bXl8WGSAiIgK///479u7dyySWrMaIESPw4Ycf4ubNm6hcuTLc3Nws3SUyoS1btiAqKgrPnz9HQECAxX8XyhWHFlgxR0dHvP/++zhw4IDehGfdunUoXLgw2rRpg4cPH+Kzzz5DQEAAnJ2d4eLigubNmyMyMjLH7egbI5uSkoJhw4ahePHi0jZu3bql89zr16/jk08+QaVKleDo6IiiRYuiY8eOWkMIVq5ciY4dOwIAGjVqJH1VfvDgQQD6x8jevXsXvXv3RokSJeDg4IDq1atj1apVWm00432/+eYbLF26FOXKlYNKpUKdOnVw/PjxHF93Vt5++20AwJUrV/Su79KlC3bt2oXHjx9Ly44fP45Lly6hS5cuOu2vXLmCUqVK6SSxAODh4WF0P7OiOZ6v/ugbh6zZh/p+MtMcj9KlS8PGxkZq4+zsnGN//Pz8styGvrHZa9asQa1ateDo6Ah3d3d06tQJN2/e1GrTsGFDVK1aFREREahXrx4cHR1RpkwZLFmyRCdeSkoKJk6ciPLly0OlUsHHxwejRo1CSkqK1Obo0aNwcHDAlStX8MYbb0ClUsHT0xMff/wxHj58qBNz06ZNUh+LFSuGbt264fbt21ptQkND4ezsjKtXryIkJAROTk7w9vbGlClTIITQavvNN9+gXr16KFq0KBwdHVGrVi38/PPPOe5bzb549dhOnToVSqUS69atM7rfr/r555+1PrfAixviRo4cCVdXV/j5+WH37t3SutGjR6Nw4cKoUKECdu3apbONV7+ZuXnzJhwdHaFQKLTOH1m9f/r06QMhBPz8/NC2bVud/iYnJ8PV1RUff/wxgJdDiTZs2IDPP/8cnp6ecHJyQps2bXTeX4cOHULHjh1RunRp6T0zbNgwnSFFhuwrzfYzLwOAli1b6tx7kPmcXKpUKQQHB8PW1haenp56Y7wqq3OA5ifzPRKGvE+TkpIwYsQI+Pj4QKVSoVKlSvjmm2+02mW33VfPQzmd57M7P2l+NMNYVq5cqfPeUavVqFatmt7XnF3MzPtXc6551TfffKOzPQBYtGiRdA7x9vbGwIEDtX5XaGJq9kOVKlVQq1YtREZGZnlO1Oeff/5BixYtUKRIETg5OaFatWqYP3++VpuLFy+iQ4cOcHd3h4ODA2rXro2tW7dK6zX7LDfvFUM+s/mNV2StXNeuXbFq1Sps3LgRgwYNkpY/fPgQe/bsQefOneHo6Ijz589jy5Yt6NixI8qUKYM7d+7gu+++wzvvvIOoqCh4e3sbtN0+ffpgzZo16NKlC+rVq4fff/8dLVu21Gl3/PhxHDlyBJ06dUKpUqUQExODxYsXo2HDhoiKikKhQoXQoEEDDB48GAsWLMDnn3+OypUrA4D076ueP3+Ohg0b4vLlyxg0aBDKlCmDTZs2ITQ0FI8fP8aQIUO02q9bt04ab6RQKDBz5ky8//77uHr1Kuzs7Ax63QCkD2SRIkX0rn///ffRv39/bN68GR999JHUB39/f9SsWVOnva+vL/bv34/ff/8d7777bo7bz8jIwP3793WWOzo6GjRWc/HixdIv2bFjx2bbtl+/flICv3nzZvz6669a63v27In9+/fj008/RfXq1WFjY4OlS5fi5MmTuepLYGAgRowYobXsxx9/xL59+7SWTZ06FePHj8cHH3yAPn364N69e/j222/RoEEDnDp1SuuK1KNHj9CiRQt88MEH6Ny5MzZu3IgBAwbA3t5eOi5qtRpt2rTB33//jX79+qFy5co4e/Ys5s6di3///Ve62eLBgwdITk7GgAED8O6776J///64cuUKFi5ciH/++Qf//PMPVCoVgBcn/169eqFOnTqYNm0a7ty5g/nz5+Pw4cM6fczIyECzZs1Qt25dzJw5E7t378bEiRORnp6OKVOmSO3mz5+PNm3aoGvXrkhNTcX69evRsWNHbN++Xe/nLjsrVqzAuHHjMHv2bK0/rAzpd27NmDED33zzDbp3745atWph2LBhSE1NxY4dOxAYGIipU6di2bJleP/99xEVFYUyZcpkGWvChAk6w3I09L1/ypcvD4VCgW7dumHmzJl4+PAh3N3dpfXbtm1DYmKizrcbU6dOhUKhwOjRo3H37l3MmzcPTZo0wenTp+Ho6AjgRcL/7NkzDBgwAEWLFsWxY8fw7bff4tatW9i0aZPB+ykrf/31F3bu3JmrtrNnz8adO3cMip/5HAAA165dw4QJE3Ta5eZ9KoRAmzZt8Mcff6B3794IDAzEnj17MHLkSNy+fRtz584FAKxevVqKe+jQISxduhRz585FsWLFAAAlSpQAkLvzfPHixbXiac5NmZeVK1cuy9e/evXqLMedqlQqLFu2TGvZ8ePHsWDBgizj5WTSpEmYPHkymjRpggEDBiA6OhqLFy/G8ePHcfjw4Wx/H40ePTrX29m3bx9atWoFLy8vDBkyBJ6enrhw4QK2b98u/X48f/486tevj5IlS2LMmDFwcnLCxo0b0a5dO/zyyy9477330KBBA619OXXqVADAF198IS2rV69elv3I7jObrwRZtfT0dOHl5SWCg4O1li9ZskQAEHv27BFCCJGcnCwyMjK02ly7dk2oVCoxZcoUrWUAxIoVK6RlEydOFJnfCqdPnxYAxCeffKIVr0uXLgKAmDhxorTs2bNnOn0ODw8XAMSPP/4oLdu0aZMAIP744w+d9u+884545513pMfz5s0TAMSaNWukZampqSI4OFg4OzuLxMRErddStGhR8fDhQ6ntb7/9JgCIbdu26Wwrsz/++EMAED/88IO4d++eiI2NFbt37xbly5cXCoVCHDt2TKt9z549hZOTkxBCiA4dOojGjRsLIYTIyMgQnp6eYvLkyVKfZs2aJT3v3LlzwtHRUQAQgYGBYsiQIWLLli0iKSlJ774AoPfn448/zvb1aHz++ecCgLh//7607I033tDaxxqXLl0SAMSqVaukZa++H54/fy6USqXO9jPvj+z4+vqKli1b6iwfOHCg1nZiYmKEjY2NmDp1qla7s2fPCltbW63lmv00e/ZsaVlKSooIDAwUHh4eIjU1VQghxOrVq4VSqRSHDh3Siqn5/Bw+fFjrNTdu3Fikp6dL7VasWCEAiG+//VYI8eJ96OHhIapWrSqeP38utdu+fbsAICZMmKC1fwCITz/9VFqmVqtFy5Ythb29vbh37560/NXPUWpqqqhatap49913dfbbqzJ/fnbs2CFsbW3FiBEjdOIZ0m99x/XVz3BycrLw8PAQnTt3ltpERkYKGxsbUb16dZGSkiKEEOL+/fuicOHCYsiQIVrb8PX1lR6fO3dOKJVK0bx5cwFAXLt2TVqX1ftHIzo6WgAQixcv1lrepk0b4efnJ9RqtRDi5ee9ZMmS0jlECCE2btwoAIj58+dLy/Sd16ZNmyYUCoW4fv26wfsq8/YzLwsKCpJec+bz6qufwbt374rChQtLbfWdRzPTPD/ze0wIIY4fP65z/s/t+3TLli0CgPjqq6+0Ynbo0EEoFApx+fJlnX5oPj+Zj6dGbs/z+l6XPq9uKzk5WZQuXVraZ6++5twet3feeUe88cYbOm1nzZqltb27d+8Ke3t70bRpU63fxWFhYdLvmcwxM5+Pd+7cKQCIZs2aZfn6NNLT00WZMmWEr6+vePTokdY6zXtdCCEaN24sAgICRHJystb6evXqiQoVKuiN/Wq/MjPkM5vfOLTAytnY2KBTp04IDw/XunS/bt06lChRAo0bNwbw4q9LpfLF4czIyMCDBw/g7OyMSpUq5fqqmYbmCsHgwYO1lg8dOlSnreYKBgCkpaXhwYMHKF++PNzc3Azebubte3p6onPnztIyOzs7DB48GE+fPsWff/6p1f7DDz/UunqqubKY2/qfH330EYoXLw5vb280a9YMCQkJWL16NerUqZPlc7p06YKDBw8iPj4ev//+O+Lj4/UOKwCAN954A6dPn0a3bt0QExOD+fPno127dihRogS+//57nfZ+fn7Yt2+fzo++/a+P5i9kBweHHNumpqYCgHS1UZ+kpCSo1eo83VCYG5s3b4ZarcYHH3yA+/fvSz+enp6oUKEC/vjjD632tra20tfGwIux1h9//DHu3r2LiIgIAC+urFWuXBn+/v5aMTVXxl+NOXz4cNjY2EiPu3fvjhIlSkg32Zw4cQJ3797FJ598orV/W7ZsCX9/f70342T+JkWhUGDQoEFITU3F/v37peWZP0ePHj1CQkIC3n77bYM+Q8eOHcMHH3yA9u3bY9asWVrrjOl35v11//59neopZ8+exd27d/H+++9Ly6pVqwYHBwcEBgZK4/2KFi2KBg0a4MCBA1n2fezYsahZs6Y0BMkQFStWRFBQENauXSste/jwIXbt2oWuXbvqfFXbo0cPFC5cWHrcoUMHeHl5aV0ZzXw8kpKScP/+fdSrVw9CCJw6dcrgPuqzefNmHD9+HNOnT8+x7ZdffglXV1edc7Ip5fQ+3blzJ2xsbHT6MGLECAghdIaP5MTQ87yhFi5ciAcPHuhUhjGG5luyzD/Pnj3TarN//36kpqZi6NCh0u9iAOjbt2+2N+oJITB27Fi0b98eQUFBOfbl1KlTuHbtGoYOHarzLYrmvf7w4UP8/vvv+OCDD/DkyROpzw8ePEBISAguXbqkM6TIUHn5zJoahxbIQNeuXTF37lysW7cOn3/+OW7duoVDhw5h8ODB0i9dtVqN+fPnY9GiRbh27RoyMjKk5xuagFy/fh1KpVLnK5tKlSrptH3+/DmmTZuGFStW4Pbt21pjpRISEgzabubtV6hQQetkALwcinD9+nWt5aVLl9Z6rElqHz16lKvtTZgwAW+//TaePn2KX3/9FevXr9fZ9qtatGiBwoULY8OGDTh9+jTq1KmD8uXLZzlOqGLFili9ejUyMjIQFRWF7du3Y+bMmejXrx/KlCmDJk2aSG2dnJy0Hhvq/v37sLOzQ6FChXJsqxm7ld1Y16JFi6JChQpYtmwZ3nnnHQQGBkKpVGqNMTWFS5cuQQiBChUq6F3/6tdy3t7eOkMtKlasCODF8JC6devi0qVLuHDhAooXL643pmbsueYXwKslzmxsbFChQgXpuGree/o+C/7+/vj777+1limVSpQtWzbLPmps374dX331FU6fPq21X3M7Xu727dto2bIlkpKS8ODBA53nGdrvpKSkLPeZhmZcaW5ujitZsqTONjT+/vtvbNu2DQcOHMCNGzdyjKVPjx49MGjQIFy/fh2+vr7YtGkT0tLS0L17d522r76/FAqFzmf3xo0bmDBhArZu3apzHjH2vJZZRkYGPv/8c3Tt2hXVqlXLtu21a9fw3XffYfHixbn649QYuXmfXr9+Hd7e3lp/BABZn5dzYuh53hAJCQn4+uuvMXz4cGkoQ15cvHgxx89DVp8xe3t7lC1bNsvXs3btWpw/fx4bN27UGdOuj+beDX3jdjUuX74MIQTGjx+P8ePH621z9+5do29sNcVn1pSYyMpArVq14O/vj59++gmff/45fvrpJwghtKoVfP311xg/fjw++ugjfPnll3B3d4dSqcTQoUOhVqvN1rdPP/0UK1aswNChQxEcHAxXV1coFAp06tTJrNvNLPMVtMzEKzcqZCUgIEBKHNu1a4dnz56hb9++eOutt+Dj46P3OSqVCu+//z5WrVqFq1ev5nqSCBsbGwQEBCAgIADBwcFo1KgR1q5dm6fE9VUxMTEoXbp0rpKg+Ph4ANApM/aqDRs2oGvXrggJCdFabsr6qmq1GgqFArt27dJ7THNzY5m+mAEBAZgzZ47e9Zrjm/kKXH47dOgQ2rRpgwYNGmDRokXw8vKCnZ0dVqxYkatfbMCLX1w1a9bE3Llz0b17d6xatQo9e/Y0uk8ODg46NUsPHTqkNa7X0LFx+movAy/GBoaEhODdd9/VuiHHEJ06dcKwYcOwdu1afP7551izZg1q166tN3HPSUZGBv73v//h4cOHGD16NPz9/eHk5ITbt28jNDTUJOe15cuXIyYmBnv27Mmx7RdffIEKFSqgZ8+eOHToUJ63/TqYMWMGlEolRo4caZIa635+fjrfnm3atAlLly7NU9zU1FSMHz8evXv3lv5wMAXNe/Szzz7TOWdrlC9f3uj4pvjMmhITWZno2rUrxo8fjzNnzmDdunWoUKGC1lffP//8Mxo1aoTly5drPe/x48fSIPvc8vX1hVqtxpUrV7R+EURHR+u0/fnnn9GzZ0/Mnj1bWpacnKxzl2Zuryxptn/mzBmo1Wqtv9YvXrworTen6dOn49dff8XUqVP13gWv0aVLF/zwww9QKpXo1KmTwdupXbs2ACAuLs7ovr4qPT0dkZGRaNasWa7aR0VFQaFQ5PgLv0aNGvj+++/x9ttvY8qUKahbty5mzZqFw4cPm6LbAF7ctCGEQJkyZXJ1Uo+NjUVSUpJWMv3vv/8CgHR3bbly5RAZGYnGjRtn+x7U3IQUHR2tdWVKrVbj0qVLqFGjBoCX773o6GidG/eio6N13ptqtRpXr17Vej2v9vGXX36Bg4MD9uzZozXEY8WKFTnuAw3NV+MlSpTAb7/9hhEjRqBFixbSVSRD+21jY6Pzx9Wrn2kvLy8AL45DTm7fvq33htMtW7YgPDzc6GFIGu7u7mjZsiXWrl2Lrl274vDhw1qzYmV26dIlrcdCCFy+fFm6Mnr27Fn8+++/WLVqlVbZw1dvTDTWs2fPMHnyZHzyySc5nstOnTqF9evXY8uWLVn+wW4KuXmfam5affLkidZVWWPPy+Y6z8fGxmL+/PmYNm0aChcubJJEVt+3ZKdPn9Z6nPkzlvkckpqaimvXrum9WLFo0SLcvXvXoNkyNd+Unjt3LssLIJrt29nZmfQiCWC6z6wpcYysTGiuvk6YMAGnT5/WqR1rY2OjcwVy06ZNRo2Dad68OQDo3L2p7xeDvu1+++23WkMbgJdX7l79ZahPixYtEB8fjw0bNkjL0tPT8e2338LZ2RnvvPNObl6G0cqVK4f27dtj5cqV0hVLfRo1aoQvv/wSYWFh2V7RPHToENLS0nSWa8bkGXPVKCt79+5FQkKC3nJEr0pPT8cvv/yCN998M8ernYmJiejevTvatGmDcePGoUmTJlIiYyrvv/++VAT+1feUEELnF1J6ejq+++476XFqaiq+++47FC9eHLVq1QIAfPDBB7h9+7bescjPnz9HUlISAKBx48ZQqVRYsGCB1hW3tWvX4s6dO2jVqhWAF398eHh4YMmSJVpDAHbt2oULFy7orTAQFham9TrCwsJgZ2cnjW/XlDPL/JmJiYnRmr4yJxUrVpS+Qv3222+hVqu1qnsY0++caCb5yFzh4syZM0hOTsbp06el8dcPHz7EX3/9hQYNGmg9X/P1epcuXRAYGGjw9l/VvXt3REVFYeTIkdK9Bfr8+OOPWuN9f/75Z8TFxUnnPU3CmPk9KITQKW1krPnz5yMpKUnrzvCsjBkzBvXr10ebNm1Msu3s5PQ+bdGiBTIyMrTaAS/qZCsUCmn/5Za5zvOTJ09GiRIl0L9/f6Oeb6wmTZrA3t4eCxYs0HrvLF++HAkJCTqfsSdPnmDq1KkYNmxYjt+IZVazZk2UKVMG8+bN0/l9qtmuh4cHGjZsiO+++07vhZJ79+4Z8MpeMvVn1lR4RVYmypQpg3r16uG3334DAJ1EtlWrVpgyZQp69eqFevXq4ezZs1i7dq3OuKfcCAwMROfOnbFo0SIkJCSgXr16OHDgAC5fvqzTtlWrVli9ejVcXV1RpUoVhIeHY//+/TrjcgMDA2FjY4MZM2YgISEBKpUK7777rt46qv369cN3332H0NBQREREwM/PDz///LN0leXVMVrmMHLkSGzcuBHz5s3L8mYMpVKJcePG5RhrxowZiIiIwPvvvy9d9Tl58iR+/PFHuLu769zElZCQgDVr1uiNld1ECRs2bMBnn30GlUqF58+fa8VISEhARkYGtmzZgnbt2mH//v3SFf7cTHs5cOBAPH/+XKdcjSmVK1cOX331FcaOHYuYmBi0a9cOhQsXxrVr1/Drr7+iX79++Oyzz6T23t7emDFjBmJiYlCxYkVpvPLSpUul8bTdu3fHxo0b0b9/f/zxxx+oX78+MjIycPHiRWzcuBF79uxB7dq14e7ujnHjxmH8+PEICQlB27ZtcfXqVYSFhaF69ero06cPgBdXOGbMmIFevXrhnXfeQefOnaUyVn5+fhg2bJjWa3JwcMDu3bvRs2dPBAUFYdeuXdixYwc+//xz6Wppy5YtMWfOHDRr1gxdunTB3bt3sXDhQpQvXx5nzpwxeD96enpi1qxZ6NOnD7p164YWLVoY3O/ccHJywpAhQzB9+nTY2tqiZs2aWLJkCZRKJeLi4tCyZUu0adMGy5YtQ0pKitaxA4Bbt27B3t4+1+WnctKyZUsULVoUmzZtQvPmzbOs0ezu7o633noLvXr1wp07dzBv3jyUL19emlXJ398f5cqVw2effYbbt2/DxcUFv/zyS5Zj7jMyMrTq5wIvr9YdO3YMpUqV0voad+/evZg6dWqu7l3Yu3evSb/1yEpu3qetW7dGo0aN8MUXXyAmJgbVq1fH3r178dtvv2Ho0KHZlsHSx1zn+b1792Lt2rX5PrlA8eLFMXbsWEyePBnNmjVDmzZtEB0djUWLFqFOnTo65+6TJ0+iWLFiOpPu5ESpVGLx4sVo3bo1AgMD0atXL3h5eeHixYs4f/68NFxl4cKFeOuttxAQEIC+ffuibNmyuHPnDsLDw3Hr1q1c1Zh/lak/syaTv0USKC8WLlwoAIg333xTZ11ycrIYMWKE8PLyEo6OjqJ+/foiPDxcp5xGbspvCfGi5NLgwYNF0aJFhZOTk2jdurW4efOmTpmYR48eiV69eolixYoJZ2dnERISIi5evCh8fX1Fz549tWJ+//33omzZssLGxkarxIm+kh937tyR4trb24uAgACtPmd+LZlLXWm82k99NOVwNm3apHd9w4YNhYuLi3j8+LEQInflpvT16fDhw2LgwIGiatWqwtXVVdjZ2YnSpUuL0NBQceXKFa3nZ1d+K6ePq6+vb7bPBSCVT/n0009FgwYNxO7du3XivPp++Omnn4RCodBpa+ryWxq//PKLeOutt4STk5NwcnIS/v7+YuDAgSI6OlpqoymJc+LECREcHCwcHByEr6+vCAsL04mXmpoqZsyYId544w2hUqlEkSJFRK1atcTkyZNFQkKCVtuFCxcKf39/YWdnJ0qUKCE+/vhj8eDBA52YGzZsEDVq1BAqlUq4u7uLrl27ilu3bundP1euXBFNmzYVhQoVEiVKlBATJ07UKZW3fPlyUaFCBaFSqYS/v79YsWJFtqWGMsuqZM67774rSpcuLZ48eWJUv1+lrzRRWlqaGDp0qChcuLAoXbq02L17t3BychI9e/YUo0ePFs7OzqJs2bJi69atOtsAoFWSSwj95ZpyKr+V2SeffCIAiHXr1ums03zef/rpJzF27Fjh4eEhHB0dRcuWLbVKagkhRFRUlGjSpIlwdnYWxYoVE3379hWRkZFZlq7K7kdzHtJs38vLS6f03qvnK82xb9u2rd7XYOryW7l9nz558kQMGzZMeHt7Czs7O1GhQgUxa9YsrbJPmWVXfkuI3J3n9b2u7LYVGBio1R99v/PMUX5LIywsTOscMmDAAJ0yWZrz/Ny5c3P9+l71999/i//973+icOHCwsnJSVSrVk0qE6hx5coV0aNHD+Hp6Sns7OxEyZIlRatWrcTPP/+sN2ZO5bdy+5nNbwohcnlHDBFZNT8/P0yaNEma6eZVBw8eRGhoqEVnYDGVhg0b4v79+zh37pylu5Kl0NBQ/Pzzz3j69Kmlu5KvnJ2d0aFDB4vcBDJs2DAsX74c8fHxOlU7Dh48iEaNGmHTpk1aU1Kbk2YGJ0PGQOa31/V9SgUHx8gSEZHsJScnY82aNWjfvn2uSs8RUcHAMbJEBcR7772X7Ti1EiVK4L333svHHhGZ3927d7F//378/PPPePDggc4U1pb05ptv5qnMERHljIksUQGhmes8K5UrV86xDZHcREVFoWvXrvDw8MCCBQus6m7qmTNnWroLRAUex8gSERERkSxxjCwRERERyRITWSIiIiKSJSayRERERCRLvNnLRNRqNWJjY1G4cOFs53QnIiIioqwJIfDkyRN4e3tDqcz+misTWROJjY2Fj4+PpbtBREREVCDcvHkTpUqVyrYNE1kT0cwLffPmTbi4uFi4N0RERETylJiYCB8fHym3yg4TWRPRDCdwcXFhIktERESUR7kZqsmbvYiIiIhIlpjIEhEREZEscWgBERERyU6GWuDYtYe4+yQZHoUd8GYZd9goTVM1SI6x5dhnU2AiS0RERLKy+1wcJm+LQlxCsrTMy9UBE1tXQbOqXq9dbDn22VQUQghh6U4UBImJiXB1dUVCQgJv9iIiIjKT3efiMGDNSbyavGiuDy7uVtPoBEuOseXY55wYklNxjCwRERHJQoZaYPK2KJ3ECoC0bPK2KGSoDb9GJ8fYcuyzqXFoAREREcnCsWsPtb7ifpUAEJeQjJ4/HEPxwiqDYt97kiK72NbQ52PXHiK4XFGDYpsSE1kiIiKShbtPsk6sMvv78n2z9UGOsc3Z59weE3NhIktERESy4FHYIVftutUtDb+iTgbFjnmQhDVHb8gqtjX0ObfHxFyYyBIREZEsvFnGHV6uDohPSNY7dlMBwNPVAZPbVDW4PFSGWuDAhbuyim0NfX6zjLtBcU3Nojd7+fn5QaFQ6PwMHDgQANCwYUOddf3799eKcePGDbRs2RKFChWCh4cHRo4cifT0dK02Bw8eRM2aNaFSqVC+fHmsXLlSpy8LFy6En58fHBwcEBQUhGPHjpntdRMREZHhbJQKTGxdBcDLO+c1NI8ntq5iVI1TOcaWY59NzaKJ7PHjxxEXFyf97Nu3DwDQsWNHqU3fvn212sycOVNal5GRgZYtWyI1NRVHjhzBqlWrsHLlSkyYMEFqc+3aNbRs2RKNGjXC6dOnMXToUPTp0wd79uyR2mzYsAHDhw/HxIkTcfLkSVSvXh0hISG4e/duPuwFIiIiyq1mVb2wuFtNnZuXPF0d8lwOShPb01X763Jrji3HPpuSVdWRHTp0KLZv345Lly5BoVCgYcOGCAwMxLx58/S237VrF1q1aoXY2FiUKFECALBkyRKMHj0a9+7dg729PUaPHo0dO3bg3Llz0vM6deqEx48fY/fu3QCAoKAg1KlTB2FhYQAAtVoNHx8ffPrppxgzZkyu+s46skRERPkn8uZjtF14GIVVtljao7ZsZrLizF45MySnspoxsqmpqVizZg2GDx8OheLlzlm7di3WrFkDT09PtG7dGuPHj0ehQoUAAOHh4QgICJCSWAAICQnBgAEDcP78edSoUQPh4eFo0qSJ1rZCQkIwdOhQabsREREYO3astF6pVKJJkyYIDw/Psr8pKSlISUmRHicmJubp9RMREVHu3Ul8cbd8meJOJi//ZKNUmK2klLliy7HPpmA1ieyWLVvw+PFjhIaGSsu6dOkCX19feHt748yZMxg9ejSio6OxefNmAEB8fLxWEgtAehwfH59tm8TERDx//hyPHj1CRkaG3jYXL17Msr/Tpk3D5MmTjX69REREZDxNjVNvV0cL94QsyWoS2eXLl6N58+bw9vaWlvXr10/6f0BAALy8vNC4cWNcuXIF5cqVs0Q3JWPHjsXw4cOlx4mJifDx8bFgj4iIiF4fsQnPAQBebpYt/0SWZRWJ7PXr17F//37pSmtWgoKCAACXL19GuXLl4OnpqVNd4M6dOwAAT09P6V/NssxtXFxc4OjoCBsbG9jY2Ohto4mhj0qlgkpl2CwZREREZBqxj3lFlixctUBjxYoV8PDwQMuWLbNtd/r0aQCAl9eLu+SCg4Nx9uxZreoC+/btg4uLC6pUqSK1OXDggFacffv2ITg4GABgb2+PWrVqabVRq9U4cOCA1IaIiIisS9xjXpElK0hk1Wo1VqxYgZ49e8LW9uUF4itXruDLL79EREQEYmJisHXrVvTo0QMNGjRAtWrVAABNmzZFlSpV0L17d0RGRmLPnj0YN24cBg4cKF0t7d+/P65evYpRo0bh4sWLWLRoETZu3Ihhw4ZJ2xo+fDi+//57rFq1ChcuXMCAAQOQlJSEXr165e/OICIiolzRjJH14hXZ15rFhxbs378fN27cwEcffaS13N7eHvv378e8efOQlJQEHx8ftG/fHuPGjZPa2NjYYPv27RgwYACCg4Ph5OSEnj17YsqUKVKbMmXKYMeOHRg2bBjmz5+PUqVKYdmyZQgJCZHafPjhh7h37x4mTJiA+Ph4BAYGYvfu3To3gBEREZHlZagF4v+rWuDNK7KvNauqIytnrCNLRESUP+ITklF32gHYKBX496vmFp9dikzLkJzK4kMLiIiIiAyhqVjg6eLAJPY1x0SWiIiIZCVWc6OXK4cVvO6YyBIREZGsxP1XesvLjTd6ve6YyBIREZGsaIYWePOK7GuPiSwRERHJinRFlonsa4+JLBEREclKnOaKLIcWvPaYyBIREZGsxCZoasgykX3dMZElIiIi2UhJz8C9JykAOLSAmMgSERGRjNxJeJHEqmyVcHeyt3BvyNKYyBIREZFsaCoWeLk6QKHgZAivOyayREREJBtxUiLL8bHERJaIiIhkJFaaDIHjY4mJLBEREcmI5opsSVYsIDCRJSIiIhl5ORkCE1liIktEREQycvvxf2NkObSAwESWiIiIZCROMxkCr8gSmMgSERGRTDxLTUfC8zQAvCJLLzCRJSIiIlnQVCxwVtnCxcHOwr0ha8BEloiIiGRBU7HAm1dj6T9MZImIiEgWWLGAXsVEloiIiGRBU7GAV2RJg4ksERERyQKnp6VXMZElIiIiWdCU3vJy5RVZeoGJLBEREclCrDS0gFdk6QUmskRERGT1hBAvJ0NgIkv/YSJLREREVi/xeTqepWYA4NACeomJLBEREVm92P9u9HJ3soeDnY2Fe0PWgoksERERWT3N+FhejaXMmMgSERGR1YtN4GQIpIuJLBEREVm9OE6GQHowkSUiIiKrF8crsqQHE1kiIiKyerG8Ikt6MJElIiIiq8casqQPE1kiIiKyamq1QFwCqxaQLiayREREZNXuJ6UgLUNAoQBKuDCRpZeYyBIREZFVi3v8YliBR2EV7GyYutBLFn03+Pn5QaFQ6PwMHDgQAJCcnIyBAweiaNGicHZ2Rvv27XHnzh2tGDdu3EDLli1RqFAheHh4YOTIkUhPT9dqc/DgQdSsWRMqlQrly5fHypUrdfqycOFC+Pn5wcHBAUFBQTh27JjZXjcRERHl3sthBRwfS9osmsgeP34ccXFx0s++ffsAAB07dgQADBs2DNu2bcOmTZvw559/IjY2Fu+//770/IyMDLRs2RKpqak4cuQIVq1ahZUrV2LChAlSm2vXrqFly5Zo1KgRTp8+jaFDh6JPnz7Ys2eP1GbDhg0YPnw4Jk6ciJMnT6J69eoICQnB3bt382lPEBERUVZi/7siW5I3etErFEIIYelOaAwdOhTbt2/HpUuXkJiYiOLFi2PdunXo0KEDAODixYuoXLkywsPDUbduXezatQutWrVCbGwsSpQoAQBYsmQJRo8ejXv37sHe3h6jR4/Gjh07cO7cOWk7nTp1wuPHj7F7924AQFBQEOrUqYOwsDAAgFqtho+PDz799FOMGTMmV31PTEyEq6srEhIS4OLiYsrdQkRE9FqbuiMK3x+6hj5vlcG4VlUs3R0yM0NyKqsZaJKamoo1a9bgo48+gkKhQEREBNLS0tCkSROpjb+/P0qXLo3w8HAAQHh4OAICAqQkFgBCQkKQmJiI8+fPS20yx9C00cRITU1FRESEVhulUokmTZpIbYiIiMhyNFdkvXhFll5ha+kOaGzZsgWPHz9GaGgoACA+Ph729vZwc3PTaleiRAnEx8dLbTInsZr1mnXZtUlMTMTz58/x6NEjZGRk6G1z8eLFLPubkpKClJQU6XFiYmLuXywRERHlWux/Y2S9WXqLXmE1V2SXL1+O5s2bw9vb29JdyZVp06bB1dVV+vHx8bF0l4iIiAqkOF6RpSxYRSJ7/fp17N+/H3369JGWeXp6IjU1FY8fP9Zqe+fOHXh6ekptXq1ioHmcUxsXFxc4OjqiWLFisLGx0dtGE0OfsWPHIiEhQfq5efOmYS+aiIiIcpSeocbdJ//N6sUrsvQKq0hkV6xYAQ8PD7Rs2VJaVqtWLdjZ2eHAgQPSsujoaNy4cQPBwcEAgODgYJw9e1arusC+ffvg4uKCKlWqSG0yx9C00cSwt7dHrVq1tNqo1WocOHBAaqOPSqWCi4uL1g8RERGZ1p0nKVALwM5GgWLOKkt3h6yMxcfIqtVqrFixAj179oSt7cvuuLq6onfv3hg+fDjc3d3h4uKCTz/9FMHBwahbty4AoGnTpqhSpQq6d++OmTNnIj4+HuPGjcPAgQOhUr14s/fv3x9hYWEYNWoUPvroI/z+++/YuHEjduzYIW1r+PDh6NmzJ2rXro0333wT8+bNQ1JSEnr16pW/O4OIiIi0xD1+MT7W09UBSqXCwr0ha2PxRHb//v24ceMGPvroI511c+fOhVKpRPv27ZGSkoKQkBAsWrRIWm9jY4Pt27djwIABCA4OhpOTE3r27IkpU6ZIbcqUKYMdO3Zg2LBhmD9/PkqVKoVly5YhJCREavPhhx/i3r17mDBhAuLj4xEYGIjdu3fr3ABGRERE+Ss24b/xsZwMgfSwqjqycsY6skRERKa35M8rmL7rItoFemNepxqW7g7lA1nWkSUiIiJ6lWZoASsWkD5MZImIiMhqaYYWsGIB6cNEloiIiKxW3H+TIXCMLOnDRJaIiIislmYyBG8OLSA9mMgSERGRVUpOy8CDpFQAgLcbhxaQLiayREREZJXi/hsf62hnA1dHOwv3hqwRE1kiIiKySi8rFjhAoeBkCKSLiSwRERFZpZcVCzg+lvRjIktERERWSboiy9JblAUmskRERGSVpCuyrFhAWWAiS0RERFZJU0OWFQsoK0xkiYiIyCrFPuZkCJQ9JrJERERklV5OhsArsqQfE1kiIiKyOk+S0/AkJR0Ar8hS1pjIEhERkdXRTIbg4mALJ5WthXtD1oqJLBEREVkdzfhYViyg7DCRJSIiIqsTx9JblAtMZImIiMjqcDIEyg0mskRERGR1bj/mFVnKGRNZIiIisjqayRB4RZayw0SWiIiIrI5mjCxLb1F2mMgSERGRVRFCZKpawCuylDUmskRERGRVHj1LQ0q6GgDgyaEFlA0mskRERGRVNFdjizmroLK1sXBvyJoxkSUiIiKrwmEFlFtMZImIiMiqvLzRi4ksZY+JLBEREVmVWKn0FisWUPaYyBIREZFViZMmQ+AVWcoeE1kiIiKyKprJEDirF+WEiSwRERFZldjHnAyBcoeJLBEREVmNDLVAfCKHFlDuGJTI3r17N9v16enpOHbsWJ46RERERK+ve09SkKEWsFEq4FGYiSxlz6BE1svLSyuZDQgIwM2bN6XHDx48QHBwsOl6R0RERK8VTcWCEoVVsFEqLNwbsnYGJbJCCK3HMTExSEtLy7YNERERUW5pKhZ48UYvygWTj5FVKPjXExERERknTqohy2EFlDPe7EVERERWQ1OxoCSvyFIu2BrSWKFQ4MmTJ3BwcIAQAgqFAk+fPkViYiIASP8SERERGYNXZMkQBo+RrVixIooUKQJ3d3c8ffoUNWrUQJEiRVCkSBFUqlTJ4A7cvn0b3bp1Q9GiReHo6IiAgACcOHFCWh8aGgqFQqH106xZM60YDx8+RNeuXeHi4gI3Nzf07t0bT58+1Wpz5swZvP3223BwcICPjw9mzpyp05dNmzbB398fDg4OCAgIwM6dOw1+PURERGS82Mf/JbK8Iku5YNAV2T/++MOkG3/06BHq16+PRo0aYdeuXShevDguXbqEIkWKaLVr1qwZVqxYIT1WqVRa67t27Yq4uDjs27cPaWlp6NWrF/r164d169YBeHGluGnTpmjSpAmWLFmCs2fP4qOPPoKbmxv69esHADhy5Ag6d+6MadOmoVWrVli3bh3atWuHkydPomrVqiZ93URERKRfbMJ/NWQ5GQLlgkJYsMzAmDFjcPjwYRw6dCjLNqGhoXj8+DG2bNmid/2FCxdQpUoVHD9+HLVr1wYA7N69Gy1atMCtW7fg7e2NxYsX44svvkB8fDzs7e2lbW/ZsgUXL14EAHz44YdISkrC9u3bpdh169ZFYGAglixZkuNrSUxMhKurKxISEuDi4pLbXUBERET/SU1Xo9L4XRACODGuCYo5q3J+EhU4huRUBg0tSE9PR0pKitayO3fuYPLkyRg1ahT+/vtvgzq6detW1K5dGx07doSHhwdq1KiB77//XqfdwYMH4eHhgUqVKmHAgAF48OCBtC48PBxubm5SEgsATZo0gVKpxD///CO1adCggZTEAkBISAiio6Px6NEjqU2TJk20thsSEoLw8HCDXhMREREZ505iMoQA7G2VKOpkn/MT6LVnUCLbt29fDB48WHr85MkT1KlTBwsXLsSePXvQqFEjg8aVXr16FYsXL0aFChWwZ88eDBgwAIMHD8aqVaukNs2aNcOPP/6IAwcOYMaMGfjzzz/RvHlzZGRkAADi4+Ph4eGhFdfW1hbu7u6Ij4+X2pQoUUKrjeZxTm0061+VkpKCxMRErR8iIiIynmZ8rLerA8t5Uq4YNEb28OHDCAsLkx7/+OOPyMjIwKVLl+Dq6orRo0dj1qxZaNGiRa7iqdVq1K5dG19//TUAoEaNGjh37hyWLFmCnj17AgA6deoktQ8ICEC1atVQrlw5HDx4EI0bNzak+yY1bdo0TJ482WLbJyIiKmji/hsf68XxsZRLBl2RvX37NipUqCA9PnDgANq3bw9XV1cAQM+ePXH+/Plcx/Py8kKVKlW0llWuXBk3btzI8jlly5ZFsWLFcPnyZQCAp6en1rS5wIshEA8fPoSnp6fU5s6dO1ptNI9zaqNZ/6qxY8ciISFB+sk8VS8REREZ7rZUsYCltyh3DEpkHRwc8Pz5c+nx0aNHERQUpLX+1bJX2alfvz6io6O1lv3777/w9fXN8jm3bt3CgwcP4OXlBQAIDg7G48ePERERIbX5/fffoVarpb4FBwfjr7/+0ppOd9++fahUqZJUISE4OBgHDhzQ2ta+ffsQHBystx8qlQouLi5aP0RERGQ8TQ1ZViyg3DIokQ0MDMTq1asBAIcOHcKdO3fw7rvvSuuvXLkCb2/vXMcbNmwYjh49iq+//hqXL1/GunXrsHTpUgwcOBAA8PTpU4wcORJHjx5FTEwMDhw4gLZt26J8+fIICQkB8OIKbrNmzdC3b18cO3YMhw8fxqBBg9CpUyepL126dIG9vT169+6N8+fPY8OGDZg/fz6GDx8u9WXIkCHYvXs3Zs+ejYsXL2LSpEk4ceIEBg0aZMguIiIiIiPF/TerF6/IUq4JAxw8eFA4OjqKsmXLCkdHR/HRRx9prR8wYIDo0aOHISHFtm3bRNWqVYVKpRL+/v5i6dKl0rpnz56Jpk2biuLFiws7Ozvh6+sr+vbtK+Lj47ViPHjwQHTu3Fk4OzsLFxcX0atXL/HkyROtNpGRkeKtt94SKpVKlCxZUkyfPl2nLxs3bhQVK1YU9vb24o033hA7duzI9etISEgQAERCQoJBr5+IiIheaDbvL+E7erv4/cIdS3eFLMiQnMrgOrIXLlzA3r174enpiY4dO0KpfHlRd+nSpXjzzTcRGBho2mxbBlhHloiIKG8Cp+zF42dp2DO0ASp5FrZ0d8hCDMmpDKpaALz4Kr9y5cp612lmySIiIiIyxLPUdDx+9uJeFg4toNwyKJH966+/ctWuQYMGRnWGiIiIXk+x/42PdVbZwsXBzsK9IbkwKJFt2LChVKA4qxEJCoVCmqyAiIiIKDc0FQu8XHk1lnLPoES2SJEiKFy4MEJDQ9G9e3cUK1bMXP0iIiKi18jLigUsvUW5Z1D5rbi4OMyYMQPh4eEICAhA7969ceTIEbi4uMDV1VX6ISIiIjJEbMLL6WmJcsugRNbe3h4ffvgh9uzZg4sXL6JatWoYNGgQfHx88MUXXyA9Pd1c/SQiIqICTLoiy8kQyAAGJbKZlS5dGhMmTMD+/ftRsWJFTJ8+HYmJiabsGxEREb0mpCuyrFhABjAqkU1JScG6devQpEkTVK1aFcWKFcOOHTvg7u5u6v4RERHRayAu4cUVWW+OkSUDGHSz17Fjx7BixQqsX78efn5+6NWrFzZu3MgEloiIiIwmhEDsY1YtIMMZlMjWrVsXpUuXxuDBg1GrVi0AwN9//63Trk2bNqbpHRERERV4ic/T8Sz1RelOjpElQxg8s9eNGzfw5ZdfZrmedWSJiIjIEJrxsUUK2cHR3sbCvSE5MSiRVavVObZ59uyZ0Z0hIiKi18/LyRB4NZYMY3TVglelpKRgzpw5KFu2rKlCEhER0WtAMz0tb/QiQxmUyKakpGDs2LGoXbs26tWrhy1btgAAfvjhB5QpUwZz587FsGHDzNFPIiIiKqDiWHqLjGTQ0IIJEybgu+++Q5MmTXDkyBF07NgRvXr1wtGjRzFnzhx07NgRNjYc20JERES5F8vJEMhIBiWymzZtwo8//og2bdrg3LlzqFatGtLT0xEZGQmFQmGuPhIREVEBpim9xSuyZCiDhhbcunVLKrtVtWpVqFQqDBs2jEksERERGU0zGQKvyJKhDEpkMzIyYG9vLz22tbWFs7OzyTtFRERErwe1WiBeSmR5RZYMY9DQAiEEQkNDoVKpAADJycno378/nJyctNpt3rzZdD0kIiKiAutBUipSM9RQKABPJrJkIIMS2Z49e2o97tatm0k7Q0RERK8XTcUCj8Iq2NmYrCoovSYMSmRXrFhhrn4QERHRa0hzoxfHx5Ix+KcPERERWczLyRA4rIAMx0SWiIiILIbT01JeMJElIiIii4llxQLKAyayREREZDFx0mQIvCJLhmMiS0RERBajmQyBiSwZg4ksERERWUR6hhp3Ev9LZDm0gIzARJaIiIgs4s6TFKgFYGejQDFnlaW7QzLERJaIiIgsQjM+toSLA5RKhYV7Q3LERJaIiIgsQlOxwJult8hITGSJiIjIIjRXZL04GQIZiYksERERWQQrFlBeMZElIiIii4jV1JBlxQIyEhNZIiIisohYTk9LecREloiIiCwi7vF/09NyjCwZiYksERER5bvktAw8SEoFwKoFZDwmskRERJTv4v+70cvBTgm3QnYW7g3JlcUT2du3b6Nbt24oWrQoHB0dERAQgBMnTkjrhRCYMGECvLy84OjoiCZNmuDSpUtaMR4+fIiuXbvCxcUFbm5u6N27N54+farV5syZM3j77bfh4OAAHx8fzJw5U6cvmzZtgr+/PxwcHBAQEICdO3ea50UTERG95jTjY73dHKFQcDIEMo5FE9lHjx6hfv36sLOzw65duxAVFYXZs2ejSJEiUpuZM2diwYIFWLJkCf755x84OTkhJCQEycnJUpuuXbvi/Pnz2LdvH7Zv346//voL/fr1k9YnJiaiadOm8PX1RUREBGbNmoVJkyZh6dKlUpsjR46gc+fO6N27N06dOoV27dqhXbt2OHfuXP7sDCIioteIZnwshxVQXiiEEMJSGx8zZgwOHz6MQ4cO6V0vhIC3tzdGjBiBzz77DACQkJCAEiVKYOXKlejUqRMuXLiAKlWq4Pjx46hduzYAYPfu3WjRogVu3boFb29vLF68GF988QXi4+Nhb28vbXvLli24ePEiAODDDz9EUlIStm/fLm2/bt26CAwMxJIlS3J8LYmJiXB1dUVCQgJcXFzytF+IiIgKum8PXMLsff+iY61SmNWxuqW7Q1bEkJzKoldkt27ditq1a6Njx47w8PBAjRo18P3330vrr127hvj4eDRp0kRa5urqiqCgIISHhwMAwsPD4ebmJiWxANCkSRMolUr8888/UpsGDRpISSwAhISEIDo6Go8ePZLaZN6Opo1mO0RERGQ6mulpvTgZAuWBRRPZq1evYvHixahQoQL27NmDAQMGYPDgwVi1ahUAID4+HgBQokQJreeVKFFCWhcfHw8PDw+t9ba2tnB3d9dqoy9G5m1k1Uaz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CpVKpTXEhIjyhoksEeWrgIAA1KxZU0owDVG4cOFsb9pZvHgxOnTogE8++QT+/v7o27evdFXwo48+wttvv401a9Zk+fySJUti586dOHbsGKpXr47+/fujd+/eWjcQ5cX06dMxZMgQ1KpVC/Hx8di2bRvs7e0BQNon69evR9WqVTFhwgRMmTIFoaGhuY6/YsUK1KpVC61atUJwcDCEENi5c6fO1+LZSUtLQ69evVCxYkVDX56kUKFC2LNnDx4+fIg6deqgQ4cOaNy4McLCwrTa7d69G15eXihTpgxmzJiBb7/9Fm+99ZbR223Tpg2GDRuGQYMGITAwEEeOHNF7o9qrGjdujAoVKqBBgwb48MMP0aZNG4NmEKtevTrmzJmDGTNmoGrVqli7di2mTZum0+6nn35C165dtcbjElHeKETm79CIiPLBjh07MHLkSJw7d84kVzqt3cGDB9GoUSM8evQoyzv9KWehoaHw8/PL8zS1r8Z8/PixVg1cc7h//z4qVaqEEydOoEyZMmbdFtHrhOW3iCjftWzZEpcuXcLt27dzPQ6RSM5iYmKwaNEiJrFEJsZElogsInPdTaKCrnbt2qhdu7alu0FU4HBoARERycKWLVvg5uaGhg0bWrorRGQlmMgSERERkSwV/LssiIiIiKhAYiJLRERERLLERJaIiIiIZImJLBERERHJEhNZIiIiIpIlJrJEREREJEtMZImIiIhIlpjIEhEREZEs/R8aeWHAFMnjowAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 700x400 with 1 Axes>"
      ]
     },
     "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</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>170835.035713</td>\n",
       "      <td>208189.809824</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>126913.469998</td>\n",
       "      <td>187521.135570</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>246611.883092</td>\n",
       "      <td>269935.842537</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>244250.462969</td>\n",
       "      <td>270102.333733</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>271127.650112</td>\n",
       "      <td>265637.877925</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>189289.951199</td>\n",
       "      <td>189107.502703</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>343510.576500</td>\n",
       "      <td>276873.696031</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>203461.591080</td>\n",
       "      <td>185461.893451</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>285903.247682</td>\n",
       "      <td>278803.162808</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>224868.958375</td>\n",
       "      <td>224449.420520</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          y_true         y_pred\n",
       "0  170835.035713  208189.809824\n",
       "1  126913.469998  187521.135570\n",
       "2  246611.883092  269935.842537\n",
       "3  244250.462969  270102.333733\n",
       "4  271127.650112  265637.877925\n",
       "5  189289.951199  189107.502703\n",
       "6  343510.576500  276873.696031\n",
       "7  203461.591080  185461.893451\n",
       "8  285903.247682  278803.162808\n",
       "9  224868.958375  224449.420520"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pred_train = best_model.predict(X_train_proc)\n",
    "pred_val = best_model.predict(X_val_proc)\n",
    "pred_test = best_model.predict(X_test_proc)\n",
    "\n",
    "metrics_df = pd.DataFrame([\n",
    "    {\"split\": \"train\", **regression_metrics(y_train, pred_train)},\n",
    "    {\"split\": \"validation\", **regression_metrics(y_val, pred_val)},\n",
    "    {\"split\": \"test\", **regression_metrics(y_test, pred_test)},\n",
    "])\n",
    "\n",
    "display(metrics_df)\n",
    "\n",
    "plt.figure(figsize=(7, 4))\n",
    "plt.plot(search_df[\"n_prototypes\"].astype(str) + \" | \" + search_df[\"alpha\"].astype(str), search_df[\"val_rmse\"], marker=\"o\")\n",
    "plt.xticks(rotation=90)\n",
    "plt.title(\"Validation RMSE для перебора конфигураций прототипной сети\")\n",
    "plt.ylabel(\"RMSE\")\n",
    "plt.xlabel(\"(число прототипов | alpha)\")\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "comparison_df = pd.DataFrame({\n",
    "    \"y_true\": y_test.reset_index(drop=True),\n",
    "    \"y_pred\": pd.Series(pred_test).reset_index(drop=True)\n",
    "})\n",
    "print(\"Первые 10 фактических и предсказанных значений на тесте:\")\n",
    "display(comparison_df.head(10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "743c25c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Основные прототипы (по impact_score = support_share × |вес выхода|):\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>prototype_id</th>\n",
       "      <th>support_n</th>\n",
       "      <th>support_share_train</th>\n",
       "      <th>prototype_output_weight</th>\n",
       "      <th>impact_score</th>\n",
       "      <th>assigned_mean_target_train</th>\n",
       "      <th>num__squarefeet</th>\n",
       "      <th>num__bedrooms</th>\n",
       "      <th>num__bathrooms</th>\n",
       "      <th>num__yearbuilt</th>\n",
       "      <th>cat__neighborhood</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>7</td>\n",
       "      <td>3844</td>\n",
       "      <td>0.128133</td>\n",
       "      <td>95506.687148</td>\n",
       "      <td>12237.590180</td>\n",
       "      <td>272746.439862</td>\n",
       "      <td>2424.082249</td>\n",
       "      <td>4.416710</td>\n",
       "      <td>2.629099</td>\n",
       "      <td>1968.388860</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>3761</td>\n",
       "      <td>0.125367</td>\n",
       "      <td>-96853.934599</td>\n",
       "      <td>12142.254934</td>\n",
       "      <td>175264.422465</td>\n",
       "      <td>1541.357333</td>\n",
       "      <td>2.579437</td>\n",
       "      <td>2.638151</td>\n",
       "      <td>1970.338735</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>3734</td>\n",
       "      <td>0.124467</td>\n",
       "      <td>96690.023035</td>\n",
       "      <td>12034.684867</td>\n",
       "      <td>272552.660643</td>\n",
       "      <td>2460.813487</td>\n",
       "      <td>4.418785</td>\n",
       "      <td>1.373829</td>\n",
       "      <td>2001.336098</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>3617</td>\n",
       "      <td>0.120567</td>\n",
       "      <td>-96452.147420</td>\n",
       "      <td>11628.913907</td>\n",
       "      <td>175220.763401</td>\n",
       "      <td>1580.509815</td>\n",
       "      <td>2.588609</td>\n",
       "      <td>1.359690</td>\n",
       "      <td>2002.136577</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6</td>\n",
       "      <td>3863</td>\n",
       "      <td>0.128767</td>\n",
       "      <td>-88722.805440</td>\n",
       "      <td>11424.539914</td>\n",
       "      <td>181692.435129</td>\n",
       "      <td>1539.175511</td>\n",
       "      <td>4.383122</td>\n",
       "      <td>1.345327</td>\n",
       "      <td>1970.988092</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2</td>\n",
       "      <td>3696</td>\n",
       "      <td>0.123200</td>\n",
       "      <td>86261.626226</td>\n",
       "      <td>10627.432351</td>\n",
       "      <td>267077.401658</td>\n",
       "      <td>2469.333784</td>\n",
       "      <td>2.594536</td>\n",
       "      <td>2.640249</td>\n",
       "      <td>2000.822288</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>3</td>\n",
       "      <td>3774</td>\n",
       "      <td>0.125800</td>\n",
       "      <td>76093.867828</td>\n",
       "      <td>9572.608573</td>\n",
       "      <td>261917.345621</td>\n",
       "      <td>2444.782666</td>\n",
       "      <td>2.598198</td>\n",
       "      <td>1.365492</td>\n",
       "      <td>1968.891333</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>5</td>\n",
       "      <td>3711</td>\n",
       "      <td>0.123700</td>\n",
       "      <td>-71996.624107</td>\n",
       "      <td>8905.982402</td>\n",
       "      <td>191311.210246</td>\n",
       "      <td>1594.221203</td>\n",
       "      <td>4.407337</td>\n",
       "      <td>2.663340</td>\n",
       "      <td>2002.108713</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   prototype_id  support_n  support_share_train  prototype_output_weight  impact_score  assigned_mean_target_train  num__squarefeet  num__bedrooms  num__bathrooms  num__yearbuilt cat__neighborhood\n",
       "0             7       3844             0.128133             95506.687148  12237.590180               272746.439862      2424.082249       4.416710        2.629099     1968.388860             Urban\n",
       "1             0       3761             0.125367            -96853.934599  12142.254934               175264.422465      1541.357333       2.579437        2.638151     1970.338735            Suburb\n",
       "2             1       3734             0.124467             96690.023035  12034.684867               272552.660643      2460.813487       4.418785        1.373829     2001.336098            Suburb\n",
       "3             4       3617             0.120567            -96452.147420  11628.913907               175220.763401      1580.509815       2.588609        1.359690     2002.136577             Rural\n",
       "4             6       3863             0.128767            -88722.805440  11424.539914               181692.435129      1539.175511       4.383122        1.345327     1970.988092             Rural\n",
       "5             2       3696             0.123200             86261.626226  10627.432351               267077.401658      2469.333784       2.594536        2.640249     2000.822288            Suburb\n",
       "6             3       3774             0.125800             76093.867828   9572.608573               261917.345621      2444.782666       2.598198        1.365492     1968.891333             Urban\n",
       "7             5       3711             0.123700            -71996.624107   8905.982402               191311.210246      1594.221203       4.407337        2.663340     2002.108713            Suburb"
      ]
     },
     "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>prototype_id</th>\n",
       "      <th>rank</th>\n",
       "      <th>feature</th>\n",
       "      <th>contribution_score</th>\n",
       "      <th>interpreted_value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>80619.041942</td>\n",
       "      <td>2.579437</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>78686.508983</td>\n",
       "      <td>1541.357333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>75406.220692</td>\n",
       "      <td>2.638151</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>70286.470265</td>\n",
       "      <td>1970.338735</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>467.942083</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>79061.972903</td>\n",
       "      <td>4.418785</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>76262.291351</td>\n",
       "      <td>2460.813487</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>74551.641471</td>\n",
       "      <td>2001.336098</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>74381.327576</td>\n",
       "      <td>1.373829</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>471.666369</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>70633.787011</td>\n",
       "      <td>2.594536</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>69317.000765</td>\n",
       "      <td>2469.333784</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>67381.067934</td>\n",
       "      <td>2.640249</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>64370.826728</td>\n",
       "      <td>2000.822288</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>2</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>1251.300681</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>62058.147331</td>\n",
       "      <td>2.598198</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>3</td>\n",
       "      <td>2</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>60539.106760</td>\n",
       "      <td>1968.891333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>59313.905693</td>\n",
       "      <td>1.365492</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>57893.233003</td>\n",
       "      <td>2444.782666</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>3</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Urban</td>\n",
       "      <td>1074.079835</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>79490.933995</td>\n",
       "      <td>2.588609</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>78096.277268</td>\n",
       "      <td>2002.136577</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>75867.866859</td>\n",
       "      <td>1.35969</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>71783.912704</td>\n",
       "      <td>1580.509815</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>4</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Rural</td>\n",
       "      <td>683.868925</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>58273.572012</td>\n",
       "      <td>2.66334</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>58198.033352</td>\n",
       "      <td>2002.108713</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>58131.177863</td>\n",
       "      <td>4.407337</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>5</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>51863.962661</td>\n",
       "      <td>1594.221203</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>743.438785</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>72417.678793</td>\n",
       "      <td>1539.175511</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>6</td>\n",
       "      <td>2</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>71348.145138</td>\n",
       "      <td>1.345327</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>6</td>\n",
       "      <td>3</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>69708.779520</td>\n",
       "      <td>4.383122</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>6</td>\n",
       "      <td>4</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>61603.866774</td>\n",
       "      <td>1970.988092</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Rural</td>\n",
       "      <td>1344.291752</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>78300.861004</td>\n",
       "      <td>1968.38886</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>7</td>\n",
       "      <td>2</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>77916.588383</td>\n",
       "      <td>4.41671</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>7</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>73298.986902</td>\n",
       "      <td>2.629099</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>7</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>69219.940212</td>\n",
       "      <td>2424.082249</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>39</th>\n",
       "      <td>7</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Urban</td>\n",
       "      <td>1426.920949</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    prototype_id  rank              feature  contribution_score interpreted_value\n",
       "0              0     1             bedrooms        80619.041942          2.579437\n",
       "1              0     2           squarefeet        78686.508983       1541.357333\n",
       "2              0     3            bathrooms        75406.220692          2.638151\n",
       "3              0     4            yearbuilt        70286.470265       1970.338735\n",
       "4              0     5  neighborhood=Suburb          467.942083            Suburb\n",
       "5              1     1             bedrooms        79061.972903          4.418785\n",
       "6              1     2           squarefeet        76262.291351       2460.813487\n",
       "7              1     3            yearbuilt        74551.641471       2001.336098\n",
       "8              1     4            bathrooms        74381.327576          1.373829\n",
       "9              1     5  neighborhood=Suburb          471.666369            Suburb\n",
       "10             2     1             bedrooms        70633.787011          2.594536\n",
       "11             2     2           squarefeet        69317.000765       2469.333784\n",
       "12             2     3            bathrooms        67381.067934          2.640249\n",
       "13             2     4            yearbuilt        64370.826728       2000.822288\n",
       "14             2     5  neighborhood=Suburb         1251.300681            Suburb\n",
       "15             3     1             bedrooms        62058.147331          2.598198\n",
       "16             3     2            yearbuilt        60539.106760       1968.891333\n",
       "17             3     3            bathrooms        59313.905693          1.365492\n",
       "18             3     4           squarefeet        57893.233003       2444.782666\n",
       "19             3     5   neighborhood=Urban         1074.079835             Urban\n",
       "20             4     1             bedrooms        79490.933995          2.588609\n",
       "21             4     2            yearbuilt        78096.277268       2002.136577\n",
       "22             4     3            bathrooms        75867.866859           1.35969\n",
       "23             4     4           squarefeet        71783.912704       1580.509815\n",
       "24             4     5   neighborhood=Rural          683.868925             Rural\n",
       "25             5     1            bathrooms        58273.572012           2.66334\n",
       "26             5     2            yearbuilt        58198.033352       2002.108713\n",
       "27             5     3             bedrooms        58131.177863          4.407337\n",
       "28             5     4           squarefeet        51863.962661       1594.221203\n",
       "29             5     5  neighborhood=Suburb          743.438785            Suburb\n",
       "30             6     1           squarefeet        72417.678793       1539.175511\n",
       "31             6     2            bathrooms        71348.145138          1.345327\n",
       "32             6     3             bedrooms        69708.779520          4.383122\n",
       "33             6     4            yearbuilt        61603.866774       1970.988092\n",
       "34             6     5   neighborhood=Rural         1344.291752             Rural\n",
       "35             7     1            yearbuilt        78300.861004        1968.38886\n",
       "36             7     2             bedrooms        77916.588383           4.41671\n",
       "37             7     3            bathrooms        73298.986902          2.629099\n",
       "38             7     4           squarefeet        69219.940212       2424.082249\n",
       "39             7     5   neighborhood=Urban         1426.920949             Urban"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQWFJREFUeJzt3XlYlPX+//HXKLKkAm6AHFEwS3HfCnFPCbdMyyzN0lw7HiiV0qQFt06YpeKWZovaSY+2aR0tFZc0FTeMMkMzw6UUqBAQNUGY3x99uX9OqOncU8Po83Fd93U5n8977vt933VO8/LeLFar1SoAAAAAMKGMsxsAAAAA4PoIFgAAAABMI1gAAAAAMI1gAQAAAMA0ggUAAAAA0wgWAAAAAEwjWAAAAAAwjWABAAAAwDSCBQAAAADTCBYAAAAATCNYAEApdOTIET3++OOqXbu2PD095e3trTZt2mjWrFk6f/68s9sDAKAEN2c3AACwtWbNGvXt21ceHh4aOHCgGjZsqPz8fG3btk1jx47VgQMHtHDhQme3CQCADYvVarU6uwkAwO/S0tLUuHFj1ahRQ5s2bVL16tVt5r///nutWbNGo0aNclKHAABcHpdCAUApMm3aNOXl5emtt94qESokqU6dOjahwmKxaOLEiTY1r7zyiiwWizp27Fji+4899pgsFkuJ5dJ1fP3113rssceMy7ACAgI0ZMgQ/frrr3/a/+eff37Z9Rcvjz32mFG7ePFiWSwWbd26VY8//riqVKkib29vDRw4UKdPny6x7tdee00NGjSQh4eHAgMDFRUVpezsbGO+Y8eOV922xWIxai9evKgpU6bo1ltvlYeHh4KDg/Xss8/qwoULRk1wcPBV1xUcHCxJOnr0qCwWixYvXmzTb1RU1BX3+UrLH/9Zfvnll+rWrZu8vb1VoUIFde7cWTt37rSp+eM6b7nlFjVq1Ehvvvnmn/7zAgBH4lIoAChF/ve//6l27dpq3bq1Xd/Pzs5WfHz8VWuqVq2qmTNnGp8fffRRm/nExET98MMPGjx4sAICAoxLrw4cOKCdO3fa/EC/kieffFJ33HGHzdiwYcMuWxsdHS1fX19NnDhRhw4d0vz583Xs2DEjpEjSxIkTNWnSJEVERGjkyJFG3Z49e7R9+3aVK1dOzz33nLGNX375RWPGjNGIESPUrl27EtscNmyYlixZogceeEBPPfWUdu3apfj4eKWmpmrlypWSpISEBOXl5UmSUlNT9dJLL+nZZ59VaGioJKlChQpX3P/vv/9eb7zxxhXnJ0+erJCQEONzXl6eRo4caVNz4MABtWvXTt7e3ho3bpzKlSun119/XR07dtSWLVsUFhZmUz9z5kxVrVpVubm5evvttzV8+HAFBwcrIiLiin0AgENZAQClQk5OjlWStVevXtf8HUnWCRMmGJ/HjRtn9fPzs7Zo0cLaoUOHEvUDBgywhoSEXHUd586dK/G9//73v1ZJ1q1bt161n82bN1slWd9///0Sc+XLl7cOGjTI+Lxo0SKrJGuLFi2s+fn5xvi0adOskqwff/yx1Wq1WjMzM63u7u7WyMhIa2FhoVE3d+5cqyTr22+/XWJbaWlpVknWRYsWlZhLSUmxSrIOGzbMZvzpp5+2SrJu2rTpivu1efPma9rWgw8+aG3YsKE1KCjosvu8Z88em3X8/PPPJf459O7d2+ru7m49cuSIMXby5ElrxYoVre3bty+xzrS0NGPsu+++s0qyTps2rUS/APBX4VIoACglcnNzJUkVK1a06/s//fST5syZoxdeeOGKf5uen58vDw+Pq67Hy8vL+PNvv/2mX375Ra1atZIk7du3z67ermbEiBEqV66c8XnkyJFyc3PTp59+KknasGGD8vPzNXr0aJUp8///szV8+HB5e3trzZo117W94vXGxMTYjD/11FOSdN3r+6Pk5GS9//77io+Pt+n3ehQWFmr9+vXq3bu3ateubYxXr15dDz/8sLZt22b8+1Ls9OnT+uWXX/TDDz9o5syZKlu2rDp06GBqXwDgehAsAKCU8Pb2liSdOXPGru9PmDBBgYGBevzxx69Yk52dfdVLeCQpKytLo0aNkr+/v7y8vFStWjXjsp2cnBy7erua2267zeZzhQoVVL16dR09elSSdOzYMUlS3bp1berc3d1Vu3ZtY/5aHTt2TGXKlFGdOnVsxgMCAuTr63vd6/uj8ePHq127drrnnnvsXsfPP/+sc+fOldhnSQoNDVVRUZFOnDhhM968eXNVq1ZNt956q95++23NnTtXd955p909AMD14h4LACglvL29FRgYqG+++ea6v5uamqrFixfr3Xfftfnb/z9KT09XrVq1rrquBx98UDt27NDYsWPVtGlTVahQQUVFReratauKioquu7fS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9/Hx0fr16xUVFaUWLVqoatWqiouLs3nXRevWrbVs2TI9//zzevbZZ3Xbbbdp1apVatiw4d9wFAAAAADX59Rg0bFjR1mt1ivOWywWTZ48WZMnT75iTeXKlbVs2bKrbqdx48b64osvrlrTt29f9e3b9+oNAwAAALisUnuPBQAAAADXQbAAAAAAYBrBAgAAAIBpBAsAAAAApjn15m0AAIAbWfD4Nc5uwemOTu3h7BbwN+GMBQAAAADTCBYAAAAATCNYAAAAADCNYAEAAADANIIFAAAAANMIFgAAAABMI1gAAAAAMI1gAQAAAMA0ggUAAAAA0wgWAAAAAEwjWAAAAAAwjWABAAAAwDSCBQAAAADTCBYAAAAATCNYAAAAADDNzdkNAAAAAFcSPH6Ns1twuqNTezi7hWvCGQsAAAAAphEsAAAAAJhGsAAAAABgGsECAAAAgGkECwAAAACmESwAAAAAmEawAAAAAGAawQIAAACAaQQLAAAAAKYRLAAAAACYRrAAAAAAYBrBAgAAAIBpBAsAAAAAphEsAAAAAJhGsAAAAABgmt3BIjs7W2+++aZiY2OVlZUlSdq3b59++uknhzUHAAAAwDXYFSy+/vpr3X777Xr55Zf16quvKjs7W5L00UcfKTY21mHNFRYW6oUXXlBISIi8vLx06623asqUKbJarUaN1WpVXFycqlevLi8vL0VEROjw4cM268nKytKAAQPk7e0tX19fDR06VHl5eSX2qV27dvL09FRQUJCmTZvmsP0AAAAAbnR2BYuYmBg99thjOnz4sDw9PY3x7t27a+vWrQ5r7uWXX9b8+fM1d+5cpaam6uWXX9a0adM0Z84co2batGmaPXu2FixYoF27dql8+fLq0qWLfvvtN6NmwIABOnDggBITE7V69Wpt3bpVI0aMMOZzc3MVGRmpWrVqKTk5Wa+88oomTpyohQsXOmxfAAAAgBuZmz1f2rNnj15//fUS4//4xz+Unp5uuqliO3bsUK9evdSjRw9JUnBwsP773/9q9+7dkn4/W5GQkKDnn39evXr1kiS988478vf316pVq9SvXz+lpqZq7dq12rNnj1q2bClJmjNnjrp3765XX31VgYGBWrp0qfLz8/X222/L3d1dDRo0UEpKimbMmGETQAAAAABcnl1nLDw8PJSbm1ti/LvvvlO1atVMN1WsdevW2rhxo777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",
      "text/plain": [
       "<Figure size 800x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Интерпретация прототипов\n",
    "\n",
    "num_pipe_fitted = preprocessor.named_transformers_[\"num\"]\n",
    "scaler = num_pipe_fitted.named_steps[\"scaler\"]\n",
    "\n",
    "if categorical_features:\n",
    "    ohe_fitted = preprocessor.named_transformers_[\"cat\"].named_steps[\"onehot\"]\n",
    "    cat_categories = ohe_fitted.categories_\n",
    "else:\n",
    "    ohe_fitted = None\n",
    "    cat_categories = []\n",
    "\n",
    "n_num = len(numeric_features)\n",
    "n_cat_proc = len(feature_names_processed) - n_num\n",
    "\n",
    "train_num_means = X_train[numeric_features].astype(float).mean() if numeric_features else pd.Series(dtype=float)\n",
    "train_num_stds = X_train[numeric_features].astype(float).std().replace(0, 1.0) if numeric_features else pd.Series(dtype=float)\n",
    "train_cat_freq = {c: X_train[c].astype(str).fillna(\"Missing\").value_counts(normalize=True).to_dict() for c in categorical_features}\n",
    "\n",
    "prototypes = best_model.prototypes_\n",
    "proto_weights = best_model.prototype_weights_\n",
    "train_assignments = best_model.kmeans_.predict(X_train_proc)\n",
    "\n",
    "prototype_rows = []\n",
    "prototype_feature_rows = []\n",
    "\n",
    "impact_scores = []\n",
    "\n",
    "for k in range(len(prototypes)):\n",
    "    center = prototypes[k]\n",
    "    beta = float(proto_weights[k])\n",
    "\n",
    "    support_n = int((train_assignments == k).sum())\n",
    "    support_share = support_n / len(train_assignments)\n",
    "    assigned_mask = (train_assignments == k)\n",
    "    assigned_mean_target = float(np.mean(y_train[assigned_mask])) if assigned_mask.any() else np.nan\n",
    "\n",
    "    numeric_values = {}\n",
    "    if n_num > 0:\n",
    "        num_center_scaled = center[:n_num].reshape(1, -1)\n",
    "        num_center_orig = scaler.inverse_transform(num_center_scaled).ravel()\n",
    "        numeric_values = dict(zip(numeric_features, num_center_orig))\n",
    "    else:\n",
    "        num_center_orig = np.array([])\n",
    "\n",
    "    dominant_cats = {}\n",
    "    cat_offset = n_num\n",
    "    cat_scores_local = []\n",
    "    for cat_idx, cat_col in enumerate(categorical_features):\n",
    "        cats = list(cat_categories[cat_idx])\n",
    "        block = center[cat_offset: cat_offset + len(cats)]\n",
    "        if len(block) == 0:\n",
    "            cat_offset += len(cats)\n",
    "            continue\n",
    "        top_j = int(np.argmax(block))\n",
    "        chosen_cat = str(cats[top_j])\n",
    "        dominant_cats[cat_col] = chosen_cat\n",
    "\n",
    "        global_freq = train_cat_freq.get(cat_col, {}).get(chosen_cat, 0.0)\n",
    "        contribution_score = abs(float(block[top_j]) - global_freq) * abs(beta)\n",
    "        cat_scores_local.append((f\"{cat_col}={chosen_cat}\", contribution_score, chosen_cat))\n",
    "        cat_offset += len(cats)\n",
    "\n",
    "    # Важность числовых признаков внутри прототипа\n",
    "    num_scores_local = []\n",
    "    for j, col in enumerate(numeric_features):\n",
    "        z = abs((num_center_orig[j] - train_num_means[col]) / train_num_stds[col])\n",
    "        contribution_score = float(z) * abs(beta)\n",
    "        num_scores_local.append((col, contribution_score, num_center_orig[j]))\n",
    "\n",
    "    all_scores_local = num_scores_local + cat_scores_local\n",
    "    all_scores_local = sorted(all_scores_local, key=lambda x: x[1], reverse=True)\n",
    "\n",
    "    impact = support_share * abs(beta)\n",
    "    impact_scores.append((k, impact))\n",
    "\n",
    "    row = {\n",
    "        \"prototype_id\": k,\n",
    "        \"support_n\": support_n,\n",
    "        \"support_share_train\": support_share,\n",
    "        \"prototype_output_weight\": beta,\n",
    "        \"impact_score\": impact,\n",
    "        \"assigned_mean_target_train\": assigned_mean_target,\n",
    "    }\n",
    "\n",
    "    # Добавляем несколько интерпретируемых признаков\n",
    "    for col in numeric_features[:4]:\n",
    "        row[f\"num__{col}\"] = numeric_values.get(col, np.nan)\n",
    "    for col in categorical_features[:3]:\n",
    "        row[f\"cat__{col}\"] = dominant_cats.get(col, None)\n",
    "\n",
    "    prototype_rows.append(row)\n",
    "\n",
    "    for rank, (fname, score, value) in enumerate(all_scores_local[:5], start=1):\n",
    "        prototype_feature_rows.append({\n",
    "            \"prototype_id\": k,\n",
    "            \"rank\": rank,\n",
    "            \"feature\": fname,\n",
    "            \"contribution_score\": score,\n",
    "            \"interpreted_value\": value,\n",
    "        })\n",
    "\n",
    "prototype_summary_df = pd.DataFrame(prototype_rows).sort_values([\"impact_score\", \"support_share_train\"], ascending=[False, False]).reset_index(drop=True)\n",
    "prototype_top_features_df = pd.DataFrame(prototype_feature_rows).sort_values([\"prototype_id\", \"rank\"]).reset_index(drop=True)\n",
    "\n",
    "print(\"Основные прототипы (по impact_score = support_share × |вес выхода|):\")\n",
    "display(prototype_summary_df)\n",
    "\n",
    "print(\"Топ-признаки внутри каждого прототипа:\")\n",
    "display(prototype_top_features_df)\n",
    "\n",
    "plt.figure(figsize=(8, 4))\n",
    "plt.bar(prototype_summary_df[\"prototype_id\"].astype(str), prototype_summary_df[\"impact_score\"])\n",
    "plt.title(\"Сила прототипов\")\n",
    "plt.xlabel(\"prototype_id\")\n",
    "plt.ylabel(\"impact_score\")\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "1917cb95",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\n",
      "Зависимая переменная: price\n",
      "\n",
      "Число исходных признаков: 5\n",
      "Число признаков после кодирования: 7\n",
      "Лучшая конфигурация прототипной сети:\n",
      "n_prototypes = 8\n",
      "alpha = 1.0\n",
      "sigma = 1.4106722300074301\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>split</th>\n",
       "      <th>r2</th>\n",
       "      <th>rmse</th>\n",
       "      <th>mae</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>train</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.396943</td>\n",
       "      <td>42622.246003</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>validation</td>\n",
       "      <td>0.512792</td>\n",
       "      <td>53050.567712</td>\n",
       "      <td>42496.273011</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>test</td>\n",
       "      <td>0.521061</td>\n",
       "      <td>52431.735115</td>\n",
       "      <td>41934.625581</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        split        r2          rmse           mae\n",
       "0       train  0.510170  53409.396943  42622.246003\n",
       "1  validation  0.512792  53050.567712  42496.273011\n",
       "2        test  0.521061  52431.735115  41934.625581"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Топ-10 конфигураций по validation RMSE:\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>n_prototypes</th>\n",
       "      <th>alpha</th>\n",
       "      <th>train_r2</th>\n",
       "      <th>train_rmse</th>\n",
       "      <th>train_mae</th>\n",
       "      <th>val_r2</th>\n",
       "      <th>val_rmse</th>\n",
       "      <th>val_mae</th>\n",
       "      <th>sigma</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>8</td>\n",
       "      <td>1.0000</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.396943</td>\n",
       "      <td>42622.246003</td>\n",
       "      <td>0.512792</td>\n",
       "      <td>53050.567712</td>\n",
       "      <td>42496.273011</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>8</td>\n",
       "      <td>0.1000</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382961</td>\n",
       "      <td>42622.409768</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.785337</td>\n",
       "      <td>42496.636716</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0100</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382822</td>\n",
       "      <td>42622.426438</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.808397</td>\n",
       "      <td>42496.674121</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0010</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382820</td>\n",
       "      <td>42622.428105</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.810716</td>\n",
       "      <td>42496.677861</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>0.0001</td>\n",
       "      <td>0.510170</td>\n",
       "      <td>53409.382820</td>\n",
       "      <td>42622.428272</td>\n",
       "      <td>0.512788</td>\n",
       "      <td>53050.810948</td>\n",
       "      <td>42496.678236</td>\n",
       "      <td>1.410672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>10</td>\n",
       "      <td>1.0000</td>\n",
       "      <td>0.508774</td>\n",
       "      <td>53485.439965</td>\n",
       "      <td>42675.452322</td>\n",
       "      <td>0.511822</td>\n",
       "      <td>53103.355012</td>\n",
       "      <td>42523.583938</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>10</td>\n",
       "      <td>0.1000</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424887</td>\n",
       "      <td>42675.636545</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.553508</td>\n",
       "      <td>42523.824404</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0100</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424736</td>\n",
       "      <td>42675.655797</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.574743</td>\n",
       "      <td>42523.848507</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0010</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424734</td>\n",
       "      <td>42675.657723</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.576880</td>\n",
       "      <td>42523.850918</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>10</td>\n",
       "      <td>0.0001</td>\n",
       "      <td>0.508775</td>\n",
       "      <td>53485.424734</td>\n",
       "      <td>42675.657915</td>\n",
       "      <td>0.511818</td>\n",
       "      <td>53103.577094</td>\n",
       "      <td>42523.851159</td>\n",
       "      <td>1.364013</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   n_prototypes   alpha  train_r2    train_rmse     train_mae    val_r2      val_rmse       val_mae     sigma\n",
       "0             8  1.0000  0.510170  53409.396943  42622.246003  0.512792  53050.567712  42496.273011  1.410672\n",
       "1             8  0.1000  0.510170  53409.382961  42622.409768  0.512788  53050.785337  42496.636716  1.410672\n",
       "2             8  0.0100  0.510170  53409.382822  42622.426438  0.512788  53050.808397  42496.674121  1.410672\n",
       "3             8  0.0010  0.510170  53409.382820  42622.428105  0.512788  53050.810716  42496.677861  1.410672\n",
       "4             8  0.0001  0.510170  53409.382820  42622.428272  0.512788  53050.810948  42496.678236  1.410672\n",
       "5            10  1.0000  0.508774  53485.439965  42675.452322  0.511822  53103.355012  42523.583938  1.364013\n",
       "6            10  0.1000  0.508775  53485.424887  42675.636545  0.511818  53103.553508  42523.824404  1.364013\n",
       "7            10  0.0100  0.508775  53485.424736  42675.655797  0.511818  53103.574743  42523.848507  1.364013\n",
       "8            10  0.0010  0.508775  53485.424734  42675.657723  0.511818  53103.576880  42523.850918  1.364013\n",
       "9            10  0.0001  0.508775  53485.424734  42675.657915  0.511818  53103.577094  42523.851159  1.364013"
      ]
     },
     "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>prototype_id</th>\n",
       "      <th>support_n</th>\n",
       "      <th>support_share_train</th>\n",
       "      <th>prototype_output_weight</th>\n",
       "      <th>impact_score</th>\n",
       "      <th>assigned_mean_target_train</th>\n",
       "      <th>num__squarefeet</th>\n",
       "      <th>num__bedrooms</th>\n",
       "      <th>num__bathrooms</th>\n",
       "      <th>num__yearbuilt</th>\n",
       "      <th>cat__neighborhood</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>7</td>\n",
       "      <td>3844</td>\n",
       "      <td>0.128133</td>\n",
       "      <td>95506.687148</td>\n",
       "      <td>12237.590180</td>\n",
       "      <td>272746.439862</td>\n",
       "      <td>2424.082249</td>\n",
       "      <td>4.416710</td>\n",
       "      <td>2.629099</td>\n",
       "      <td>1968.388860</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>3761</td>\n",
       "      <td>0.125367</td>\n",
       "      <td>-96853.934599</td>\n",
       "      <td>12142.254934</td>\n",
       "      <td>175264.422465</td>\n",
       "      <td>1541.357333</td>\n",
       "      <td>2.579437</td>\n",
       "      <td>2.638151</td>\n",
       "      <td>1970.338735</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>3734</td>\n",
       "      <td>0.124467</td>\n",
       "      <td>96690.023035</td>\n",
       "      <td>12034.684867</td>\n",
       "      <td>272552.660643</td>\n",
       "      <td>2460.813487</td>\n",
       "      <td>4.418785</td>\n",
       "      <td>1.373829</td>\n",
       "      <td>2001.336098</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>3617</td>\n",
       "      <td>0.120567</td>\n",
       "      <td>-96452.147420</td>\n",
       "      <td>11628.913907</td>\n",
       "      <td>175220.763401</td>\n",
       "      <td>1580.509815</td>\n",
       "      <td>2.588609</td>\n",
       "      <td>1.359690</td>\n",
       "      <td>2002.136577</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6</td>\n",
       "      <td>3863</td>\n",
       "      <td>0.128767</td>\n",
       "      <td>-88722.805440</td>\n",
       "      <td>11424.539914</td>\n",
       "      <td>181692.435129</td>\n",
       "      <td>1539.175511</td>\n",
       "      <td>4.383122</td>\n",
       "      <td>1.345327</td>\n",
       "      <td>1970.988092</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2</td>\n",
       "      <td>3696</td>\n",
       "      <td>0.123200</td>\n",
       "      <td>86261.626226</td>\n",
       "      <td>10627.432351</td>\n",
       "      <td>267077.401658</td>\n",
       "      <td>2469.333784</td>\n",
       "      <td>2.594536</td>\n",
       "      <td>2.640249</td>\n",
       "      <td>2000.822288</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>3</td>\n",
       "      <td>3774</td>\n",
       "      <td>0.125800</td>\n",
       "      <td>76093.867828</td>\n",
       "      <td>9572.608573</td>\n",
       "      <td>261917.345621</td>\n",
       "      <td>2444.782666</td>\n",
       "      <td>2.598198</td>\n",
       "      <td>1.365492</td>\n",
       "      <td>1968.891333</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>5</td>\n",
       "      <td>3711</td>\n",
       "      <td>0.123700</td>\n",
       "      <td>-71996.624107</td>\n",
       "      <td>8905.982402</td>\n",
       "      <td>191311.210246</td>\n",
       "      <td>1594.221203</td>\n",
       "      <td>4.407337</td>\n",
       "      <td>2.663340</td>\n",
       "      <td>2002.108713</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   prototype_id  support_n  support_share_train  prototype_output_weight  impact_score  assigned_mean_target_train  num__squarefeet  num__bedrooms  num__bathrooms  num__yearbuilt cat__neighborhood\n",
       "0             7       3844             0.128133             95506.687148  12237.590180               272746.439862      2424.082249       4.416710        2.629099     1968.388860             Urban\n",
       "1             0       3761             0.125367            -96853.934599  12142.254934               175264.422465      1541.357333       2.579437        2.638151     1970.338735            Suburb\n",
       "2             1       3734             0.124467             96690.023035  12034.684867               272552.660643      2460.813487       4.418785        1.373829     2001.336098            Suburb\n",
       "3             4       3617             0.120567            -96452.147420  11628.913907               175220.763401      1580.509815       2.588609        1.359690     2002.136577             Rural\n",
       "4             6       3863             0.128767            -88722.805440  11424.539914               181692.435129      1539.175511       4.383122        1.345327     1970.988092             Rural\n",
       "5             2       3696             0.123200             86261.626226  10627.432351               267077.401658      2469.333784       2.594536        2.640249     2000.822288            Suburb\n",
       "6             3       3774             0.125800             76093.867828   9572.608573               261917.345621      2444.782666       2.598198        1.365492     1968.891333             Urban\n",
       "7             5       3711             0.123700            -71996.624107   8905.982402               191311.210246      1594.221203       4.407337        2.663340     2002.108713            Suburb"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Топ-5 вкладов признаков для основных прототипов:\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>prototype_id</th>\n",
       "      <th>rank</th>\n",
       "      <th>feature</th>\n",
       "      <th>contribution_score</th>\n",
       "      <th>interpreted_value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>80619.041942</td>\n",
       "      <td>2.579437</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>78686.508983</td>\n",
       "      <td>1541.357333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>75406.220692</td>\n",
       "      <td>2.638151</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>70286.470265</td>\n",
       "      <td>1970.338735</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>467.942083</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>79061.972903</td>\n",
       "      <td>4.418785</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>76262.291351</td>\n",
       "      <td>2460.813487</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>74551.641471</td>\n",
       "      <td>2001.336098</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>74381.327576</td>\n",
       "      <td>1.373829</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Suburb</td>\n",
       "      <td>471.666369</td>\n",
       "      <td>Suburb</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>79490.933995</td>\n",
       "      <td>2.588609</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>78096.277268</td>\n",
       "      <td>2002.136577</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>75867.866859</td>\n",
       "      <td>1.35969</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>4</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>71783.912704</td>\n",
       "      <td>1580.509815</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>4</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Rural</td>\n",
       "      <td>683.868925</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>72417.678793</td>\n",
       "      <td>1539.175511</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>6</td>\n",
       "      <td>2</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>71348.145138</td>\n",
       "      <td>1.345327</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>6</td>\n",
       "      <td>3</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>69708.779520</td>\n",
       "      <td>4.383122</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>6</td>\n",
       "      <td>4</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>61603.866774</td>\n",
       "      <td>1970.988092</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Rural</td>\n",
       "      <td>1344.291752</td>\n",
       "      <td>Rural</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>yearbuilt</td>\n",
       "      <td>78300.861004</td>\n",
       "      <td>1968.38886</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>7</td>\n",
       "      <td>2</td>\n",
       "      <td>bedrooms</td>\n",
       "      <td>77916.588383</td>\n",
       "      <td>4.41671</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>7</td>\n",
       "      <td>3</td>\n",
       "      <td>bathrooms</td>\n",
       "      <td>73298.986902</td>\n",
       "      <td>2.629099</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>7</td>\n",
       "      <td>4</td>\n",
       "      <td>squarefeet</td>\n",
       "      <td>69219.940212</td>\n",
       "      <td>2424.082249</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>39</th>\n",
       "      <td>7</td>\n",
       "      <td>5</td>\n",
       "      <td>neighborhood=Urban</td>\n",
       "      <td>1426.920949</td>\n",
       "      <td>Urban</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    prototype_id  rank              feature  contribution_score interpreted_value\n",
       "0              0     1             bedrooms        80619.041942          2.579437\n",
       "1              0     2           squarefeet        78686.508983       1541.357333\n",
       "2              0     3            bathrooms        75406.220692          2.638151\n",
       "3              0     4            yearbuilt        70286.470265       1970.338735\n",
       "4              0     5  neighborhood=Suburb          467.942083            Suburb\n",
       "5              1     1             bedrooms        79061.972903          4.418785\n",
       "6              1     2           squarefeet        76262.291351       2460.813487\n",
       "7              1     3            yearbuilt        74551.641471       2001.336098\n",
       "8              1     4            bathrooms        74381.327576          1.373829\n",
       "9              1     5  neighborhood=Suburb          471.666369            Suburb\n",
       "20             4     1             bedrooms        79490.933995          2.588609\n",
       "21             4     2            yearbuilt        78096.277268       2002.136577\n",
       "22             4     3            bathrooms        75867.866859           1.35969\n",
       "23             4     4           squarefeet        71783.912704       1580.509815\n",
       "24             4     5   neighborhood=Rural          683.868925             Rural\n",
       "30             6     1           squarefeet        72417.678793       1539.175511\n",
       "31             6     2            bathrooms        71348.145138          1.345327\n",
       "32             6     3             bedrooms        69708.779520          4.383122\n",
       "33             6     4            yearbuilt        61603.866774       1970.988092\n",
       "34             6     5   neighborhood=Rural         1344.291752             Rural\n",
       "35             7     1            yearbuilt        78300.861004        1968.38886\n",
       "36             7     2             bedrooms        77916.588383           4.41671\n",
       "37             7     3            bathrooms        73298.986902          2.629099\n",
       "38             7     4           squarefeet        69219.940212       2424.082249\n",
       "39             7     5   neighborhood=Urban         1426.920949             Urban"
      ]
     },
     "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</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>170835.035713</td>\n",
       "      <td>208189.809824</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>126913.469998</td>\n",
       "      <td>187521.135570</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>246611.883092</td>\n",
       "      <td>269935.842537</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>244250.462969</td>\n",
       "      <td>270102.333733</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>271127.650112</td>\n",
       "      <td>265637.877925</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>189289.951199</td>\n",
       "      <td>189107.502703</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>343510.576500</td>\n",
       "      <td>276873.696031</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>203461.591080</td>\n",
       "      <td>185461.893451</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>285903.247682</td>\n",
       "      <td>278803.162808</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>224868.958375</td>\n",
       "      <td>224449.420520</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          y_true         y_pred\n",
       "0  170835.035713  208189.809824\n",
       "1  126913.469998  187521.135570\n",
       "2  246611.883092  269935.842537\n",
       "3  244250.462969  270102.333733\n",
       "4  271127.650112  265637.877925\n",
       "5  189289.951199  189107.502703\n",
       "6  343510.576500  276873.696031\n",
       "7  203461.591080  185461.893451\n",
       "8  285903.247682  278803.162808\n",
       "9  224868.958375  224449.420520"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print(\"=== КЛЮЧЕВАЯ ИНФОРМАЦИЯ ДЛЯ ВЫВОДА ===\")\n",
    "print(\"Зависимая переменная:\", target_col)\n",
    "print()\n",
    "print(\"Число исходных признаков:\", X.shape[1])\n",
    "print(\"Число признаков после кодирования:\", X_train_proc.shape[1])\n",
    "print(\"Лучшая конфигурация прототипной сети:\")\n",
    "print(\"n_prototypes =\", best_n_prototypes)\n",
    "print(\"alpha =\", best_alpha)\n",
    "print(\"sigma =\", best_model.sigma_)\n",
    "print()\n",
    "\n",
    "print(\"Метрики модели:\")\n",
    "display(metrics_df)\n",
    "\n",
    "print(\"Топ-10 конфигураций по validation RMSE:\")\n",
    "display(search_df.head(10))\n",
    "\n",
    "print(\"Основные прототипы:\")\n",
    "display(prototype_summary_df.head(10))\n",
    "\n",
    "print(\"Топ-5 вкладов признаков для основных прототипов:\")\n",
    "top_proto_ids = prototype_summary_df[\"prototype_id\"].head(5).tolist()\n",
    "display(prototype_top_features_df[prototype_top_features_df[\"prototype_id\"].isin(top_proto_ids)].copy())\n",
    "\n",
    "print(\"Первые 10 фактических и предсказанных значений на тесте:\")\n",
    "display(comparison_df.head(10))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6504550",
   "metadata": {},
   "source": [
    "Итог\n",
    "\n",
    "Зависимой переменной выбрана price. Лучшая прототипная сеть использует 8 прототипов (alpha = 1.0, sigma ≈ 1.41) и показывает на тесте R² = 0.521, RMSE ≈ 52432, MAE ≈ 41935.\n",
    "\n",
    "Основные прототипы соответствуют типичным сегментам объектов: более дорогие дома с большой площадью, большим числом комнат и расположением в Urban/Suburb, и менее дорогие объекты с меньшей площадью и Rural/Suburb-локацией.\n",
    "\n",
    "Наибольший вклад в прототипах дают признаки squarefeet, bedrooms, bathrooms, yearbuilt; категориальный признак neighborhood также участвует, но его вклад заметно ниже.\n",
    "\n",
    "Следовательно, прототипная сеть выделяет интерпретируемые группы жилья, а ключевыми факторами цены являются площадь, число спален/ванных, год постройки и тип района."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
