{ "cells": [ { "cell_type": "markdown", "id": "2b3d1ae8", "metadata": {}, "source": [ "# 00 — Resultados ejecutados (vía Metabase, sin ADC)\n", "\n", "Resultados de la ejecución del script `run_via_metabase.py` (BigQuery `autingo-159109.psql_dcpublic`).\n", "\n", "Ventana: 90 días Q0, 60 días para detectar regeneración.\n", "Centros call_center excluidos del cómputo: 159 (CALL CENTER AURGI), 162 (CALL CENTER)." ] }, { "cell_type": "code", "execution_count": 1, "id": "c39f6e2c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'window_days': 90,\n", " 'A_quote_cc_eur': 6392965.08,\n", " 'B_mismo_cliente_eur': 6923203.81,\n", " 'C_total_centros_eur': 29635811.36,\n", " 'A_sobre_C': 0.2157,\n", " 'B_sobre_C': 0.2336,\n", " 'lift_B_vs_A': 1.08,\n", " 'centros_activos': 139}" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import json\n", "from pathlib import Path\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "BASE = Path('../data/results').resolve()\n", "\n", "def load(name):\n", " return pd.read_csv(BASE / f'{name}.csv')\n", "\n", "totales = json.loads((BASE / 'totales_globales.json').read_text())\n", "totales" ] }, { "cell_type": "markdown", "id": "33adaf14", "metadata": {}, "source": [ "## Q1 — Tasa de conversión por origen del usuario que generó la quote" ] }, { "cell_type": "code", "execution_count": null, "id": "24471a70", "metadata": {}, "outputs": [], "source": [ "load('01_conversion_origen')" ] }, { "cell_type": "markdown", "id": "5847ffda", "metadata": {}, "source": [ "**Lectura:** \n", "- Call center genera 62.8K quotes / 90d, convierte 47.1% (29.6K facturas con mismo `order_id`).\n", "- Otros usuarios generan 477K quotes / 90d, convierten 57.4% (273.8K facturas).\n", "- Brecha de ~10pp es esperable: el call_center genera quote en frío (cliente no presente), el TPV de centro genera quote casi siempre con el cliente ya en mostrador." ] }, { "cell_type": "markdown", "id": "3484eeb6", "metadata": {}, "source": [ "## Q2 — 3 KPI por centro\n", "\n", "- **A** = € facturados desde quotes creados por call_center (mismo order_id).\n", "- **B** = € facturados a los mismos clientes (`customer_id` + `vehicle_id`) en centros físicos NO call_center.\n", "- **C** = € facturados totales del centro (todos los clientes).\n", "- `lift_B_vs_A`: 1.0 = solo factura el quote inicial; >1 = el centro factura más al cliente que sólo el quote." ] }, { "cell_type": "code", "execution_count": null, "id": "f2bc0458", "metadata": {}, "outputs": [], "source": [ "df = load('02_kpi_3_por_centro')\n", "df.head(15)" ] }, { "cell_type": "code", "execution_count": null, "id": "201ac95f", "metadata": {}, "outputs": [], "source": [ "# Top 15 centros por valor A (más facturado vía call_center)\n", "top = df.sort_values('A_quote_cc_eur', ascending=False).head(15).iloc[::-1]\n", "fig, ax = plt.subplots(figsize=(10, 7))\n", "y = range(len(top))\n", "ax.barh(y, top.A_quote_cc_eur, label='A (cc -> factura)')\n", "ax.barh(y, (top.B_mismo_cliente_eur - top.A_quote_cc_eur).clip(lower=0),\n", " left=top.A_quote_cc_eur, label='B-A (mismo cliente extra)')\n", "ax.set_yticks(list(y)); ax.set_yticklabels(top.center_name)\n", "ax.set_xlabel('€ facturados (90d)')\n", "ax.legend(); ax.set_title('Top 15 centros — quotes call_center -> factura')\n", "plt.tight_layout(); plt.show()" ] }, { "cell_type": "code", "execution_count": null, "id": "291fa4af", "metadata": {}, "outputs": [], "source": [ "print('TOTALES 90d (excluye centros call_center 159/162):')\n", "for k, v in totales.items():\n", " print(f' {k:25} {v}')" ] }, { "cell_type": "markdown", "id": "3d161868", "metadata": {}, "source": [ "## Q3 — Centros que MÁS regeneran el presupuesto\n", "\n", "Definición operativa: para un par `(customer_id, vehicle_id)` cuyo primer presupuesto (Q0) lo abrió el call_center, hay un Q1+ posterior con **distinto `order_id`** abierto en un terminal del centro físico dentro de 60 días." ] }, { "cell_type": "code", "execution_count": null, "id": "7831e9fe", "metadata": {}, "outputs": [], "source": [ "regen = load('03_regen_por_centro')\n", "regen" ] }, { "cell_type": "code", "execution_count": null, "id": "83758dc9", "metadata": {}, "outputs": [], "source": [ "top_regen = regen.head(15).iloc[::-1]\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "y = range(len(top_regen))\n", "ax.barh(y, top_regen.q0_regenerados_aqui)\n", "ax.set_yticks(list(y)); ax.set_yticklabels(top_regen.center_name)\n", "ax.set_xlabel('# Q0 (de call_center) regenerados en este centro')\n", "ax.set_title('Top centros regeneradores de presupuesto call_center (90d Q0, 60d window)')\n", "plt.tight_layout(); plt.show()" ] }, { "cell_type": "markdown", "id": "b0f6c55c", "metadata": {}, "source": [ "## Q4 — ¿Regenerar perjudica la conversión propia del Q0?\n", "\n", "Conversión del Q0 = el invoice se genera contra el MISMO order_id del Q0 (no contra el order_id regenerado en centro). Si regeneran, ese flujo cae." ] }, { "cell_type": "code", "execution_count": null, "id": "423b68cd", "metadata": {}, "outputs": [], "source": [ "load('04_regen_vs_conversion')" ] }, { "cell_type": "markdown", "id": "4956e2d1", "metadata": {}, "source": [ "**Lectura:**\n", "- 35.5K Q0 sin regeneración convierten al **63.1%** (sobre el order_id original).\n", "- 18.5K Q0 con regeneración convierten al **38.7%** sobre el order_id original.\n", "- Los 'regenerados' no se 'pierden' necesariamente — el cliente puede haberse facturado vía un order_id distinto (el del centro). Esa parte está capturada en el KPI **B** del cuadro anterior.\n", "- Aprox **34.2% de los Q0 call_center** entran en patrón de regeneración (18488 / 53995)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12" } }, "nbformat": 4, "nbformat_minor": 5 }