Módulo 7: Sample Size And Pitfalls
La paradoja de Simpson
Descripción
Las lecciones 4 y 5 mostraron dos formas de engañarte a ti mismo por exceso de oportunidades —mirar demasiadas veces, probar demasiadas métricas—. Esta lección presenta una trampa completamente distinta, y en cierto sentido más inquietante: un resultado agregado, calculado sobre una sola métrica primaria, medido una sola vez, al final del experimento, con el tamaño de muestra correcto — y aun así engañoso, porque esconde una historia diferente cuando lo separas por segmentos. Se llama la paradoja de Simpson, y ocurre cuando la tendencia que ves en el total se invierte, o directamente desaparece, al mirar los datos separados por grupos.
El nombre es intimidante, pero el mecanismo es preciso: pasa cuando una tercera variable —un confusor— está correlacionada al mismo tiempo con (a) qué tan bien convierte cada segmento de por sí, y (b) qué proporción de cada grupo experimental (control o variant) proviene de cada segmento. Si esas dos correlaciones se alinean de cierta manera, el promedio agregado de cada grupo puede terminar contando una historia completamente distinta —a veces la opuesta— de lo que pasa dentro de cada segmento individual.
Conexión con el módulo. Esta lección construye simpsonCheck(), la función que vas a reutilizar en el mini-proyecto de la lección 8 para auditar si el lift de +18.75% de recommendations —el mismo de los módulos 5 y 6— se sostiene cuando separas el tráfico por tipo de dispositivo (mobile / desktop). Hoy trabajas con un caso ilustrativo, construido a propósito para mostrar la reversión con toda claridad; el mini-proyecto aplica la misma función a los datos reales del experimento y revisa si ese peligro específico ocurrió ahí.
Una analogía: el medicamento que funciona… y "falla"
Imagina un ensayo clínico donde un medicamento nuevo se prueba contra un placebo. Cuando el equipo mira solo a los pacientes hombres, el medicamento gana claramente: mejora más que el placebo. Cuando mira solo a las pacientes mujeres, el medicamento también gana claramente. Dos subgrupos, dos victorias consistentes para el medicamento. Y sin embargo, cuando el equipo junta a todos los pacientes en un solo número agregado —hombres y mujeres mezclados—, el placebo aparece ganando. ¿Cómo es posible que algo pierda en cada subgrupo por separado, pero gane en el total?
La respuesta está en cómo se mezclaron los grupos, no en el medicamento. Si, por ejemplo, la mayoría de los hombres del ensayo (donde el medicamento funciona muy bien, pero la enfermedad de base es más leve para todos, hombres o mujeres) terminaron en el grupo placebo, y la mayoría de las mujeres (donde la enfermedad de base es más severa en general, medicamento o placebo) terminaron en el grupo tratamiento, el agregado de "tratamiento" queda dominado por los casos más difíciles, y el agregado de "placebo" queda dominado por los casos más leves — no porque el placebo funcione mejor, sino porque la mezcla de pacientes de cada grupo no es comparable. El medicamento sigue siendo, honestamente, mejor en cada subgrupo homogéneo; es el agregado, contaminado por una mezcla desigual, el que miente.
Un A/B test puede sufrir exactamente el mismo fenómeno si la mezcla de tipos de usuario —por ejemplo, mobile contra desktop— termina siendo distinta entre control y variant, ya sea por un error de instrumentación, un bug en la asignación, o simplemente una casualidad del muestreo. El lift agregado que calculaste con abTest() en el módulo 5 puede estar contando una historia distinta de la que cuenta cada segmento por separado — y la única forma de saberlo es, precisamente, revisar los segmentos.
Ejemplo trabajado: simpsonCheck() sobre un caso ilustrativo de Mercado
Construimos un caso pedagógico, diseñado a propósito para mostrar la reversión con claridad — no los datos reales del experimento de recommendations (esos los revisas en el mini-proyecto de la lección 8). Imagina que, por un error en cómo se repartió el tráfico durante el rollout, variant terminó recibiendo mucho más tráfico mobile (un canal que convierte menos en general) que control, que se quedó con mucho más tráfico desktop (un canal que convierte más):
// simpsonCheck: compara el lift agregado (todo el trafico junto) contra el
// lift por segmento, y detecta si hay una reversion (Simpson's paradox) --
// el caso donde variant gana en CADA segmento individual pero pierde en el
// agregado (o viceversa), por como se mezclo el trafico de cada segmento
// entre control y variant.
function simpsonCheck(segments) {
const totals = { control: { n: 0, conversions: 0 }, variant: { n: 0, conversions: 0 } };
const bySegment = {};
for (const [name, seg] of Object.entries(segments)) {
const controlRate = seg.control.conversions / seg.control.n;
const variantRate = seg.variant.conversions / seg.variant.n;
bySegment[name] = { controlRate, variantRate, variantWins: variantRate > controlRate };
totals.control.n += seg.control.n;
totals.control.conversions += seg.control.conversions;
totals.variant.n += seg.variant.n;
totals.variant.conversions += seg.variant.conversions;
}
const aggControlRate = totals.control.conversions / totals.control.n;
const aggVariantRate = totals.variant.conversions / totals.variant.n;
const aggregateVariantWins = aggVariantRate > aggControlRate;
const segmentValues = Object.values(bySegment);
const allSegmentsAgree = segmentValues.every((s) => s.variantWins === segmentValues[0].variantWins);
const reversal = allSegmentsAgree && segmentValues[0].variantWins !== aggregateVariantWins;
return {
bySegment,
aggregate: { controlRate: aggControlRate, variantRate: aggVariantRate, variantWins: aggregateVariantWins },
reversal,
};
}
// Caso ILUSTRATIVO (no son los datos reales del modulo 5): recommendations
// segmentado por dispositivo, con un confusor -- variant quedo con mucho mas
// trafico mobile (canal de menor conversion), control con mucho mas desktop
// (canal de mayor conversion).
const illustrativeCase = {
mobile: {
control: { n: 1000, conversions: 20 }, // 2.00%
variant: { n: 9000, conversions: 189 }, // 2.10%
},
desktop: {
control: { n: 9000, conversions: 450 }, // 5.00%
variant: { n: 1000, conversions: 52 }, // 5.20%
},
};
const result = simpsonCheck(illustrativeCase);
console.log('=== simpsonCheck() -- caso ilustrativo con confusor de dispositivo ===\n');
for (const [name, seg] of Object.entries(result.bySegment)) {
console.log(name + ': control=' + (seg.controlRate * 100).toFixed(2) + '% variant=' +
(seg.variantRate * 100).toFixed(2) + '% variant gana? ' + seg.variantWins);
}
console.log('\nagregado: control=' + (result.aggregate.controlRate * 100).toFixed(2) + '% variant=' +
(result.aggregate.variantRate * 100).toFixed(2) + '% variant gana? ' + result.aggregate.variantWins);
console.log('\nreversal detectado (Simpson): ' + result.reversal);
Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:
=== simpsonCheck() -- caso ilustrativo con confusor de dispositivo ===
mobile: control=2.00% variant=2.10% variant gana? true
desktop: control=5.00% variant=5.20% variant gana? true
agregado: control=4.70% variant=2.41% variant gana? false
reversal detectado (Simpson): true
Mira con atención lo que pasa: en mobile, variant gana (2.10% contra 2.00%). En desktop, variant también gana (5.20% contra 5.00%). Los dos únicos segmentos que existen están de acuerdo: variant es mejor. Y sin embargo, en el agregado, control convierte al 4.70% y variant apenas al 2.41% — una reversión completa, variant perdiendo por más de 2 puntos porcentuales en el número que un reporte descuidado citaría como "el resultado del experimento". ¿Qué pasó? El agregado de control está dominado por desktop (9,000 de sus 10,000 usuarios, el canal que más convierte), mientras que el agregado de variant está dominado por mobile (9,000 de sus 10,000 usuarios, el canal que menos convierte). El agregado no está midiendo "el efecto de recommendations" — está midiendo, mayormente, la diferencia entre mobile y desktop, disfrazada de diferencia entre control y variant.
Por qué esto es una señal de alerta sobre la aleatorización, no solo de los segmentos
El punto más importante de esta lección no es "siempre desconfía del agregado" — es que una reversión de Simpson casi siempre delata un problema de aleatorización, no una propiedad misteriosa de los datos. Si control y variant se asignaron de verdad al azar —la disciplina completa de la lección 4 del módulo 5—, la mezcla de mobile y desktop debería, en promedio, ser prácticamente idéntica en ambos grupos: el azar no tiene ninguna razón para preferir mandar más tráfico mobile a un grupo que al otro. El caso ilustrativo de hoy, con variant en 90% mobile y control en 90% desktop, no es lo que produciría una asignación al azar correctamente implementada — es la clase de desbalance que aparece cuando algo salió mal: un bug en el rollout, una asignación por versión de la app en vez de por usuario, o un error de instrumentación que clasificó mal el tráfico.
Por eso simpsonCheck() cumple una doble función: no solo protege contra reportar un lift agregado engañoso, sino que actúa como una auditoría de la aleatorización misma. Si separas por un segmento razonable —dispositivo, país, tipo de usuario— y encuentras una reversión como la de hoy, la primera pregunta no es "¿qué segmento es el verdadero ganador?" — es "¿por qué la mezcla de este segmento es tan distinta entre control y variant, si se supone que la asignación fue al azar?". El mini-proyecto de la lección 8 aplica exactamente esta auditoría a los datos reales del experimento de recommendations.
Errores comunes
Confiar en el lift agregado sin verificar si la mezcla de segmentos está balanceada entre grupos. Qué pasa: un equipo reporta el lift de checkoutConversionRate calculado con abTest() sobre el total de usuarios, sin revisar nunca si la proporción de mobile/desktop (o cualquier otro segmento relevante) es parecida entre control y variant. Por qué pasa: el agregado es el número más simple de calcular y comunicar, y separar por segmentos se siente como un paso extra opcional, no una verificación necesaria. Cómo detectarlo: nadie en el equipo puede decir, con un número concreto, qué porcentaje de control y de variant es mobile contra desktop. Cómo corregirlo: como hace simpsonCheck() de hoy, siempre revisa la mezcla de al menos un segmento estructuralmente importante (dispositivo, país, tipo de usuario) antes de confiar plenamente en el agregado — es una verificación rápida que puede revelar un desbalance grave, como en el caso ilustrativo de hoy.
Ver un lift agregado positivo y no molestarse en revisar si se sostiene por segmento, "porque ya se ve bien". Qué pasa: el lift agregado de recommendations salió positivo y significativo (módulo 6), y el equipo da el resultado por cerrado, sin correr simpsonCheck() ni ningún corte por segmento, porque "el número que importa ya salió bien". Por qué pasa: revisar los segmentos de un resultado que ya parece favorable se siente como buscarle defectos a algo que no los tiene, en vez de una verificación de rutina. Cómo detectarlo: el análisis del experimento se detiene en el número agregado, sin ningún desglose por segmento en el reporte final. Cómo corregirlo: la verificación por segmentos no es opcional solo cuando el resultado se ve mal — es parte de la disciplina completa de auditar un experimento, sin importar si el agregado favorece o no la hipótesis que esperabas. El mini-proyecto de la lección 8 aplica exactamente esta verificación al resultado real de recommendations, sin importar que ya sepas, de los módulos 5 y 6, que el agregado se ve favorable.
Al encontrar una reversión de Simpson, concluir que "el efecto no es real" en vez de investigar la mezcla. Qué pasa: un equipo encuentra una reversión como la de hoy y concluye, incorrectamente, que recommendations "en realidad no funciona" — descartando el resultado por segmento (donde variant sí gana consistentemente) a favor del agregado (donde parece perder). Por qué pasa: el número agregado se siente más "oficial" o más fácil de comunicar que un desglose por segmentos, y es tentador tratarlo como la verdad final incluso después de encontrar la reversión. Cómo detectarlo: la conclusión del análisis cita el número agregado como definitivo, sin explicar por qué difiere tan drásticamente de cada segmento individual. Cómo corregirlo: cuando encuentras una reversión, el paso correcto no es elegir ciegamente el agregado ni el segmento — es investigar la causa de la reversión (casi siempre, como viste hoy, un problema de mezcla o de aleatorización) y, mientras esa causa no esté resuelta, confiar más en el patrón que se repite de forma consistente en cada segmento individual que en un agregado potencialmente contaminado por un desbalance de mezcla.
Ejercicios
Ejercicio 1 — Detecta la reversión con nuevos números. Un segundo experimento en Mercado (un rediseño del botón de "agregar al carrito") da estos resultados por segmento: newUsers — control: n=2,000, conversions=100 (5.0%); variant: n=8,000, conversions=560 (7.0%). returningUsers — control: n=8,000, conversions=640 (8.0%); variant: n=2,000, conversions=220 (11.0%). Calcula el agregado de control y variant a mano. ¿Hay una reversión de Simpson?
Ver solución
control agregado: (100+640)/(2000+8000) = 740/10000 = 7.4%. variant agregado: (560+220)/(8000+2000) = 780/10000 = 7.8%. En este caso, variant gana en ambos segmentos (newUsers: 7.0% > 5.0%; returningUsers: 11.0% > 8.0%) y en el agregado (7.8% > 7.4%) — no hay reversión. Ejecutar simpsonCheck() con estos datos confirmaría reversal: false. Este ejercicio contrasta a propósito con el ejemplo trabajado de hoy: no toda diferencia de mezcla entre segmentos produce una reversión — solo lo hace cuando la mezcla y las tasas de cada segmento se alinean de una forma específica, como en el caso ilustrativo del dispositivo.
Ejercicio 2 — Explica por qué el Ejercicio 1 no tuvo reversión. A diferencia del ejemplo trabajado de hoy (donde variant tenía 90% de tráfico mobile y control 90% desktop), en el Ejercicio 1 la mezcla también es distinta entre grupos (variant tiene 80% newUsers, control tiene 80% returningUsers). ¿Por qué esa diferencia de mezcla no produjo una reversión esta vez?
Ver solución
Para que ocurra una reversión de Simpson, la mezcla desigual tiene que combinarse con una dirección de efecto que "cancele" el patrón cuando se pondera diferente. En el ejemplo de hoy, control estaba concentrado en el segmento de mayor conversión (desktop, 5%) mientras variant estaba concentrado en el de menor conversión (mobile, 2%) — esa combinación específica es la que invierte el agregado. En el Ejercicio 1, aunque la mezcla también es desigual, variant está concentrado en newUsers (la tasa más baja de los dos segmentos, 5-7%) y su ventaja relativa dentro de ambos segmentos es lo bastante grande como para que, incluso ponderado por esa mezcla desfavorable, siga ganando en el agregado. La lección general: una mezcla desigual entre grupos es una señal de alerta que vale la pena revisar (primer error común de hoy), pero no garantiza por sí sola una reversión — depende de cómo se combinen las tasas y los pesos exactos de cada segmento.
Ejercicio 3 — Diseña la verificación correcta para el equipo de Mercado. Basándote en las tres secciones de esta lección, redacta en 2-3 frases el paso de verificación que el equipo de recommendations debería agregar a su checklist, antes de reportar cualquier lift agregado como el resultado final de un experimento.
Ver solución
Un paso razonable: "Antes de reportar el lift agregado de cualquier experimento, corre simpsonCheck() (o un desglose equivalente) sobre al menos un segmento estructuralmente relevante —dispositivo, país, tipo de usuario—. Si reversal sale true, o si la mezcla de ese segmento es notablemente distinta entre control y variant, no reportes el agregado como definitivo: investiga primero si hubo un problema de aleatorización antes de decidir en qué número confiar." Esto convierte la verificación de segmentos en un paso obligatorio del protocolo, exactamente igual que el balance de randomize() que el módulo 5 ya verificaba antes de confiar en cualquier resultado.
Resumen y siguiente paso
En esta lección viste la paradoja de Simpson: un lift agregado puede mostrar una tendencia —o directamente su opuesta— frente a lo que ocurre en cada segmento individual, cuando un confusor (como el tipo de dispositivo) está desbalanceado entre control y variant. Construiste y ejecutaste simpsonCheck() sobre un caso ilustrativo donde variant ganaba en mobile (2.10% contra 2.00%) y en desktop (5.20% contra 5.00%) pero perdía en el agregado (2.41% contra 4.70%) — una reversión completa causada por una mezcla de tráfico desbalanceada entre los dos grupos. Y viste por qué una reversión así casi siempre es, en el fondo, una señal de alerta sobre la aleatorización misma, no una propiedad misteriosa e inevitable de los datos.
Antes de avanzar deberías poder: explicar con tus propias palabras cómo un confusor puede invertir un resultado agregado; ejecutar simpsonCheck() sobre datos segmentados y leer si hay una reversión; y explicar por qué una reversión de Simpson debería hacerte sospechar primero de la aleatorización, no descartar el efecto directamente.
La lección 7, la última antes del mini-proyecto, cierra el catálogo de trampas con dos más: el efecto novedad —el bump inicial de un lanzamiento que se desinfla con el tiempo, fácil de confundir con un efecto permanente— y el p-hacking —la tentación, más sutil de lo que parece, de ajustar el análisis después de ver los datos hasta que algo salga significativo.
Recursos
- Wikipedia, "Simpson's paradox" — en.wikipedia.org/wiki/Simpson's_paradox. Referencia formal del fenómeno, con varios ejemplos reales documentados —incluyendo el caso célebre de un estudio sobre tratamientos de cálculos renales, muy parecido en estructura al ejemplo del medicamento de esta lección—. En inglés.
- Brilliant.org, "Simpson's Paradox" — brilliant.org/wiki/simpsons-paradox. Una explicación visual e interactiva del fenómeno con un ejemplo numérico simple, útil para reforzar la intuición antes de aplicarla a datos de experimentación real. En inglés.
- Ron Kohavi, Diane Tang y Ya Xu, Trustworthy Online Controlled Experiments: A Practical Guide to A/B Testing — experimentguide.com. El capítulo sobre segmentación cubre cómo detectar y diagnosticar reversiones como la de esta lección en experimentos de producto reales, y por qué casi siempre apuntan a un problema del diseño del experimento. En inglés.