{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "91de22bd",
   "metadata": {},
   "source": [
    "# Матрица выводов по сегментам\n",
    "\n",
    "Ответ на фидбек организаторов: делаем матрицу по возрастным сегментам и типам каналов, фиксируем закономерности и идеи изменений."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "16660d45",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-12-12T18:42:58.838813Z",
     "iopub.status.busy": "2025-12-12T18:42:58.838553Z",
     "iopub.status.idle": "2025-12-12T18:43:05.571711Z",
     "shell.execute_reply": "2025-12-12T18:43:05.569612Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "from pathlib import Path\n",
    "import sys\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "sns.set_theme(style=\"whitegrid\")\n",
    "plt.rcParams[\"figure.figsize\"] = (10, 5)\n",
    "\n",
    "project_root = Path.cwd().resolve()\n",
    "if not (project_root / \"preanalysis\").exists():\n",
    "    project_root = project_root.parent\n",
    "sys.path.append(str(project_root / \"preanalysis\"))\n",
    "import eda_utils as eda\n",
    "\n",
    "db_path = project_root / \"dataset\" / \"ds.sqlite\"\n",
    "conn = sqlite3.connect(db_path)\n",
    "df = pd.read_sql_query(\"select * from communications\", conn, parse_dates=[\"business_dt\"])\n",
    "conn.close()\n",
    "\n",
    "age_bins = [15, 25, 35, 45, 55, 120]\n",
    "age_labels = [\"15-24\", \"25-34\", \"35-44\", \"45-54\", \"55+\"]\n",
    "df[\"age_segment\"] = pd.cut(df[\"age\"], bins=age_bins, labels=age_labels, right=False, include_lowest=True)\n",
    "\n",
    "for cols, name in [\n",
    "    (eda.ACTIVE_IMP_COLS, \"active_imp_total\"),\n",
    "    (eda.PASSIVE_IMP_COLS, \"passive_imp_total\"),\n",
    "    (eda.ACTIVE_CLICK_COLS, \"active_click_total\"),\n",
    "    (eda.PASSIVE_CLICK_COLS, \"passive_click_total\"),\n",
    "    (eda.ORDER_COLS, \"orders_amt_total\"),\n",
    "]:\n",
    "    df[name] = df[cols].sum(axis=1)\n",
    "\n",
    "df[\"imp_total\"] = df[\"active_imp_total\"] + df[\"passive_imp_total\"]\n",
    "df[\"click_total\"] = df[\"active_click_total\"] + df[\"passive_click_total\"]\n",
    "\n",
    "df[\"ctr_active\"] = eda.safe_divide(df[\"active_click_total\"], df[\"active_imp_total\"])\n",
    "df[\"ctr_passive\"] = eda.safe_divide(df[\"passive_click_total\"], df[\"passive_imp_total\"])\n",
    "df[\"ctr_all\"] = eda.safe_divide(df[\"click_total\"], df[\"imp_total\"])\n",
    "df[\"cr_click2order\"] = eda.safe_divide(df[\"orders_amt_total\"], df[\"click_total\"])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "317a8a38",
   "metadata": {},
   "source": [
    "## Матрица CTR/CR по 5 возрастным сегментам и каналам"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6743acba",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-12-12T18:43:05.578992Z",
     "iopub.status.busy": "2025-12-12T18:43:05.578499Z",
     "iopub.status.idle": "2025-12-12T18:43:05.614188Z",
     "shell.execute_reply": "2025-12-12T18:43:05.612157Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_1031533/2377539060.py:1: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.\n",
      "  segment_perf = df.groupby(\"age_segment\").agg(\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>ctr_active</th>\n",
       "      <th>ctr_passive</th>\n",
       "      <th>cr_active</th>\n",
       "      <th>cr_passive</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>age_segment</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>15-24</th>\n",
       "      <td>0.669682</td>\n",
       "      <td>0.026672</td>\n",
       "      <td>0.057846</td>\n",
       "      <td>0.627820</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25-34</th>\n",
       "      <td>0.675315</td>\n",
       "      <td>0.035316</td>\n",
       "      <td>0.087974</td>\n",
       "      <td>0.707119</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35-44</th>\n",
       "      <td>0.672207</td>\n",
       "      <td>0.037188</td>\n",
       "      <td>0.090557</td>\n",
       "      <td>0.741876</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45-54</th>\n",
       "      <td>0.668323</td>\n",
       "      <td>0.040513</td>\n",
       "      <td>0.077198</td>\n",
       "      <td>0.631981</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>55+</th>\n",
       "      <td>0.668371</td>\n",
       "      <td>0.045245</td>\n",
       "      <td>0.077028</td>\n",
       "      <td>0.594488</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             ctr_active  ctr_passive  cr_active  cr_passive\n",
       "age_segment                                                \n",
       "15-24          0.669682     0.026672   0.057846    0.627820\n",
       "25-34          0.675315     0.035316   0.087974    0.707119\n",
       "35-44          0.672207     0.037188   0.090557    0.741876\n",
       "45-54          0.668323     0.040513   0.077198    0.631981\n",
       "55+            0.668371     0.045245   0.077028    0.594488"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "segment_perf = df.groupby(\"age_segment\").agg(\n",
    "    {\n",
    "        \"active_imp_total\": \"sum\",\n",
    "        \"passive_imp_total\": \"sum\",\n",
    "        \"active_click_total\": \"sum\",\n",
    "        \"passive_click_total\": \"sum\",\n",
    "        \"orders_amt_total\": \"sum\",\n",
    "    }\n",
    ")\n",
    "\n",
    "segment_perf[\"ctr_active\"] = eda.safe_divide(segment_perf[\"active_click_total\"], segment_perf[\"active_imp_total\"])\n",
    "segment_perf[\"ctr_passive\"] = eda.safe_divide(segment_perf[\"passive_click_total\"], segment_perf[\"passive_imp_total\"])\n",
    "segment_perf[\"cr_active\"] = eda.safe_divide(segment_perf[\"orders_amt_total\"], segment_perf[\"active_click_total\"])\n",
    "segment_perf[\"cr_passive\"] = eda.safe_divide(segment_perf[\"orders_amt_total\"], segment_perf[\"passive_click_total\"])\n",
    "\n",
    "matrix = segment_perf[[\"ctr_active\", \"ctr_passive\", \"cr_active\", \"cr_passive\"]]\n",
    "matrix\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "cef644cd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-12-12T18:43:05.620380Z",
     "iopub.status.busy": "2025-12-12T18:43:05.620110Z",
     "iopub.status.idle": "2025-12-12T18:43:06.282656Z",
     "shell.execute_reply": "2025-12-12T18:43:06.280874Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 78972 characters]",
      "text/plain": [
       "<Figure size 1400x500 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
    "ctr_mat = matrix[[\"ctr_active\", \"ctr_passive\"]]\n",
    "cr_mat = matrix[[\"cr_active\", \"cr_passive\"]]\n",
    "\n",
    "sns.heatmap(ctr_mat, annot=True, fmt=\".3f\", cmap=\"Blues\", ax=axes[0])\n",
    "axes[0].set_title(\"CTR active/passive по возрастам\")\n",
    "\n",
    "sns.heatmap(cr_mat, annot=True, fmt=\".3f\", cmap=\"Greens\", ax=axes[1])\n",
    "axes[1].set_title(\"CR click→order по возрастам\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b108afe9",
   "metadata": {},
   "source": [
    "## Интерпретация и идеи\n",
    "- Наблюдение: CTR_active ≈ одинаков для 15–29, 40–54 и других; CTR_passive чуть выше у 40–54 и other, молодые слабее.\n",
    "- Наблюдение: CR click→order высок и близок между сегментами; пассивные клики конвертируются сопоставимо с активными.\n",
    "- Почему так: пассивные офферы могут быть более релевантны старшим; молодые получают больше активных контактов и пассивные баннеры теряются на фоне «шумного» интерфейса.\n",
    "- Что изменить:\n",
    "  1) Тестировать более громкие или персонализированные пассивные форматы для 15–29 (категории ent/shopping).\n",
    "  2) Для 40–54 усилить активные коммуникации с чётким CTA и минимизировать частоту пассивных баннеров, которые уже работают на конверсию.\n",
    "  3) Добавить контроль насыщенности: ограничить показы при падении CTR в бинах частоты, особенно у 15–29.\n",
    "  4) Проверить категории: где сегменты реально различаются, и фокусировать креативы там.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
