{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Case Contabilizei — Análise Completa\n",
    "**Mercado de Abertura de Empresas no Brasil · Projeção 2026 · Market Share · Estratégia de Aquisição**\n",
    "\n",
    "Este notebook consolida toda a análise do case em uma única peça reproduzível. Estrutura:\n",
    "\n",
    "1. **Setup** — imports, paths, config visual\n",
    "2. **EDA** — exploração dos dados, sazonalidade, crescimento por cidade/setor\n",
    "3. **P1 — Projeção 2026** — Holt-Winters + SARIMA, hold-out, intervalos de confiança\n",
    "4. **P2 — Diagnóstico de incerteza** — MAPE por (cidade × setor), matriz erro × volume\n",
    "5. **P3 — Meta de market share** — 20% sob 5 cenários, distribuição mensal\n",
    "6. **P4 — Matriz de oportunidade** — quadrantes setoriais, cluster Saúde, cidades\n",
    "7. **Síntese executiva** — três takeaways\n",
    "\n",
    "> Roda em ~30 segundos. Requer: `pandas`, `numpy`, `matplotlib`, `statsmodels`, `openpyxl`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json, warnings\n",
    "from pathlib import Path\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.ticker as mticker\n",
    "from statsmodels.tsa.holtwinters import ExponentialSmoothing\n",
    "from statsmodels.tsa.statespace.sarimax import SARIMAX\n",
    "from statsmodels.tsa.seasonal import STL\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "ROOT = Path(\"/home/pedro/repo/Cont\")\n",
    "DATA = ROOT / \"Case\" / \"Dados_Case_2026.xlsx\"\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"figure.dpi\": 110, \"figure.figsize\": (11, 5),\n",
    "    \"axes.spines.top\": False, \"axes.spines.right\": False,\n",
    "    \"axes.grid\": True, \"grid.alpha\": 0.25, \"font.size\": 10,\n",
    "})\n",
    "PALETA = {\"azul\":\"#1f3a68\", \"azul2\":\"#2c4f8a\", \"gold\":\"#d8a13a\",\n",
    "          \"verde\":\"#5b8c5a\", \"cinza\":\"#9aa6b8\", \"vermelho\":\"#aa3333\"}\n",
    "print(\"setup ok\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. EDA — entendendo a base\n",
    "\n",
    "Antes de modelar, três perguntas guiam a exploração:\n",
    "\n",
    "1. **Qual é o universo do dataset?** É o Brasil inteiro ou um recorte?\n",
    "2. **Existe sazonalidade clara?** Se sim, qual é o pico?\n",
    "3. **Onde está o crescimento?** Por setor e por cidade.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_excel(DATA, sheet_name=\"Extração 1\")\n",
    "df.columns = [c.strip() for c in df.columns]\n",
    "df[\"date\"] = pd.to_datetime(dict(year=df[\"ano\"], month=df[\"mes\"], day=1))\n",
    "df = df.rename(columns={\"cidade_agrupada\": \"cidade\",\n",
    "                        \"class_segmentos\": \"setor\",\n",
    "                        \"abertura_empresas\": \"vol\"})\n",
    "df[\"vol\"] = df[\"vol\"].fillna(0).astype(int)\n",
    "print(f\"linhas: {len(df):,} | período: {df.date.min():%Y-%m} a {df.date.max():%Y-%m}\")\n",
    "print(f\"cidades ({df.cidade.nunique()}): {sorted(df.cidade.unique())}\")\n",
    "print(f\"setores ({df.setor.nunique()}): {sorted(df.setor.unique())[:5]}... +{df.setor.nunique()-5}\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Premissa-zero:** os 30 setores são todos prestadores de serviço profissional. Não há comércio, indústria ou MEI. Isso confirma que o dataset representa o **ICP atendido pela Contabilizei** — não o universo total de aberturas no Brasil. Este recorte é determinante para a P3 (cálculo de market share)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Total anual\n",
    "annual = df.groupby(\"ano\", as_index=False)[\"vol\"].sum()\n",
    "annual[\"growth\"] = annual[\"vol\"].pct_change()\n",
    "print(annual.to_string(index=False))\n",
    "\n",
    "cagr = (annual[\"vol\"].iloc[-1] / annual[\"vol\"].iloc[0]) ** (1/(len(annual)-1)) - 1\n",
    "print(f\"\\nCAGR 2018-2025: {cagr:.2%}\")\n",
    "print(f\"YoY 2024-2025:   {annual['growth'].iloc[-1]:.2%}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Série mensal agregada\n",
    "monthly = df.groupby(\"date\", as_index=False)[\"vol\"].sum().sort_values(\"date\")\n",
    "ts = monthly.set_index(\"date\")[\"vol\"].asfreq(\"MS\")\n",
    "\n",
    "# Decomposição STL\n",
    "stl = STL(ts, period=12, robust=True).fit()\n",
    "\n",
    "fig, axes = plt.subplots(4, 1, figsize=(11, 8), sharex=True)\n",
    "axes[0].plot(ts, color=PALETA[\"azul\"]); axes[0].set_title(\"Série observada\")\n",
    "axes[1].plot(stl.trend, color=PALETA[\"azul\"]); axes[1].set_title(\"Tendência\")\n",
    "axes[2].plot(stl.seasonal, color=PALETA[\"azul\"]); axes[2].set_title(\"Sazonalidade\")\n",
    "axes[3].plot(stl.resid, color=PALETA[\"azul\"]); axes[3].set_title(\"Resíduo\")\n",
    "for a in axes: a.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x,p: f\"{int(x):,}\"))\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Sazonalidade — índice 100 = mês médio\n",
    "sazon = df.groupby([\"ano\",\"mes\"])[\"vol\"].sum().reset_index()\n",
    "sazon[\"share_ano\"] = sazon.groupby(\"ano\")[\"vol\"].transform(lambda s: s/s.sum())\n",
    "idx = sazon.groupby(\"mes\")[\"share_ano\"].mean().reset_index()\n",
    "idx[\"index_100\"] = idx[\"share_ano\"] * 12 * 100\n",
    "\n",
    "mes_nomes = [\"Jan\",\"Fev\",\"Mar\",\"Abr\",\"Mai\",\"Jun\",\"Jul\",\"Ago\",\"Set\",\"Out\",\"Nov\",\"Dez\"]\n",
    "fig, ax = plt.subplots(figsize=(10, 4.5))\n",
    "cores = [PALETA[\"azul\"] if v >= 100 else PALETA[\"cinza\"] for v in idx[\"index_100\"]]\n",
    "ax.bar(mes_nomes, idx[\"index_100\"], color=cores)\n",
    "ax.axhline(100, color=\"black\", lw=0.7, ls=\"--\")\n",
    "for i, v in enumerate(idx[\"index_100\"]):\n",
    "    ax.text(i, v+1, f\"{v:.0f}\", ha=\"center\", fontsize=9)\n",
    "ax.set_title(\"Índice sazonal — 100 = mês médio do ano\")\n",
    "plt.tight_layout(); plt.show()\n",
    "idx.round(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Achado contraintuitivo:** o pico **não é janeiro** — é **julho-agosto** (índice 110-111). Dezembro é o vale (85). Janeiro está abaixo da média (91).\n",
    "\n",
    "> Implicação: capacidade comercial e mídia paga devem ser concentradas em mai-ago, não distribuídas uniformemente no ano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Crescimento por setor\n",
    "setor_ano = df.groupby([\"setor\",\"ano\"])[\"vol\"].sum().unstack(\"ano\").fillna(0)\n",
    "setor_summary = pd.DataFrame({\n",
    "    \"vol_2025\": setor_ano[2025],\n",
    "    \"share_2025\": setor_ano[2025] / setor_ano[2025].sum(),\n",
    "    \"cagr_18_25\": (setor_ano[2025] / setor_ano[2018].replace(0, np.nan)) ** (1/7) - 1,\n",
    "}).sort_values(\"vol_2025\", ascending=False)\n",
    "\n",
    "print(\"Top 10 setores por volume 2025:\")\n",
    "print(setor_summary.head(10).round(3))\n",
    "print(\"\\nTop 5 setores em crescimento (vol > 1000):\")\n",
    "print(setor_summary[setor_summary.vol_2025>1000].sort_values(\"cagr_18_25\",ascending=False).head().round(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Crescimento por cidade\n",
    "cidade_ano = df.groupby([\"cidade\",\"ano\"])[\"vol\"].sum().unstack(\"ano\").fillna(0)\n",
    "cidade_summary = pd.DataFrame({\n",
    "    \"vol_2025\": cidade_ano[2025],\n",
    "    \"share_2025\": cidade_ano[2025] / cidade_ano[2025].sum(),\n",
    "    \"cagr_18_25\": (cidade_ano[2025] / cidade_ano[2018]) ** (1/7) - 1,\n",
    "}).sort_values(\"vol_2025\", ascending=False)\n",
    "cidade_summary.round(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. P1 — Projeção 2026\n",
    "\n",
    "**Estratégia:**\n",
    "- Hold-out: jan-dez/2025 (12 meses); treino: 2018-2024\n",
    "- Quatro modelos comparados: Holt-Winters multiplicativo, SARIMA, ETS aditivo, Naive sazonal com CAGR\n",
    "- Modelo escolhido: o de menor MAPE no hold-out\n",
    "- Refit com base completa e projeção 2026 com IC 80% e 95% (via SARIMA)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "train = ts.loc[:\"2024-12-01\"]\n",
    "test  = ts.loc[\"2025-01-01\":\"2025-12-01\"]\n",
    "\n",
    "def metrics(y_true, y_pred):\n",
    "    e = y_true - y_pred\n",
    "    mape = float(np.mean(np.abs(e/y_true))*100)\n",
    "    rmse = float(np.sqrt(np.mean(e**2)))\n",
    "    return {\"MAPE_%\": round(mape,2), \"RMSE\": round(rmse,1)}\n",
    "\n",
    "# Holt-Winters multiplicativo\n",
    "hw = ExponentialSmoothing(train, trend=\"add\", seasonal=\"mul\", seasonal_periods=12,\n",
    "                          initialization_method=\"estimated\").fit(optimized=True)\n",
    "hw_test = hw.forecast(len(test))\n",
    "\n",
    "# SARIMA\n",
    "sar = SARIMAX(train, order=(1,1,1), seasonal_order=(1,1,1,12),\n",
    "              enforce_stationarity=False, enforce_invertibility=False).fit(disp=False)\n",
    "sar_test = sar.get_forecast(len(test)).predicted_mean\n",
    "\n",
    "# ETS aditivo\n",
    "ets = ExponentialSmoothing(train, trend=\"add\", seasonal=\"add\", seasonal_periods=12,\n",
    "                           initialization_method=\"estimated\").fit(optimized=True)\n",
    "ets_test = ets.forecast(len(test))\n",
    "\n",
    "# Naive sazonal: jan/2025 = jan/2024 × (1+CAGR)\n",
    "cagr_recente = (train.iloc[-12:].sum() / train.iloc[-24:-12].sum()) - 1\n",
    "naive = pd.Series(train.iloc[-12:].values * (1+cagr_recente), index=test.index)\n",
    "\n",
    "cmp = pd.DataFrame([\n",
    "    {\"modelo\":\"Holt-Winters mul\",   **metrics(test.values, hw_test.values)},\n",
    "    {\"modelo\":\"SARIMA(1,1,1)(1,1,1,12)\", **metrics(test.values, sar_test.values)},\n",
    "    {\"modelo\":\"ETS aditivo\",        **metrics(test.values, ets_test.values)},\n",
    "    {\"modelo\":f\"Naive sazonal (cagr={cagr_recente:.0%})\", **metrics(test.values, naive.values)},\n",
    "])\n",
    "print(cmp.to_string(index=False))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Insight:** o Naive sazonal acerta quase tão bem quanto Holt-Winters. *A alavanca não está no modelo — está na granularidade.* Esse achado é importante para a P2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(11,5))\n",
    "ax.plot(train.index[-36:], train.values[-36:], color=PALETA[\"azul\"], lw=1.4, label=\"Treino (últ. 36m)\")\n",
    "ax.plot(test.index, test.values, color=\"black\", lw=2.0, label=\"Realizado 2025\")\n",
    "ax.plot(test.index, hw_test.values, color=PALETA[\"gold\"], lw=1.6, ls=\"--\", label=\"HW\")\n",
    "ax.plot(test.index, sar_test.values, color=PALETA[\"verde\"], lw=1.6, ls=\"--\", label=\"SARIMA\")\n",
    "ax.plot(test.index, naive.values, color=PALETA[\"vermelho\"], lw=1.4, ls=\":\", label=\"Naive sazonal\")\n",
    "ax.set_title(\"Hold-out 2025 — comparação dos modelos\")\n",
    "ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x,p: f\"{int(x):,}\"))\n",
    "ax.legend(); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Refit em toda a base + projeção 2026 com IC\n",
    "sar_full = SARIMAX(ts, order=(1,1,1), seasonal_order=(1,1,1,12),\n",
    "                   enforce_stationarity=False, enforce_invertibility=False).fit(disp=False)\n",
    "fc = sar_full.get_forecast(steps=12)\n",
    "fc_mean = fc.predicted_mean\n",
    "ci80 = fc.conf_int(alpha=0.20); ci95 = fc.conf_int(alpha=0.05)\n",
    "fc_mean.index = ci80.index = ci95.index = pd.date_range(\"2026-01-01\", periods=12, freq=\"MS\")\n",
    "\n",
    "hw_full = ExponentialSmoothing(ts, trend=\"add\", seasonal=\"mul\", seasonal_periods=12,\n",
    "                               initialization_method=\"estimated\").fit(optimized=True)\n",
    "hw_2026 = hw_full.forecast(12); hw_2026.index = fc_mean.index\n",
    "\n",
    "print(f\"Total 2025 realizado:  {int(ts.loc['2025'].sum()):,}\")\n",
    "print(f\"Total 2026 SARIMA base: {int(fc_mean.sum()):,}\")\n",
    "print(f\"Total 2026 HW (sanity): {int(hw_2026.sum()):,}\")\n",
    "print(f\"IC 80%: {int(ci80.iloc[:,0].sum()):,} – {int(ci80.iloc[:,1].sum()):,}\")\n",
    "print(f\"IC 95%: {int(ci95.iloc[:,0].sum()):,} – {int(ci95.iloc[:,1].sum()):,}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(12,5.5))\n",
    "ax.plot(ts.index, ts.values, color=PALETA[\"azul\"], lw=1.6, label=\"Realizado 2018-2025\")\n",
    "ax.plot(fc_mean.index, fc_mean.values, color=PALETA[\"gold\"], lw=2.4, label=\"Projeção 2026 (SARIMA)\")\n",
    "ax.plot(hw_2026.index, hw_2026.values, color=PALETA[\"cinza\"], lw=1.4, ls=\"--\", label=\"Sanity (HW)\")\n",
    "ax.fill_between(ci95.index, ci95.iloc[:,0], ci95.iloc[:,1], color=PALETA[\"gold\"], alpha=0.10, label=\"IC 95%\")\n",
    "ax.fill_between(ci80.index, ci80.iloc[:,0], ci80.iloc[:,1], color=PALETA[\"gold\"], alpha=0.22, label=\"IC 80%\")\n",
    "ax.axvline(pd.Timestamp(\"2026-01-01\"), color=\"black\", ls=\":\", lw=0.8)\n",
    "ax.set_title(\"Aberturas mensais — realizado e projeção 2026\")\n",
    "ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x,p: f\"{int(x):,}\"))\n",
    "ax.legend(loc=\"upper left\"); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. P2 — Diagnóstico de incerteza\n",
    "\n",
    "Não basta o número agregado. Como o erro se distribui pelos cortes (cidade × setor)? Onde a Contabilizei NÃO deve confiar em metas mensais granulares?\n",
    "\n",
    "**Abordagem:** ajustar Holt-Winters em cada (cidade × setor), reportar MAPE no hold-out 2025, cruzar com volume.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Painel completo cidade x setor x mes\n",
    "all_dates = pd.date_range(\"2018-01-01\",\"2025-12-01\",freq=\"MS\")\n",
    "all_keys = df[[\"cidade\",\"setor\"]].drop_duplicates()\n",
    "grid = all_keys.assign(_=1).merge(pd.DataFrame({\"date\":all_dates,\"_\":1}), on=\"_\").drop(\"_\",axis=1)\n",
    "panel = grid.merge(df.groupby([\"cidade\",\"setor\",\"date\"], as_index=False)[\"vol\"].sum(),\n",
    "                   on=[\"cidade\",\"setor\",\"date\"], how=\"left\")\n",
    "panel[\"vol\"] = panel[\"vol\"].fillna(0)\n",
    "\n",
    "def fit_predict(s, h=12):\n",
    "    s = s.replace(0, np.nan).ffill().bfill()\n",
    "    if s.isna().all() or s.sum() < 12: return np.full(h, np.nan)\n",
    "    try:\n",
    "        seas = \"mul\" if (s>0).all() else \"add\"\n",
    "        m = ExponentialSmoothing(s, trend=\"add\", seasonal=seas, seasonal_periods=12,\n",
    "                                 initialization_method=\"estimated\").fit(optimized=True)\n",
    "        return np.maximum(m.forecast(h).values, 0)\n",
    "    except Exception:\n",
    "        return s.iloc[-12:].values\n",
    "\n",
    "results = []\n",
    "for (cidade, setor), g in panel.groupby([\"cidade\",\"setor\"]):\n",
    "    g = g.sort_values(\"date\").set_index(\"date\")\n",
    "    train_g = g.loc[:\"2024-12-01\",\"vol\"].asfreq(\"MS\")\n",
    "    test_g  = g.loc[\"2025-01-01\":\"2025-12-01\",\"vol\"].asfreq(\"MS\")\n",
    "    if test_g.sum() == 0 or train_g.sum() < 100: continue\n",
    "    pred = fit_predict(train_g, h=len(test_g))\n",
    "    e = test_g.values - pred\n",
    "    mape = float(np.mean(np.abs(e/np.maximum(test_g.values,1)))*100)\n",
    "    results.append({\n",
    "        \"cidade\":cidade, \"setor\":setor,\n",
    "        \"vol_2025\":int(test_g.sum()),\n",
    "        \"MAPE_%\":round(mape,2),\n",
    "        \"cv_hist\": float(g[\"vol\"].std()/max(g[\"vol\"].mean(),1e-9)),\n",
    "    })\n",
    "err_df = pd.DataFrame(results).sort_values(\"vol_2025\", ascending=False)\n",
    "print(f\"Cortes avaliados: {len(err_df)}\")\n",
    "print(f\"MAPE mediano: {err_df['MAPE_%'].median():.1f}%\")\n",
    "print(f\"MAPE pond. vol: {(err_df['MAPE_%']*err_df['vol_2025']).sum()/err_df['vol_2025'].sum():.1f}%\")\n",
    "print(\"\\nTop 5 mais difíceis (vol > 1000):\")\n",
    "print(err_df[err_df.vol_2025>1000].sort_values(\"MAPE_%\",ascending=False).head().to_string(index=False))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Matriz erro x volume — scatter\n",
    "fig, ax = plt.subplots(figsize=(11,6))\n",
    "e = err_df[err_df.vol_2025>100].copy()\n",
    "sizes = e.vol_2025/e.vol_2025.max()*800 + 25\n",
    "sc = ax.scatter(e.vol_2025, e[\"MAPE_%\"], s=sizes, alpha=0.55, c=e.cv_hist,\n",
    "                cmap=\"viridis_r\", edgecolors=\"black\", linewidths=0.4)\n",
    "ax.set_xscale(\"log\"); ax.set_xlabel(\"Volume 2025 (log)\"); ax.set_ylabel(\"MAPE (%)\")\n",
    "ax.set_title(\"Erro x volume — cor = CV histórico\")\n",
    "plt.colorbar(sc, ax=ax, label=\"CV histórico\")\n",
    "ax.axhline(e[\"MAPE_%\"].median(), color=\"red\", lw=0.8, ls=\"--\",\n",
    "           label=f\"MAPE mediano: {e['MAPE_%'].median():.1f}%\")\n",
    "piores = e.sort_values(\"MAPE_%\",ascending=False).head(4)\n",
    "for _, r in piores.iterrows():\n",
    "    ax.annotate(f\"{r.cidade[:3]}/{r.setor[:8]}\", (r.vol_2025, r[\"MAPE_%\"]),\n",
    "                fontsize=8, xytext=(5,4), textcoords=\"offset points\")\n",
    "ax.legend(); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Leitura:** o **MAPE ponderado por volume** (≈16-18%) é dramaticamente maior que o MAPE do agregado (8%). Isso confirma o que o avaliador antecipou: *\"a projeção mês a mês é notoriamente imprecisa para qualquer player do mercado.\"*\n",
    "\n",
    "**Cortes mais perigosos** (alto volume + alto erro):\n",
    "- **SP / Apoio Adm** — vol 19,5k, MAPE 41%\n",
    "- **SP / Psicologia** — vol 4,5k, MAPE 26% (crescimento explosivo +36% a.a.)\n",
    "- **Florianópolis** (todas) — MAPE 28%\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. P3 — Meta de market share (20% em 2026)\n",
    "\n",
    "A nota do avaliador é explícita: *\"a projeção mês a mês é imprecisa, mas a anual é confiável.\"* Aplico 20% sobre 5 cenários de mercado e distribuo pela sazonalidade.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "share_target = 0.20\n",
    "total_2025 = int(ts.loc[\"2025\"].sum())\n",
    "yoy_25 = total_2025/int(ts.loc[\"2024\"].sum()) - 1\n",
    "\n",
    "cenarios = {\n",
    "    \"Conservador (HW projeção)\": int(hw_2026.sum()),\n",
    "    \"Base (SARIMA)\":             int(fc_mean.sum()),\n",
    "    \"Recente (CAGR 22-25)\":      int(total_2025 * (1 + (total_2025/int(ts.loc[\"2022\"].sum()))**(1/3) - 1)),\n",
    "    \"Otimista (CAGR 18-25)\":     int(total_2025 * (1+cagr)),\n",
    "    f\"YoY 2025 ({yoy_25:+.0%})\": int(total_2025 * (1+yoy_25)),\n",
    "}\n",
    "meta = pd.DataFrame({\n",
    "    \"cenario\": list(cenarios.keys()),\n",
    "    \"mercado_2026\": list(cenarios.values()),\n",
    "})\n",
    "meta[\"meta_anual\"] = (meta[\"mercado_2026\"]*share_target).round().astype(int)\n",
    "meta[\"meta_mensal_media\"] = (meta[\"meta_anual\"]/12).round().astype(int)\n",
    "meta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Distribuição mensal pelo índice sazonal\n",
    "share_mes = idx.set_index(\"mes\")[\"share_ano\"]\n",
    "base_mercado = cenarios[\"Base (SARIMA)\"]\n",
    "base_meta = int(base_mercado * share_target)\n",
    "\n",
    "mensal = pd.DataFrame({\n",
    "    \"mes\": mes_nomes,\n",
    "    \"mercado_mes\": (base_mercado * share_mes).round().astype(int).values,\n",
    "    \"meta_mes\":    (base_meta    * share_mes).round().astype(int).values,\n",
    "})\n",
    "mensal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(1, 2, figsize=(14,4.5))\n",
    "# Cenários\n",
    "ax = axes[0]\n",
    "x = np.arange(len(meta))\n",
    "ax.bar(x-0.2, meta.mercado_2026, 0.4, color=PALETA[\"azul\"], label=\"Mercado 2026\")\n",
    "ax.bar(x+0.2, meta.meta_anual, 0.4, color=PALETA[\"gold\"], label=\"Meta 20%\")\n",
    "ax.set_xticks(x); ax.set_xticklabels(meta.cenario, rotation=18, ha=\"right\", fontsize=8)\n",
    "ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v,p: f\"{int(v/1000)}k\"))\n",
    "ax.set_title(\"Meta sob 5 cenários\"); ax.legend()\n",
    "# Mensal\n",
    "ax = axes[1]\n",
    "ax.bar(mes_nomes, mensal.meta_mes, color=PALETA[\"gold\"])\n",
    "ax.axhline(base_meta/12, color=\"black\", lw=0.8, ls=\"--\", label=f\"Uniforme: {int(base_meta/12):,}\")\n",
    "for i, v in enumerate(mensal.meta_mes):\n",
    "    ax.text(i, v+50, f\"{v:,}\", ha=\"center\", fontsize=8)\n",
    "ax.set_title(\"Meta mensal — distribuída pela sazonalidade\"); ax.legend()\n",
    "plt.tight_layout(); plt.show()\n",
    "print(f\"Faixa de meta: {meta.meta_anual.min():,} – {meta.meta_anual.max():,} vendas em 2026\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Aviso de honestidade:** 20% é stretch. Estimativa pública: Contabilizei abre ~35-40k empresas/ano hoje (extrapolação de 100k clientes em 12 anos × 40% crescimento atual). Para 67,5k em 2026 ela precisa **quase dobrar** a taxa atual. Vale propor 17% (~57k) como cenário alternativo realista no Q&A."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. P4 — Matriz de oportunidade e cluster Saúde\n",
    "\n",
    "Cruzando volume (2025) com CAGR (2018-2025), o mercado se separa em 4 quadrantes. A estratégia de aquisição deve atacar o canto superior-direito.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = setor_summary[setor_summary.vol_2025>1500].copy()\n",
    "med_cagr = s.cagr_18_25.median(); med_vol = s.vol_2025.median()\n",
    "\n",
    "quadr = []\n",
    "for nome, r in s.iterrows():\n",
    "    if r.vol_2025>=med_vol and r.cagr_18_25>=med_cagr: q=\"ATACAR\"\n",
    "    elif r.vol_2025>=med_vol: q=\"MANTER\"\n",
    "    elif r.cagr_18_25>=med_cagr: q=\"APOSTAR\"\n",
    "    else: q=\"DEPRIORIZAR\"\n",
    "    quadr.append({\"setor\":nome,\"vol_2025\":int(r.vol_2025),\"cagr\":r.cagr_18_25,\"quadrante\":q})\n",
    "quadr_df = pd.DataFrame(quadr)\n",
    "print(quadr_df.groupby(\"quadrante\")[\"setor\"].apply(lambda s: \", \".join(s.tolist())).to_string())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(12,7))\n",
    "cores = {\"ATACAR\":PALETA[\"azul\"], \"APOSTAR\":PALETA[\"gold\"],\n",
    "         \"MANTER\":PALETA[\"verde\"], \"DEPRIORIZAR\":\"#aaaaaa\"}\n",
    "for q, c in cores.items():\n",
    "    sub = quadr_df[quadr_df.quadrante==q]\n",
    "    ax.scatter(sub.vol_2025, sub.cagr*100, s=300, c=c, alpha=0.78,\n",
    "               edgecolors=\"black\", linewidths=0.5, label=q)\n",
    "for _, r in quadr_df.iterrows():\n",
    "    ax.annotate(r.setor, (r.vol_2025, r.cagr*100),\n",
    "                fontsize=8, xytext=(7,5), textcoords=\"offset points\")\n",
    "ax.axvline(med_vol, color=\"black\", lw=0.7, ls=\"--\", alpha=0.5)\n",
    "ax.axhline(med_cagr*100, color=\"black\", lw=0.7, ls=\"--\", alpha=0.5)\n",
    "ax.set_xscale(\"log\")\n",
    "ax.set_xlabel(\"Volume 2025 (log)\"); ax.set_ylabel(\"CAGR 2018-2025 (%)\")\n",
    "ax.set_title(\"Matriz de oportunidade — quadrantes setoriais\")\n",
    "ax.yaxis.set_major_formatter(mticker.PercentFormatter())\n",
    "ax.legend(loc=\"upper left\"); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Cluster Saúde\n",
    "saude = [\"Medicina\",\"Psicologia\",\"Odontologia\",\"Fisioterapia\",\"Veterinária\",\"Outros Saúde\",\"Educação Física\"]\n",
    "cl = setor_summary.loc[setor_summary.index.isin(saude)].sort_values(\"vol_2025\")\n",
    "print(f\"Cluster Saúde 2025: {int(cl.vol_2025.sum()):,} aberturas \"\n",
    "      f\"({cl.vol_2025.sum()/setor_summary.vol_2025.sum()*100:.1f}% do mercado)\")\n",
    "print(f\"CAGR médio do cluster: {cl.cagr_18_25.mean()*100:.1f}% a.a.\")\n",
    "cl.round(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Síntese executiva\n",
    "\n",
    "### As 3 frentes priorizadas para 2026\n",
    "\n",
    "| Frente | Setor-alvo | Canal-chave | Mensagem | KPI 12m |\n",
    "|---|---|---|---|---:|\n",
    "| **1. Vertical Saúde** | Medicina, Psicologia, Odonto, Fisio, Outros Saúde | Landing dedicada + parceria CRM/CRP/CFO + YouTube série | \"Saí do CLT, virei PJ\" | **19k aberturas** |\n",
    "| **2. TI/DEV fora de SP** | TI/DEV, Mídia, Design (interior) | SEO PJ vs CLT + plataformas de freela + bancos digitais | calculadora CLT vs PJ | **12k aberturas** |\n",
    "| **3. Reforma como gatilho** | Toda a base | Calculadora pós-Reforma + roadshow + mídia mai-ago | \"Você está pronto para 2026?\" | **30k aberturas** |\n",
    "\n",
    "**Total das 3 frentes:** ~61k aberturas (~90% da meta de 67,5k).\n",
    "\n",
    "### Três coisas para levar\n",
    "\n",
    "1. **Mercado vai chegar em ~340k aberturas em 2026.** 20% = 67,5k vendas (faixa honesta 65-78k).\n",
    "2. **A heterogeneidade importa mais que o número agregado.** Saúde sozinha é 24% do mercado e cresce 21% a.a. É lá.\n",
    "3. **A estratégia é executável em 90 dias.** Vertical Saúde (parceria com 3 conselhos) + landing TI/DEV regional + calculadora Reforma.\n",
    "\n",
    "### Confissão proativa\n",
    "Não tenho dado de CAC ou conversão da Contabilizei. Com isso em mãos, eu reordenaria a priorização — provavelmente Saúde sobe ainda mais e TI cai um pouco.\n",
    "\n",
    "### Pergunta inversa para os avaliadores\n",
    "*\"Vocês têm visão de CAC por setor? E qual é o CAC alvo para 2026?\"*\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}