[{"data":1,"prerenderedAt":1295},["ShallowReactive",2],{"article-alternates":3,"article-\u002Fes\u002Fdata\u002Fmarketing-mix-modeling-configuracion-practica-robyn":13},{"i18nKey":4,"paths":5},"data-005-2026-07",{"de":6,"en":7,"es":8,"fr":9,"it":10,"ru":11,"tr":12},"\u002Fde\u002Fdata\u002Fmarketing-mix-modeling-robyn-praktische-einrichtung","\u002Fen\u002Fdata\u002Fmarketing-mix-modeling-robyn-practical-setup","\u002Fes\u002Fdata\u002Fmarketing-mix-modeling-robyn-configuracion-practica","\u002Ffr\u002Fdata\u002Fmodelisation-mix-marketing-configuration-pratique-robyn","\u002Fit\u002Fdata\u002Fmarketing-mix-modeling-robyn-kurulum","\u002Fru\u002Fdata\u002Fmarketing-mix-modeling-robyn-prakticheskaia-nastroika","\u002Ftr\u002Fdata\u002Fmarketing-mix-modeling-robyn-ile-pratik-kurulum",{"_path":14,"_dir":15,"_draft":16,"_partial":16,"_locale":17,"title":18,"description":19,"publishedAt":20,"modifiedAt":20,"category":15,"i18nKey":4,"tags":21,"readingTime":27,"author":28,"body":29,"_type":1289,"_id":1290,"_source":1291,"_file":1292,"_stem":1293,"_extension":1294},"\u002Fes\u002Fdata\u002Fmarketing-mix-modeling-configuracion-practica-robyn","data",false,"","Marketing Mix Modeling: Configuración Práctica con Robyn","Demostramos la configuración de la librería MMM open-source de Meta, Robyn, incluyendo curvas de saturación, adstock decay y validación holdout sobre datos de producción.","2026-07-07",[22,23,24,25,26],"marketing-mix-modeling","robyn","adstock","saturation-curve","media-attribution",8,"Roibase",{"type":30,"children":31,"toc":1277},"root",[32,40,47,52,57,73,79,84,186,205,223,231,251,264,270,275,282,303,311,319,332,342,352,358,363,371,396,401,411,417,422,445,458,544,554,600,605,659,664,690,696,701,777,790,874,884,894,908,914,933,941,1010,1015,1136,1141,1159,1164,1178,1191,1197,1202,1256,1261,1271],{"type":33,"tag":34,"props":35,"children":36},"element","p",{},[37],{"type":38,"value":39},"text","Los modelos de atribución multitouch pierden confiabilidad en la era post-cookie, mientras que el marketing mix modeling resurge como protagonista. Las herramientas MMM open-source de Google y Meta (LightweightMMM, Robyn) permiten al marketer medir la efectividad del canal a nivel agregado. En 2025, Robyn 3.11 de Meta alcanzó madurez productiva con optimización Bayesiana y búsqueda paralela de hiperparámetros. Este artículo presenta la configuración de Robyn en torno a tres conceptos fundamentales: curva de saturación (rendimientos decrecientes), adstock decay (efecto retrasado) y validación holdout (confiabilidad del modelo).",{"type":33,"tag":41,"props":42,"children":44},"h2",{"id":43},"qué-es-robyn-y-por-qué-importa-ahora",[45],{"type":38,"value":46},"Qué es Robyn y por qué importa ahora",{"type":33,"tag":34,"props":48,"children":49},{},[50],{"type":38,"value":51},"Robyn es un paquete R lanzado por Meta en 2021 como software open-source. El modelo, construido sobre regresión ridge, ingiere datos de gasto por canal y conversiones en agregación semanal o diaria, y calcula la contribución de conversión incremental de cada canal. Con la gran actualización de 2024, el modelo integró componentes de series temporales de Prophet y ganó soporte de exportación basada en JSON — permitiendo conexión a flujos de trabajo Python.",{"type":33,"tag":34,"props":53,"children":54},{},[55],{"type":38,"value":56},"Tres características diferencian a Robyn de otros enfoques MMM: primero, modela la relación gasto-conversión no linealmente mediante la transformación Hill-Adstock (saturación realista); segundo, resuelve la optimización de hiperparámetros con algoritmo genético y optimizador Nevergrad sin gradiente (sin necesidad de ajuste manual); tercero, reporta automáticamente métricas de calidad del modelo (NRMSE, DECOMP.RSSD, MAPE). Para confiabilidad en producción, la función integrada de validación holdout es crítica — la demostraremos más adelante.",{"type":33,"tag":34,"props":58,"children":59},{},[60,62,71],{"type":38,"value":61},"La ventaja del marketing mix modeling sobre atribución es que trabaja con datos agregados, evitando limitaciones GDPR\u002FCCPA y complejidad de journeys multi-dispositivo. La desventaja es la granularidad semanal — no sirve para optimización intraday, solo para asignación de presupuesto trimestral. En Roibase, dentro de la ",{"type":33,"tag":63,"props":64,"children":68},"a",{"href":65,"rel":66},"https:\u002F\u002Fwww.roibase.com.tr\u002Fes\u002Ffirstparty",[67],"nofollow",[69],{"type":38,"value":70},"arquitectura de datos first-party",{"type":38,"value":72},", posicionamos MMM junto con resultados de pruebas de incrementalidad: un canal con ROAS alto en MMM no es suficiente — requiere validación mediante test geo-split o control sintético.",{"type":33,"tag":41,"props":74,"children":76},{"id":75},"preparación-de-datos-gasto-por-canal-variables-macroeconómicas",[77],{"type":38,"value":78},"Preparación de datos: gasto por canal + variables macroeconómicas",{"type":33,"tag":34,"props":80,"children":81},{},[82],{"type":38,"value":83},"Robyn requiere como entrada mínima estas columnas en una serie temporal semanal:",{"type":33,"tag":85,"props":86,"children":90},"pre",{"code":87,"language":88,"meta":17,"className":89,"style":17},"# Estructura de datos de ejemplo (2 años de datos semanales)\ndata \u003C- data.frame(\n  date = seq(as.Date(\"2024-01-01\"), by = \"week\", length.out = 104),\n  revenue = rnorm(104, 50000, 8000),\n  facebook_spend = rnorm(104, 5000, 1000),\n  google_search_spend = rnorm(104, 7000, 1500),\n  display_spend = rnorm(104, 3000, 800),\n  competitor_index = rnorm(104, 100, 15),  # variable macroeconómica\n  holiday_flag = sample(0:1, 104, replace = TRUE)\n)\n","r","language-r shiki shiki-themes github-dark",[91],{"type":33,"tag":92,"props":93,"children":94},"code",{"__ignoreMap":17},[95,106,115,124,133,142,151,160,168,177],{"type":33,"tag":96,"props":97,"children":100},"span",{"class":98,"line":99},"line",1,[101],{"type":33,"tag":96,"props":102,"children":103},{},[104],{"type":38,"value":105},"# Estructura de datos de ejemplo (2 años de datos semanales)\n",{"type":33,"tag":96,"props":107,"children":109},{"class":98,"line":108},2,[110],{"type":33,"tag":96,"props":111,"children":112},{},[113],{"type":38,"value":114},"data \u003C- data.frame(\n",{"type":33,"tag":96,"props":116,"children":118},{"class":98,"line":117},3,[119],{"type":33,"tag":96,"props":120,"children":121},{},[122],{"type":38,"value":123},"  date = seq(as.Date(\"2024-01-01\"), by = \"week\", length.out = 104),\n",{"type":33,"tag":96,"props":125,"children":127},{"class":98,"line":126},4,[128],{"type":33,"tag":96,"props":129,"children":130},{},[131],{"type":38,"value":132},"  revenue = rnorm(104, 50000, 8000),\n",{"type":33,"tag":96,"props":134,"children":136},{"class":98,"line":135},5,[137],{"type":33,"tag":96,"props":138,"children":139},{},[140],{"type":38,"value":141},"  facebook_spend = rnorm(104, 5000, 1000),\n",{"type":33,"tag":96,"props":143,"children":145},{"class":98,"line":144},6,[146],{"type":33,"tag":96,"props":147,"children":148},{},[149],{"type":38,"value":150},"  google_search_spend = rnorm(104, 7000, 1500),\n",{"type":33,"tag":96,"props":152,"children":154},{"class":98,"line":153},7,[155],{"type":33,"tag":96,"props":156,"children":157},{},[158],{"type":38,"value":159},"  display_spend = rnorm(104, 3000, 800),\n",{"type":33,"tag":96,"props":161,"children":162},{"class":98,"line":27},[163],{"type":33,"tag":96,"props":164,"children":165},{},[166],{"type":38,"value":167},"  competitor_index = rnorm(104, 100, 15),  # variable macroeconómica\n",{"type":33,"tag":96,"props":169,"children":171},{"class":98,"line":170},9,[172],{"type":33,"tag":96,"props":173,"children":174},{},[175],{"type":38,"value":176},"  holiday_flag = sample(0:1, 104, replace = TRUE)\n",{"type":33,"tag":96,"props":178,"children":180},{"class":98,"line":179},10,[181],{"type":33,"tag":96,"props":182,"children":183},{},[184],{"type":38,"value":185},")\n",{"type":33,"tag":34,"props":187,"children":188},{},[189,195,197,203],{"type":33,"tag":190,"props":191,"children":192},"strong",{},[193],{"type":38,"value":194},"Número de columnas de canal:",{"type":38,"value":196}," Mínimo 2, máximo 15 recomendado. Con 20+ canales, riesgo de overfitting aumenta y estabilidad de coeficientes cae. Si existen canales long-tail (affiliate, influencer, podcast), agruparlos en una sola columna ",{"type":33,"tag":92,"props":198,"children":200},{"className":199},[],[201],{"type":38,"value":202},"other_digital",{"type":38,"value":204}," es más saludable.",{"type":33,"tag":34,"props":206,"children":207},{},[208,213,215,221],{"type":33,"tag":190,"props":209,"children":210},{},[211],{"type":38,"value":212},"Variables macroeconómicas:",{"type":38,"value":214}," Deben incluir seasonalidad, festivos, índice competidor, indicadores económicos — de lo contrario, el modelo puede atribuir todo crecimiento de conversiones a canales de medios. La integración de Prophet en Robyn captura automáticamente tendencia y festivos, pero shocks específicos del sector (Black Friday, Ramadán) requieren ",{"type":33,"tag":92,"props":216,"children":218},{"className":217},[],[219],{"type":38,"value":220},"holiday_flag",{"type":38,"value":222}," explícito.",{"type":33,"tag":34,"props":224,"children":225},{},[226],{"type":33,"tag":190,"props":227,"children":228},{},[229],{"type":38,"value":230},"Controles de calidad de datos:",{"type":33,"tag":232,"props":233,"children":234},"ul",{},[235,241,246],{"type":33,"tag":236,"props":237,"children":238},"li",{},[239],{"type":38,"value":240},"Ninguna columna debe tener varianza cero (gasto constante = inútil)",{"type":33,"tag":236,"props":242,"children":243},{},[244],{"type":38,"value":245},"Tolerancia de valores faltantes: máximo 5% — Robyn no imputa automáticamente",{"type":33,"tag":236,"props":247,"children":248},{},[249],{"type":38,"value":250},"Granularidad semanal es preferida — datos diarios aumentan ruido, datos mensuales resultan en observaciones insuficientes",{"type":33,"tag":34,"props":252,"children":253},{},[254,256,262],{"type":38,"value":255},"Si datos de gasto provienen de múltiples fuentes (Google Ads API, Meta Marketing API, sistemas internos de finanzas), establece un pipeline ETL. En nuestro flujo de producción, tenemos tabla ",{"type":33,"tag":92,"props":257,"children":259},{"className":258},[],[260],{"type":38,"value":261},"marketing_spend_weekly",{"type":38,"value":263}," en BigQuery; cada lunes por la mañana, el modelo dbt actualiza esta tabla y el script R la consume, activando Robyn.",{"type":33,"tag":41,"props":265,"children":267},{"id":266},"saturación-y-adstock-transformación-hill-adstock",[268],{"type":38,"value":269},"Saturación y adstock: transformación Hill-Adstock",{"type":33,"tag":34,"props":271,"children":272},{},[273],{"type":38,"value":274},"Robyn procesa cada gasto de canal a través de dos transformaciones: primero adstock (efecto retrasado), luego saturación (rendimientos decrecientes).",{"type":33,"tag":276,"props":277,"children":279},"h3",{"id":278},"adstock-decay-geométrico-o-weibull",[280],{"type":38,"value":281},"Adstock decay (geométrico o Weibull)",{"type":33,"tag":34,"props":283,"children":284},{},[285,287,293,295,301],{"type":38,"value":286},"El impacto de un anuncio de TV no termina instantáneamente — persiste semanas en la memoria del espectador. Adstock lo modela. Robyn soporta dos tipos: ",{"type":33,"tag":92,"props":288,"children":290},{"className":289},[],[291],{"type":38,"value":292},"geometric",{"type":38,"value":294}," (simple, decaimiento exponencial) y ",{"type":33,"tag":92,"props":296,"children":298},{"className":297},[],[299],{"type":38,"value":300},"weibull",{"type":38,"value":302}," (flexible, curva S).",{"type":33,"tag":34,"props":304,"children":305},{},[306],{"type":33,"tag":190,"props":307,"children":308},{},[309],{"type":38,"value":310},"Adstock geométrico:",{"type":33,"tag":85,"props":312,"children":314},{"code":313},"adstocked_spend[t] = spend[t] + θ × adstocked_spend[t-1]\n",[315],{"type":33,"tag":92,"props":316,"children":317},{"__ignoreMap":17},[318],{"type":38,"value":313},{"type":33,"tag":34,"props":320,"children":321},{},[322,324,330],{"type":38,"value":323},"Aquí ",{"type":33,"tag":92,"props":325,"children":327},{"className":326},[],[328],{"type":38,"value":329},"θ",{"type":38,"value":331}," (theta) es la tasa de decay — 0.5 significa que la mitad del efecto de la semana anterior se transfiere a esta semana. Robyn busca automáticamente este parámetro entre 0–0.9.",{"type":33,"tag":34,"props":333,"children":334},{},[335,340],{"type":33,"tag":190,"props":336,"children":337},{},[338],{"type":38,"value":339},"Adstock Weibull:",{"type":38,"value":341}," Más complejo — tiene parámetros shape y scale. Para canales \"awareness\" (TV, outdoor, influencer), Weibull ajusta mejor porque el efecto puede comenzar lentamente, alcanzar pico y luego caer rápido.",{"type":33,"tag":34,"props":343,"children":344},{},[345,350],{"type":33,"tag":190,"props":346,"children":347},{},[348],{"type":38,"value":349},"Recomendación práctica:",{"type":38,"value":351}," En la primera iteración del modelo, usa geométrico — convergencia más rápida. Si performance es baja (NRMSE > 0.15) y el mix es heavy en awareness, prueba Weibull.",{"type":33,"tag":276,"props":353,"children":355},{"id":354},"saturación-función-hill",[356],{"type":38,"value":357},"Saturación: función Hill",{"type":33,"tag":34,"props":359,"children":360},{},[361],{"type":38,"value":362},"Doblar gasto no dobla conversiones — existen rendimientos decrecientes. Robyn lo modela con ecuación Hill:",{"type":33,"tag":85,"props":364,"children":366},{"code":365},"effect = spend^α \u002F (K^α + spend^α)\n",[367],{"type":33,"tag":92,"props":368,"children":369},{"__ignoreMap":17},[370],{"type":38,"value":365},{"type":33,"tag":232,"props":372,"children":373},{},[374,385],{"type":33,"tag":236,"props":375,"children":376},{},[377,383],{"type":33,"tag":92,"props":378,"children":380},{"className":379},[],[381],{"type":38,"value":382},"α",{"type":38,"value":384}," (alpha): inclinación de la curva — pequeño = saturación lenta, grande = rápida",{"type":33,"tag":236,"props":386,"children":387},{},[388,394],{"type":33,"tag":92,"props":389,"children":391},{"className":390},[],[392],{"type":38,"value":393},"K",{"type":38,"value":395},": punto de semi-saturación — cuando gasto alcanza este nivel, se logra la mitad del efecto máximo",{"type":33,"tag":34,"props":397,"children":398},{},[399],{"type":38,"value":400},"Robyn encuentra estos dos parámetros para cada canal durante la búsqueda de hiperparámetros. El resultado: ves la \"response curve\" de cada canal — por ejemplo, Facebook Ads se aplana después de €10K, mientras Google Search sigue lineal hasta €20K.",{"type":33,"tag":34,"props":402,"children":403},{},[404,409],{"type":33,"tag":190,"props":405,"children":406},{},[407],{"type":38,"value":408},"Utilidad de la curva de saturación:",{"type":38,"value":410}," Scenarios de reasignación de presupuesto. Si la pendiente de un canal ya es plana (flat), transferir presupuesto desde allí hacia un canal con pendiente más pronunciada aumenta ROAS total.",{"type":33,"tag":41,"props":412,"children":414},{"id":413},"ejecución-del-modelo-e-ionización-de-hiperparámetros",[415],{"type":38,"value":416},"Ejecución del modelo e ionización de hiperparámetros",{"type":33,"tag":34,"props":418,"children":419},{},[420],{"type":38,"value":421},"Instalación de Robyn en dos líneas:",{"type":33,"tag":85,"props":423,"children":425},{"code":424,"language":88,"meta":17,"className":89,"style":17},"install.packages(\"Robyn\")\nlibrary(Robyn)\n",[426],{"type":33,"tag":92,"props":427,"children":428},{"__ignoreMap":17},[429,437],{"type":33,"tag":96,"props":430,"children":431},{"class":98,"line":99},[432],{"type":33,"tag":96,"props":433,"children":434},{},[435],{"type":38,"value":436},"install.packages(\"Robyn\")\n",{"type":33,"tag":96,"props":438,"children":439},{"class":98,"line":108},[440],{"type":33,"tag":96,"props":441,"children":442},{},[443],{"type":38,"value":444},"library(Robyn)\n",{"type":33,"tag":34,"props":446,"children":447},{},[448,450,456],{"type":38,"value":449},"En ",{"type":33,"tag":92,"props":451,"children":453},{"className":452},[],[454],{"type":38,"value":455},"InputCollect",{"type":38,"value":457}," defines la estructura de datos:",{"type":33,"tag":85,"props":459,"children":461},{"code":460,"language":88,"meta":17,"className":89,"style":17},"InputCollect \u003C- robyn_inputs(\n  dt_input = data,\n  date_var = \"date\",\n  dep_var = \"revenue\",\n  paid_media_spends = c(\"facebook_spend\", \"google_search_spend\", \"display_spend\"),\n  context_vars = c(\"competitor_index\", \"holiday_flag\"),\n  window_start = \"2024-01-01\",\n  window_end = \"2025-12-31\",\n  adstock = \"geometric\"  # o \"weibull\"\n)\n",[462],{"type":33,"tag":92,"props":463,"children":464},{"__ignoreMap":17},[465,473,481,489,497,505,513,521,529,537],{"type":33,"tag":96,"props":466,"children":467},{"class":98,"line":99},[468],{"type":33,"tag":96,"props":469,"children":470},{},[471],{"type":38,"value":472},"InputCollect \u003C- robyn_inputs(\n",{"type":33,"tag":96,"props":474,"children":475},{"class":98,"line":108},[476],{"type":33,"tag":96,"props":477,"children":478},{},[479],{"type":38,"value":480},"  dt_input = data,\n",{"type":33,"tag":96,"props":482,"children":483},{"class":98,"line":117},[484],{"type":33,"tag":96,"props":485,"children":486},{},[487],{"type":38,"value":488},"  date_var = \"date\",\n",{"type":33,"tag":96,"props":490,"children":491},{"class":98,"line":126},[492],{"type":33,"tag":96,"props":493,"children":494},{},[495],{"type":38,"value":496},"  dep_var = \"revenue\",\n",{"type":33,"tag":96,"props":498,"children":499},{"class":98,"line":135},[500],{"type":33,"tag":96,"props":501,"children":502},{},[503],{"type":38,"value":504},"  paid_media_spends = c(\"facebook_spend\", \"google_search_spend\", \"display_spend\"),\n",{"type":33,"tag":96,"props":506,"children":507},{"class":98,"line":144},[508],{"type":33,"tag":96,"props":509,"children":510},{},[511],{"type":38,"value":512},"  context_vars = c(\"competitor_index\", \"holiday_flag\"),\n",{"type":33,"tag":96,"props":514,"children":515},{"class":98,"line":153},[516],{"type":33,"tag":96,"props":517,"children":518},{},[519],{"type":38,"value":520},"  window_start = \"2024-01-01\",\n",{"type":33,"tag":96,"props":522,"children":523},{"class":98,"line":27},[524],{"type":33,"tag":96,"props":525,"children":526},{},[527],{"type":38,"value":528},"  window_end = \"2025-12-31\",\n",{"type":33,"tag":96,"props":530,"children":531},{"class":98,"line":170},[532],{"type":33,"tag":96,"props":533,"children":534},{},[535],{"type":38,"value":536},"  adstock = \"geometric\"  # o \"weibull\"\n",{"type":33,"tag":96,"props":538,"children":539},{"class":98,"line":179},[540],{"type":33,"tag":96,"props":541,"children":542},{},[543],{"type":38,"value":185},{"type":33,"tag":34,"props":545,"children":546},{},[547,552],{"type":33,"tag":190,"props":548,"children":549},{},[550],{"type":38,"value":551},"Rangos de hiperparámetros:",{"type":38,"value":553},"\nRobyn busca valores de adstock theta y saturación alpha\u002FK para cada canal dentro del rango especificado. Los rangos por defecto generalmente son suficientes, pero si tienes knowledge del dominio, puedes añadir restricciones:",{"type":33,"tag":85,"props":555,"children":557},{"code":556,"language":88,"meta":17,"className":89,"style":17},"hyperparameters \u003C- list(\n  facebook_spend_alphas = c(0.5, 3),   # pendiente de saturación\n  facebook_spend_gammas = c(0.3, 1),   # inflexión de saturación\n  facebook_spend_thetas = c(0, 0.5)    # adstock decay (geométrico)\n)\n",[558],{"type":33,"tag":92,"props":559,"children":560},{"__ignoreMap":17},[561,569,577,585,593],{"type":33,"tag":96,"props":562,"children":563},{"class":98,"line":99},[564],{"type":33,"tag":96,"props":565,"children":566},{},[567],{"type":38,"value":568},"hyperparameters \u003C- list(\n",{"type":33,"tag":96,"props":570,"children":571},{"class":98,"line":108},[572],{"type":33,"tag":96,"props":573,"children":574},{},[575],{"type":38,"value":576},"  facebook_spend_alphas = c(0.5, 3),   # pendiente de saturación\n",{"type":33,"tag":96,"props":578,"children":579},{"class":98,"line":117},[580],{"type":33,"tag":96,"props":581,"children":582},{},[583],{"type":38,"value":584},"  facebook_spend_gammas = c(0.3, 1),   # inflexión de saturación\n",{"type":33,"tag":96,"props":586,"children":587},{"class":98,"line":126},[588],{"type":33,"tag":96,"props":589,"children":590},{},[591],{"type":38,"value":592},"  facebook_spend_thetas = c(0, 0.5)    # adstock decay (geométrico)\n",{"type":33,"tag":96,"props":594,"children":595},{"class":98,"line":135},[596],{"type":33,"tag":96,"props":597,"children":598},{},[599],{"type":38,"value":185},{"type":33,"tag":34,"props":601,"children":602},{},[603],{"type":38,"value":604},"Ejecución del modelo:",{"type":33,"tag":85,"props":606,"children":608},{"code":607,"language":88,"meta":17,"className":89,"style":17},"OutputModels \u003C- robyn_run(\n  InputCollect = InputCollect,\n  iterations = 2000,     # iteraciones del algoritmo genético\n  trials = 5,            # cuántas seeds aleatorias\n  cores = 4\n)\n",[609],{"type":33,"tag":92,"props":610,"children":611},{"__ignoreMap":17},[612,620,628,636,644,652],{"type":33,"tag":96,"props":613,"children":614},{"class":98,"line":99},[615],{"type":33,"tag":96,"props":616,"children":617},{},[618],{"type":38,"value":619},"OutputModels \u003C- robyn_run(\n",{"type":33,"tag":96,"props":621,"children":622},{"class":98,"line":108},[623],{"type":33,"tag":96,"props":624,"children":625},{},[626],{"type":38,"value":627},"  InputCollect = InputCollect,\n",{"type":33,"tag":96,"props":629,"children":630},{"class":98,"line":117},[631],{"type":33,"tag":96,"props":632,"children":633},{},[634],{"type":38,"value":635},"  iterations = 2000,     # iteraciones del algoritmo genético\n",{"type":33,"tag":96,"props":637,"children":638},{"class":98,"line":126},[639],{"type":33,"tag":96,"props":640,"children":641},{},[642],{"type":38,"value":643},"  trials = 5,            # cuántas seeds aleatorias\n",{"type":33,"tag":96,"props":645,"children":646},{"class":98,"line":135},[647],{"type":33,"tag":96,"props":648,"children":649},{},[650],{"type":38,"value":651},"  cores = 4\n",{"type":33,"tag":96,"props":653,"children":654},{"class":98,"line":144},[655],{"type":33,"tag":96,"props":656,"children":657},{},[658],{"type":38,"value":185},{"type":33,"tag":34,"props":660,"children":661},{},[662],{"type":38,"value":663},"Este paso toma 10–30 minutos (según tamaño de datos). Produce un conjunto Pareto-óptimo de modelos — tradeoff entre NRMSE (calidad de ajuste) y DECOMP.RSSD (suavidad en distribución de contribuciones).",{"type":33,"tag":34,"props":665,"children":666},{},[667,672,674,680,682,688],{"type":33,"tag":190,"props":668,"children":669},{},[670],{"type":38,"value":671},"Selección de modelo:",{"type":38,"value":673}," Robyn sugiere 10–20 modelos Pareto. Elegir el NRMSE más bajo no siempre es correcto — algunos modelos pueden overfitting. Con argumento ",{"type":33,"tag":92,"props":675,"children":677},{"className":676},[],[678],{"type":38,"value":679},"robyn_clusters",{"type":38,"value":681}," en ",{"type":33,"tag":92,"props":683,"children":685},{"className":684},[],[686],{"type":38,"value":687},"robyn_outputs()",{"type":38,"value":689}," puedes agrupar modelos y seleccionar el centro del cluster más estable.",{"type":33,"tag":41,"props":691,"children":693},{"id":692},"validación-holdout-medir-confiabilidad-del-modelo",[694],{"type":38,"value":695},"Validación holdout: medir confiabilidad del modelo",{"type":33,"tag":34,"props":697,"children":698},{},[699],{"type":38,"value":700},"Una de las características más críticas de Robyn es la validación holdout integrada. Mantienes las últimas N semanas fuera del entrenamiento, luego genera predicciones para ese período y compara con valores reales.",{"type":33,"tag":85,"props":702,"children":704},{"code":703,"language":88,"meta":17,"className":89,"style":17},"# Últimas 8 semanas como holdout\nOutputModels \u003C- robyn_run(\n  InputCollect = InputCollect,\n  iterations = 2000,\n  trials = 5,\n  cores = 4,\n  calibration_input = NULL,\n  holdout_periods = 8  # últimas 8 semanas como set de test\n)\n",[705],{"type":33,"tag":92,"props":706,"children":707},{"__ignoreMap":17},[708,716,723,730,738,746,754,762,770],{"type":33,"tag":96,"props":709,"children":710},{"class":98,"line":99},[711],{"type":33,"tag":96,"props":712,"children":713},{},[714],{"type":38,"value":715},"# Últimas 8 semanas como holdout\n",{"type":33,"tag":96,"props":717,"children":718},{"class":98,"line":108},[719],{"type":33,"tag":96,"props":720,"children":721},{},[722],{"type":38,"value":619},{"type":33,"tag":96,"props":724,"children":725},{"class":98,"line":117},[726],{"type":33,"tag":96,"props":727,"children":728},{},[729],{"type":38,"value":627},{"type":33,"tag":96,"props":731,"children":732},{"class":98,"line":126},[733],{"type":33,"tag":96,"props":734,"children":735},{},[736],{"type":38,"value":737},"  iterations = 2000,\n",{"type":33,"tag":96,"props":739,"children":740},{"class":98,"line":135},[741],{"type":33,"tag":96,"props":742,"children":743},{},[744],{"type":38,"value":745},"  trials = 5,\n",{"type":33,"tag":96,"props":747,"children":748},{"class":98,"line":144},[749],{"type":33,"tag":96,"props":750,"children":751},{},[752],{"type":38,"value":753},"  cores = 4,\n",{"type":33,"tag":96,"props":755,"children":756},{"class":98,"line":153},[757],{"type":33,"tag":96,"props":758,"children":759},{},[760],{"type":38,"value":761},"  calibration_input = NULL,\n",{"type":33,"tag":96,"props":763,"children":764},{"class":98,"line":27},[765],{"type":33,"tag":96,"props":766,"children":767},{},[768],{"type":38,"value":769},"  holdout_periods = 8  # últimas 8 semanas como set de test\n",{"type":33,"tag":96,"props":771,"children":772},{"class":98,"line":170},[773],{"type":33,"tag":96,"props":774,"children":775},{},[776],{"type":38,"value":185},{"type":33,"tag":34,"props":778,"children":779},{},[780,782,788],{"type":38,"value":781},"Los resultados holdout aparecen en ",{"type":33,"tag":92,"props":783,"children":785},{"className":784},[],[786],{"type":38,"value":787},"OutputModels$resultHypParam",{"type":38,"value":789},":",{"type":33,"tag":791,"props":792,"children":793},"table",{},[794,823],{"type":33,"tag":795,"props":796,"children":797},"thead",{},[798],{"type":33,"tag":799,"props":800,"children":801},"tr",{},[802,808,813,818],{"type":33,"tag":803,"props":804,"children":805},"th",{},[806],{"type":38,"value":807},"Model ID",{"type":33,"tag":803,"props":809,"children":810},{},[811],{"type":38,"value":812},"Train NRMSE",{"type":33,"tag":803,"props":814,"children":815},{},[816],{"type":38,"value":817},"Holdout MAPE",{"type":33,"tag":803,"props":819,"children":820},{},[821],{"type":38,"value":822},"Holdout NRMSE",{"type":33,"tag":824,"props":825,"children":826},"tbody",{},[827,851],{"type":33,"tag":799,"props":828,"children":829},{},[830,836,841,846],{"type":33,"tag":831,"props":832,"children":833},"td",{},[834],{"type":38,"value":835},"1_123_4",{"type":33,"tag":831,"props":837,"children":838},{},[839],{"type":38,"value":840},"0.08",{"type":33,"tag":831,"props":842,"children":843},{},[844],{"type":38,"value":845},"12.3%",{"type":33,"tag":831,"props":847,"children":848},{},[849],{"type":38,"value":850},"0.14",{"type":33,"tag":799,"props":852,"children":853},{},[854,859,864,869],{"type":33,"tag":831,"props":855,"children":856},{},[857],{"type":38,"value":858},"2_456_1",{"type":33,"tag":831,"props":860,"children":861},{},[862],{"type":38,"value":863},"0.07",{"type":33,"tag":831,"props":865,"children":866},{},[867],{"type":38,"value":868},"18.5%",{"type":33,"tag":831,"props":870,"children":871},{},[872],{"type":38,"value":873},"0.21",{"type":33,"tag":34,"props":875,"children":876},{},[877,882],{"type":33,"tag":190,"props":878,"children":879},{},[880],{"type":38,"value":881},"Holdout MAPE \u003C 15%",{"type":38,"value":883}," generalmente se considera listo para producción. Por encima de 20% indica que el modelo tiene poder de forecast débil — o hay problema de calidad de datos o los rangos de hiperparámetros son demasiado amplios.",{"type":33,"tag":34,"props":885,"children":886},{},[887,892],{"type":33,"tag":190,"props":888,"children":889},{},[890],{"type":38,"value":891},"Trampa práctica:",{"type":38,"value":893}," Si el período holdout contiene un evento outlier (outage de plataforma, campaña viral), el modelo no puede predecirlo y MAPE se dispara. En ese caso, desplaza el período holdout y prueba nuevamente, o marca esa semana como anomalía.",{"type":33,"tag":34,"props":895,"children":896},{},[897,899,906],{"type":38,"value":898},"Un beneficio colateral de validación holdout: oportunidad de cross-check con resultados de pruebas de incrementalidad. Si MMM muestra 30% ROAS para Facebook pero un test geo-split anterior mostró 15%, probablemente MMM esté atribuyendo a Facebook un efecto macroeconómico correlacionado (seasonalidad, trend orgánico). Detectar estas inconsistencias es crítico — por eso en ",{"type":33,"tag":63,"props":900,"children":903},{"href":901,"rel":902},"https:\u002F\u002Fwww.roibase.com.tr\u002Fes\u002Fretention-engineering-cdp",[67],[904],{"type":38,"value":905},"CDP & retention engineering",{"type":38,"value":907}," conectamos MMM output a dashboards de experiments.",{"type":33,"tag":41,"props":909,"children":911},{"id":910},"optimización-de-presupuesto-y-planificación-de-escenarios",[912],{"type":38,"value":913},"Optimización de presupuesto y planificación de escenarios",{"type":33,"tag":34,"props":915,"children":916},{},[917,919,924,926,931],{"type":38,"value":918},"Después de construir el modelo Robyn, hay dos casos de uso principales: ",{"type":33,"tag":190,"props":920,"children":921},{},[922],{"type":38,"value":923},"reasignación de presupuesto",{"type":38,"value":925}," (distribución óptima por canal) y ",{"type":33,"tag":190,"props":927,"children":928},{},[929],{"type":38,"value":930},"what-if scenarios",{"type":38,"value":932}," (qué pasa si aumentamos presupuesto 20%).",{"type":33,"tag":34,"props":934,"children":935},{},[936],{"type":33,"tag":190,"props":937,"children":938},{},[939],{"type":38,"value":940},"Budget allocator:",{"type":33,"tag":85,"props":942,"children":944},{"code":943,"language":88,"meta":17,"className":89,"style":17},"AllocatorCollect \u003C- robyn_allocator(\n  InputCollect = InputCollect,\n  OutputCollect = OutputModels,\n  select_model = \"1_123_4\",  # modelo Pareto seleccionado\n  scenario = \"max_response\",  # o \"target_efficiency\"\n  channel_constr_low = 0.7,   # cada canal min 70% presupuesto actual\n  channel_constr_up = 1.5     # máx 150%\n)\n",[945],{"type":33,"tag":92,"props":946,"children":947},{"__ignoreMap":17},[948,956,963,971,979,987,995,1003],{"type":33,"tag":96,"props":949,"children":950},{"class":98,"line":99},[951],{"type":33,"tag":96,"props":952,"children":953},{},[954],{"type":38,"value":955},"AllocatorCollect \u003C- robyn_allocator(\n",{"type":33,"tag":96,"props":957,"children":958},{"class":98,"line":108},[959],{"type":33,"tag":96,"props":960,"children":961},{},[962],{"type":38,"value":627},{"type":33,"tag":96,"props":964,"children":965},{"class":98,"line":117},[966],{"type":33,"tag":96,"props":967,"children":968},{},[969],{"type":38,"value":970},"  OutputCollect = OutputModels,\n",{"type":33,"tag":96,"props":972,"children":973},{"class":98,"line":126},[974],{"type":33,"tag":96,"props":975,"children":976},{},[977],{"type":38,"value":978},"  select_model = \"1_123_4\",  # modelo Pareto seleccionado\n",{"type":33,"tag":96,"props":980,"children":981},{"class":98,"line":135},[982],{"type":33,"tag":96,"props":983,"children":984},{},[985],{"type":38,"value":986},"  scenario = \"max_response\",  # o \"target_efficiency\"\n",{"type":33,"tag":96,"props":988,"children":989},{"class":98,"line":144},[990],{"type":33,"tag":96,"props":991,"children":992},{},[993],{"type":38,"value":994},"  channel_constr_low = 0.7,   # cada canal min 70% presupuesto actual\n",{"type":33,"tag":96,"props":996,"children":997},{"class":98,"line":153},[998],{"type":33,"tag":96,"props":999,"children":1000},{},[1001],{"type":38,"value":1002},"  channel_constr_up = 1.5     # máx 150%\n",{"type":33,"tag":96,"props":1004,"children":1005},{"class":98,"line":27},[1006],{"type":33,"tag":96,"props":1007,"children":1008},{},[1009],{"type":38,"value":185},{"type":33,"tag":34,"props":1011,"children":1012},{},[1013],{"type":38,"value":1014},"Salida: presupuesto recomendado por canal y revenue incremental esperado:",{"type":33,"tag":791,"props":1016,"children":1017},{},[1018,1049],{"type":33,"tag":795,"props":1019,"children":1020},{},[1021],{"type":33,"tag":799,"props":1022,"children":1023},{},[1024,1029,1034,1039,1044],{"type":33,"tag":803,"props":1025,"children":1026},{},[1027],{"type":38,"value":1028},"Canal",{"type":33,"tag":803,"props":1030,"children":1031},{},[1032],{"type":38,"value":1033},"Actual",{"type":33,"tag":803,"props":1035,"children":1036},{},[1037],{"type":38,"value":1038},"Recomendado",{"type":33,"tag":803,"props":1040,"children":1041},{},[1042],{"type":38,"value":1043},"Delta",{"type":33,"tag":803,"props":1045,"children":1046},{},[1047],{"type":38,"value":1048},"Revenue Incremental",{"type":33,"tag":824,"props":1050,"children":1051},{},[1052,1080,1108],{"type":33,"tag":799,"props":1053,"children":1054},{},[1055,1060,1065,1070,1075],{"type":33,"tag":831,"props":1056,"children":1057},{},[1058],{"type":38,"value":1059},"Facebook",{"type":33,"tag":831,"props":1061,"children":1062},{},[1063],{"type":38,"value":1064},"€5K",{"type":33,"tag":831,"props":1066,"children":1067},{},[1068],{"type":38,"value":1069},"€4.2K",{"type":33,"tag":831,"props":1071,"children":1072},{},[1073],{"type":38,"value":1074},"-16%",{"type":33,"tag":831,"props":1076,"children":1077},{},[1078],{"type":38,"value":1079},"-€800",{"type":33,"tag":799,"props":1081,"children":1082},{},[1083,1088,1093,1098,1103],{"type":33,"tag":831,"props":1084,"children":1085},{},[1086],{"type":38,"value":1087},"Google Search",{"type":33,"tag":831,"props":1089,"children":1090},{},[1091],{"type":38,"value":1092},"€7K",{"type":33,"tag":831,"props":1094,"children":1095},{},[1096],{"type":38,"value":1097},"€9.1K",{"type":33,"tag":831,"props":1099,"children":1100},{},[1101],{"type":38,"value":1102},"+30%",{"type":33,"tag":831,"props":1104,"children":1105},{},[1106],{"type":38,"value":1107},"+€3.2K",{"type":33,"tag":799,"props":1109,"children":1110},{},[1111,1116,1121,1126,1131],{"type":33,"tag":831,"props":1112,"children":1113},{},[1114],{"type":38,"value":1115},"Display",{"type":33,"tag":831,"props":1117,"children":1118},{},[1119],{"type":38,"value":1120},"€3K",{"type":33,"tag":831,"props":1122,"children":1123},{},[1124],{"type":38,"value":1125},"€2.7K",{"type":33,"tag":831,"props":1127,"children":1128},{},[1129],{"type":38,"value":1130},"-10%",{"type":33,"tag":831,"props":1132,"children":1133},{},[1134],{"type":38,"value":1135},"-€200",{"type":33,"tag":34,"props":1137,"children":1138},{},[1139],{"type":38,"value":1140},"Esta tabla dice: \"si asignas 30% más presupuesto a Google Search y reduces Facebook 16%, puedes incrementar revenue total €2.2K\". Los parámetros de restricción (low\u002Fup) previenen cambios radicales — en práctica, cortar un canal 50% en una noche conlleva riesgo operacional.",{"type":33,"tag":34,"props":1142,"children":1143},{},[1144,1149,1151,1157],{"type":33,"tag":190,"props":1145,"children":1146},{},[1147],{"type":38,"value":1148},"Planificación de escenarios:",{"type":38,"value":1150}," Con parámetro ",{"type":33,"tag":92,"props":1152,"children":1154},{"className":1153},[],[1155],{"type":38,"value":1156},"expected_spend",{"type":38,"value":1158}," puedes variar presupuesto total y obtener la distribución óptima para ese escenario. Ejemplo: si presupuesto Q4 aumenta 25%, Robyn te da el breakdown de canales para ese scenario.",{"type":33,"tag":34,"props":1160,"children":1161},{},[1162],{"type":38,"value":1163},"En proyectos Roibase, exportamos MMM output automáticamente a Google Sheets o Looker Studio — el CMO ve recomendaciones en vivo en reuniones de presupuesto semanal. Exportación JSON:",{"type":33,"tag":85,"props":1165,"children":1167},{"code":1166,"language":88,"meta":17,"className":89,"style":17},"robyn_write(InputCollect, OutputModels, select_model = \"1_123_4\", export = TRUE)\n",[1168],{"type":33,"tag":92,"props":1169,"children":1170},{"__ignoreMap":17},[1171],{"type":33,"tag":96,"props":1172,"children":1173},{"class":98,"line":99},[1174],{"type":33,"tag":96,"props":1175,"children":1176},{},[1177],{"type":38,"value":1166},{"type":33,"tag":34,"props":1179,"children":1180},{},[1181,1183,1189],{"type":38,"value":1182},"Genera archivo ",{"type":33,"tag":92,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":38,"value":1188},"Robyn_[timestamp].json",{"type":38,"value":1190}," con todos los hiperparámetros, coeficientes y datos de response curve. Puedes leerlo con script Python y crear notificaciones Slack o reportes por email.",{"type":33,"tag":41,"props":1192,"children":1194},{"id":1193},"refresh-del-modelo-y-versionado",[1195],{"type":38,"value":1196},"Refresh del modelo y versionado",{"type":33,"tag":34,"props":1198,"children":1199},{},[1200],{"type":38,"value":1201},"MMM no es estático — debes refresh cada trimestre con nuevos datos. Robyn tiene capacidad \"warm start\": usar hiperparámetros del modelo anterior como seed y fine-tune solo con datos nuevos.",{"type":33,"tag":85,"props":1203,"children":1205},{"code":1204,"language":88,"meta":17,"className":89,"style":17},"# Cargar modelo anterior\nInputCollectRefresh \u003C- robyn_refresh(\n  json_file = \"Robyn_2025Q4.json\",\n  dt_input = new_data,  # datos últimos 3 meses\n  refresh_steps = 1000\n)\n",[1206],{"type":33,"tag":92,"props":1207,"children":1208},{"__ignoreMap":17},[1209,1217,1225,1233,1241,1249],{"type":33,"tag":96,"props":1210,"children":1211},{"class":98,"line":99},[1212],{"type":33,"tag":96,"props":1213,"children":1214},{},[1215],{"type":38,"value":1216},"# Cargar modelo anterior\n",{"type":33,"tag":96,"props":1218,"children":1219},{"class":98,"line":108},[1220],{"type":33,"tag":96,"props":1221,"children":1222},{},[1223],{"type":38,"value":1224},"InputCollectRefresh \u003C- robyn_refresh(\n",{"type":33,"tag":96,"props":1226,"children":1227},{"class":98,"line":117},[1228],{"type":33,"tag":96,"props":1229,"children":1230},{},[1231],{"type":38,"value":1232},"  json_file = \"Robyn_2025Q4.json\",\n",{"type":33,"tag":96,"props":1234,"children":1235},{"class":98,"line":126},[1236],{"type":33,"tag":96,"props":1237,"children":1238},{},[1239],{"type":38,"value":1240},"  dt_input = new_data,  # datos últimos 3 meses\n",{"type":33,"tag":96,"props":1242,"children":1243},{"class":98,"line":135},[1244],{"type":33,"tag":96,"props":1245,"children":1246},{},[1247],{"type":38,"value":1248},"  refresh_steps = 1000\n",{"type":33,"tag":96,"props":1250,"children":1251},{"class":98,"line":144},[1252],{"type":33,"tag":96,"props":1253,"children":1254},{},[1255],{"type":38,"value":185},{"type":33,"tag":34,"props":1257,"children":1258},{},[1259],{"type":38,"value":1260},"Este approach reduce tiempo de convergencia 60% y minimiza coefficient drift — Facebook's saturasyon curve no cambia 50% de la noche a la mañana, la transición es smooth.",{"type":33,"tag":34,"props":1262,"children":1263},{},[1264,1269],{"type":33,"tag":190,"props":1265,"children":1266},{},[1267],{"type":38,"value":1268},"Best practice de versionado:",{"type":38,"value":1270}," En cada refresh, commit el JSON a Git o sube a S3 con timestamp. Así, 6 meses después puedes responder \"por qué asignamos menos presupuesto a Google en ese período\" consultando model history. En nuestro",{"type":33,"tag":1272,"props":1273,"children":1274},"style",{},[1275],{"type":38,"value":1276},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":17,"searchDepth":117,"depth":117,"links":1278},[1279,1280,1281,1285,1286,1287,1288],{"id":43,"depth":108,"text":46},{"id":75,"depth":108,"text":78},{"id":266,"depth":108,"text":269,"children":1282},[1283,1284],{"id":278,"depth":117,"text":281},{"id":354,"depth":117,"text":357},{"id":413,"depth":108,"text":416},{"id":692,"depth":108,"text":695},{"id":910,"depth":108,"text":913},{"id":1193,"depth":108,"text":1196},"markdown","content:es:data:marketing-mix-modeling-configuracion-practica-robyn.md","content","es\u002Fdata\u002Fmarketing-mix-modeling-configuracion-practica-robyn.md","es\u002Fdata\u002Fmarketing-mix-modeling-configuracion-practica-robyn","md",1785247481464]