Estadística

Métricas de Cuantil en Test A/B: mediana y p90

Las métricas de cuantil como el p90 de tiempo de carga rompen la fórmula estándar. Por qué la lectura ingenua dio 31% de falso positivo y cómo leerla bien.

Ilustración plana de una larga fila de barras verticales verdes, con una barra en tono ámbar destacada cerca del extremo derecho y una línea fina tocando su parte superior

Cuando la métrica es un percentil y no un promedio, la fórmula estándar de error estándar deja de valer, porque asume que cada observación es independiente y las páginas vistas del mismo usuario no lo son. El precio es medible: en la simulación de este artículo, la lectura ingenua de un cuantil produjo resultado significativo en 31,20 por ciento de los tests A/A en el p50 y en 28,13 por ciento en el p90, contra un objetivo nominal de 5 por ciento. No es un detalle teórico, es la diferencia entre publicar una optimización de rendimiento que existe y publicar una que nunca existió. Esta guía muestra por qué el promedio no sirve para rendimiento, qué se rompe exactamente en la cuenta, cómo corregirlo con bootstrap en la unidad correcta, y cuál es el proxy barato cuando el bootstrap no es viable. Forma parte de nuestra guía completa de test A/B y complementa métricas de ratio y tamaño de muestra para métricas continuas.

Métricas de cuantil: por qué el rendimiento no se mide por el promedio

El equipo de experimentación de LinkedIn abre su artículo sobre el tema con un ejemplo hipotético que resuelve la discusión en dos frases. Imagine dos sitios con exactamente el mismo tiempo promedio de carga de 0,5 segundo. El sitio A carga todas las páginas en 0,5 segundo. El sitio B carga 10 por ciento de las páginas en 5 segundos y el otro 90 por ciento en 0 segundo.

El promedio es idéntico. La experiencia no lo es: el sitio A se percibe como rápido porque toda página carga en un parpadeo, y el sitio B se percibe como lento porque el usuario con frecuencia necesita esperar 5 segundos antes de que la página aparezca. La conclusión de los autores es directa: para optimizar la experiencia de velocidad hay que reducir el tiempo de las cargas más lentas, y no reducir el promedio dejando las páginas rápidas todavía más rápidas.

Corriendo los cuantiles de ese mismo ejemplo, la diferencia aparece de inmediato:

sitio promedio p50 p95
A: todas las páginas en 0,5 s 0,50 s 0,50 s 0,50 s
B: 10% en 5 s, 90% en 0 s 0,50 s 0,00 s 5,00 s

El p50 y el p95 separan por completo los dos sitios que el promedio declara empatados. (El p90 del sitio B cae exactamente en la frontera entre el grupo rápido y el lento, así que es justamente el percentil que no distingue los dos en este ejemplo específico: elegir el percentil correcto forma parte del trabajo.) Según LinkedIn, el estándar de la industria para medir tiempo de carga es el cuantil, con el p90 monitoreando la cola como métrica final a optimizar y el p50 monitoreando el rendimiento general. Antes de que su plataforma soportara cuantiles, el tiempo promedio se usaba como sustituto del p50, y no existía sustituto alguno para el p90.

Qué se rompe exactamente en la cuenta

Existe una fórmula asintótica clásica para el error estándar de un cuantil muestral. Funciona, y funciona bien, bajo una condición: las observaciones necesitan ser independientes e igualmente distribuidas.

En un test A/B de rendimiento, esa condición es falsa por construcción. Usted aleatoriza usuarios, y cada usuario genera varias páginas vistas. Como lo plantean los autores de LinkedIn, los tiempos de carga del mismo miembro tienden a estar positivamente correlacionados, porque las páginas vistas de un miembro con aparato y red rápidos probablemente serán todas más rápidas, y viceversa.

Por qué las páginas vistas del mismo usuario no son independientesDiagrama con cuatro usuarios representados por círculos a la izquierda, cada uno con una franja horizontal de puntos a la derecha que representa sus tiempos de carga. El primer y el tercer usuario, marcados como red rápida, tienen todos sus puntos agrupados a la izquierda de la franja, en la región de los tiempos cortos. El segundo y el cuarto usuario, marcados como red lenta, tienen todos sus puntos agrupados a la derecha, en la región de los tiempos largos. Una anotación debajo dice que sortear páginas vistas individualmente supone que los puntos están esparcidos de forma independiente, lo que la figura contradice.Cada usuario trae un bloque entero de tiempos parecidos entre síred rápidared lentared rápidared lentarápidolentotiempo de cargala fórmula bajo independencia cuenta 26.755 observaciones librescuando la información libre viene de 6.000 usuarios, no de 26.755 páginas vistas
Las páginas vistas de un mismo usuario cargan casi la misma información. Contar cada una como observación independiente infla la cantidad de evidencia disponible.

El resultado es conocido y grande. LinkedIn midió contra el bootstrap, que tratan como referencia por ser insesgado, y encontró una subestimación mediana de 74 por ciento en la desviación estándar del cuantil. La consecuencia que publican es directa: cuando el valor p estimado es 0,05, el valor p verdadero es en realidad 0,61, lo que infla la tasa de falso positivo en 12 veces y expone al experimentador a 61 por ciento de falsos positivos cuando la tasa nominal es de 5 por ciento.

El precio, medido en una simulación reproducible

Reprodujimos el fenómeno en un escenario controlado, para poder mostrar las dos cuentas lado a lado. El diseño: 6.000 usuarios por brazo; cada usuario tiene un efecto persistente propio (su aparato y su red) sumado a un ruido por página vista; el número de páginas vistas por usuario es aleatorio, con promedio cerca de 5. Eso produjo 26.755 páginas vistas en el control y 26.729 en la variación.

Primero, el test A/A. Generamos los dos brazos exactamente de la misma distribución y leímos el cuantil con la fórmula asintótica bajo independencia. Cualquier resultado significativo aquí es falso positivo:

cuantil falso positivo real de la lectura ingenua objetivo nominal réplicas A/A
p50 31,20% 5% 3.000
p90 28,13% 5% 3.000

Seis veces el nivel prometido en la mediana. La magnitud quedó por debajo del 61 por ciento que LinkedIn observa en datos reales, lo que es esperable: la correlación intrausuario de nuestro escenario simulado es más débil que la de tiempos de carga reales. El signo y el orden de magnitud son los mismos.

Después, el test A/B propiamente dicho, con un desplazamiento pequeño introducido en la variación:

cuantil diferencia observada error estándar ingenuo valor p ingenuo error estándar por bootstrap de usuario valor p correcto subestimación
p50 más 0,0485 s 0,01092 0,00001 0,02058 0,01856 47,0%
p90 más 0,1259 s 0,03656 0,00057 0,05878 0,03216 37,8%

En los dos casos el efecto es real y las dos cuentas coinciden sobre el veredicto. Lo que cambia es la confianza declarada. En el p50, la cuenta ingenua reporta un valor p de 0,00001, el tipo de número que en una reunión se convierte en “prácticamente imposible que sea azar”. La cuenta correcta reporta 0,01856, que es significativo pero modesto. El intervalo de 95 por ciento correcto va de 0,0086 a 0,0899 segundo, mientras que el ingenuo va de 0,0271 a 0,0698. La lectura ingenua no solo declara más certeza de la que tiene, sino que declara un efecto más preciso del que midió.

Intervalo de confianza del p50 por la cuenta ingenua y por el bootstrapGráfico de intervalos horizontales. Una línea vertical punteada marca el cero. La barra superior, más corta y oscura, representa el intervalo de 95 por ciento de la cuenta ingenua para la diferencia en el p50, yendo de 0,0271 a 0,0698 segundo. La barra inferior, casi el doble de larga y en tono claro, representa el intervalo del bootstrap por usuario, yendo de 0,0086 a 0,0899 segundo. Un punto marca la diferencia observada de 0,0485 segundo, común a las dos barras. El intervalo del bootstrap llega mucho más cerca del cero.La misma diferencia de 0,0485 s, con dos anchos de incertidumbrecero0,025 s0,050 s0,075 s0,100 singenuo0,02710,0698bootstrap0,00860,0899casi el doble
Intervalo de 95 por ciento de la diferencia en el p50 del tiempo de carga. El bootstrap en la unidad de aleatorización casi duplica el ancho y acerca el límite inferior al cero.

La forma correcta: bootstrap en la unidad de aleatorización

La corrección no es sofisticada, es conceptual: remuestree en la misma unidad en la que usted aleatorizó. Como LinkedIn describe el procedimiento, el remuestreo necesita ocurrir a nivel del miembro para preservar la estructura de dependencia, porque los tiempos de carga del mismo miembro no son necesariamente independientes, pero los miembros sí son independientes entre sí.

En la práctica:

// Bootstrap del cuantil a nivel del usuario aleatorizado.
// usuarios = arreglo de arreglos; cada elemento reune TODOS los eventos de un usuario.
function bootstrapQuantile(usuarios, q, B, rand) {
  const n = usuarios.length;
  const estimativas = new Array(B);
  for (let b = 0; b < B; b++) {
    const amostra = [];
    for (let i = 0; i < n; i++) {
      const u = usuarios[Math.floor(rand() * n)];   // usuario entero, con reposicion
      for (const x of u) amostra.push(x);           // todos sus eventos juntos
    }
    amostra.sort((a, c) => a - c);
    const pos = q * (amostra.length - 1);
    const lo = Math.floor(pos), hi = Math.ceil(pos);
    estimativas[b] = amostra[lo] + (amostra[hi] - amostra[lo]) * (pos - lo);
  }
  estimativas.sort((a, c) => a - c);
  return {
    p025: estimativas[Math.floor(0.025 * (B - 1))],
    p975: estimativas[Math.floor(0.975 * (B - 1))],
  };
}

El error común y carísimo es remuestrear páginas vistas individuales con reposición en vez de usuarios. Eso rompe la dependencia del mismo modo que la rompe la fórmula i.i.d., y devuelve exactamente el error estándar demasiado pequeño que usted estaba tratando de evitar. El bootstrap no corrige nada por sí solo: lo que corrige es remuestrear en la unidad correcta. Es el mismo principio que describimos en unidad de aleatorización.

Para el valor p, el compañero natural es el test de permutación, barajando usuarios enteros entre los dos brazos. La diferencia entre cuantiles no tiene fórmula cerrada cómoda, y la dupla permutación para el valor p y bootstrap para el intervalo cubre los dos lados.

La trampa del intervalo libre de distribución

Existe una construcción elegante y antigua para el intervalo de confianza de un cuantil que no asume normalidad ni forma alguna: el intervalo por estadísticas de orden. Usted calcula qué posiciones de la muestra ordenada delimitan el cuantil con la confianza deseada, usando la distribución binomial, y lee los valores de esas posiciones. Spotify registra que ese tipo de intervalo exacto y libre de distribución para cuantiles poblacionales se conoce desde hace mucho tiempo y puede construirse usando solo estadísticas de orden.

Aplicándolo al brazo de control de nuestro ejemplo:

cuantil intervalo de 95% por las estadísticas de orden posiciones usadas
p50 de 1,3989 a 1,4260 s 13.217 y 13.539 de 26.755
p90 de 3,4618 a 3,5503 s 23.983 y 24.177 de 26.755

El semiancho del intervalo del p50 aquí es 0,0136 segundo, casi exactamente 1,96 veces el error estándar ingenuo de 0,00717 segundo. Es decir: el intervalo libre de distribución reproduce el intervalo ingenuo, porque también asume independencia. Prescinde del supuesto de normalidad y mantiene intacto el supuesto que está equivocado en su caso.

Vale registrar la limitación práctica que Spotify señala junto a eso: esos intervalos por estadísticas de orden destraban el caso de una sola muestra para muestras enormes, pero no se extienden directamente al caso de dos muestras, que es la diferencia entre cuantiles, que es justamente lo que un test A/B necesita.

Cuando el bootstrap no cabe en el presupuesto

El bootstrap es caro. Spotify lo cuantifica: la complejidad del algoritmo de bootstrap de Poisson es del orden del producto entre el costo del estimador y el número de remuestreos, y como los estimadores de cuantil se basan en estadísticas de orden, el costo por remuestreo ya es lineal en el tamaño de la muestra. Multiplique por mil remuestreos y por cientos de millones de observaciones y la cuenta deja de cerrar.

Las dos soluciones publicadas atacan el costo, no la validez:

Si usted no tiene escala de LinkedIn ni de Spotify, la buena noticia es que el bootstrap simple resuelve su caso. Algunos miles de usuarios y mil remuestreos corren en segundos, como corrieron para generar las tablas de este artículo.

El proxy binario, cuando nada de eso cabe

La salida más barata de todas cambia el cuantil por un indicador por usuario: en vez de “p90 del tiempo de carga”, medir “usuario que tuvo al menos una carga por encima de 3 segundos”. Eso resuelve el problema de la dependencia de raíz, porque pasa a existir una observación por usuario aleatorizado, y devuelve el problema a la cuenta de dos proporciones, que toda herramienta hace.

Calculadora de significancia estadística
Control (A)
Variación (B)
Control (A) · Tasa-
Variación (B) · Tasa-
Mejora relativa-
valor-p-
IC 95% de la diferencia-

Test z bilateral de dos proporciones. "Sin significancia" casi siempre significa que falta muestra, no que las versiones sean iguales.

En nuestro escenario, 1.796 de los 6.000 usuarios del control tuvieron al menos una carga por encima de 3 segundos (29,933 por ciento), contra 1.925 de los 6.000 de la variación (32,083 por ciento). Pegando esos cuatro números en la calculadora de arriba: z de 2,5460, valor p de 0,01090, diferencia de 2,1500 puntos porcentuales e intervalo de 95 por ciento de 0,4953 a 3,8047 puntos porcentuales.

Lo que usted gana: una cuenta correcta, con fórmula cerrada, sin bootstrap y sin riesgo de subestimar el error estándar. Lo que pierde: el tamaño del efecto en milisegundos. El proxy dice que la proporción de usuarios afectados subió 2,15 puntos, y no dice que el p90 subió 126 milisegundos. Para una métrica de guardrail, en la que la pregunta es binaria (“¿empeoró lo suficiente como para abortar?”), el proxy suele ser suficiente, y así aparece en nuestra pieza sobre métricas de guardrail. Para una métrica de éxito de un proyecto de rendimiento, en la que la pregunta es “cuánto mejoró”, no sirve.

Una trampa del proxy: el umbral tiene que elegirse antes de mirar los datos. Probar 2, 3 y 5 segundos y reportar el que dio significativo es un problema de múltiples métricas disfrazado de elección técnica.

Checklist

  1. Elija el cuantil por lo que la métrica necesita mostrar, no por costumbre. p50 para rendimiento general, p90 o p95 para la cola.
  2. Nunca lea un cuantil con la fórmula asintótica i.i.d. si la unidad de aleatorización es el usuario y la unidad de medida es la página vista.
  3. Bootstrap remuestreando usuarios enteros, con todos sus eventos juntos. Mil remuestreos ya dan una estimación estable.
  4. Desconfíe del intervalo por estadísticas de orden. Libre de distribución no es libre de dependencia.
  5. Corra un A/A antes de confiar en el pipeline de cuantiles. Si da significativo mucho más de 5 por ciento de las veces, la cuenta está mal, no el producto.
  6. Si no puede hacer bootstrap, use el proxy binario por usuario, con umbral declarado antes de mirar los datos.
  7. Al publicar, diga qué cuenta usó. Un p90 con valor p sin método declarado es un número sin procedencia.

Hágalo automático con Donnu

El motivo por el cual casi ninguna herramienta de test A/B reporta cuantiles no es falta de interés, es la arquitectura: para calcular un cuantil correctamente hay que mantener los eventos ligados al usuario que los generó, y la mayor parte de las plataformas agrega todo en contadores en el momento de la recolección. Después de agregar, la información necesaria ya no existe.

Donnu mantiene el evento ligado al usuario aleatorizado, que es la condición para remuestrear en la unidad correcta y para que el proxy binario por usuario salga correcto sin parches. Si su proyecto actual es de rendimiento y su herramienta solo reporta promedio, el paso inmediato y barato es armar el indicador binario por usuario y correr la calculadora de valor p con él, en vez de comparar promedios que esconden la cola.

Referencias

Lee también: Test de permutación · Métricas de ratio · Métricas de conteo · Unidad de aleatorización · Métricas de guardrail · Calculadora de valor p · Leia em português

Preguntas frecuentes

¿Qué es una métrica de cuantil en un test A/B?
Es una métrica definida por una posición en la distribución en vez de por un promedio: la mediana del tiempo de carga, el percentil 90 de la latencia, el percentil 95 del tiempo de respuesta de una búsqueda. Existe porque el promedio esconde exactamente lo que importa en rendimiento. El estándar de la industria para medir tiempo de carga es el cuantil, y no el promedio, según el equipo de experimentación de LinkedIn: el p90 monitorea la cola y es la métrica final a optimizar, mientras que el p50 monitorea el rendimiento general.
¿Por qué la fórmula estándar se equivoca en un cuantil?
Porque asume que las observaciones son independientes, y las páginas vistas del mismo usuario no lo son. Quien tiene aparato y red rápidos carga todo rápido; quien tiene aparato lento carga todo despacio. El error estándar calculado bajo independencia sale demasiado pequeño. En la simulación de este artículo salió 47 por ciento menor que el correcto en el p50 y 37,8 por ciento menor en el p90, y la tasa real de falso positivo en tests A/A fue de 31,20 por ciento en el p50, contra un objetivo nominal de 5 por ciento.
¿Cómo calcular el intervalo de confianza de un cuantil correctamente?
Con bootstrap remuestreando a nivel de la unidad de aleatorización. Si usted aleatorizó usuarios, cada remuestreo sortea usuarios enteros con reposición, junta todas sus páginas vistas y recalcula el cuantil. Repita algunos cientos o miles de veces y use la desviación estándar de esas estimaciones como error estándar, o los percentiles 2,5 y 97,5 como intervalo. Fue ese procedimiento el que devolvió un error estándar de 0,02058 segundo en el p50 del ejemplo, contra 0,01092 de la cuenta ingenua.
¿El bootstrap no es demasiado lento para datos reales?
Lo es, y por eso las dos grandes soluciones publicadas atacan el costo, no la validez. LinkedIn derivó una expresión asintótica en forma cerrada que no exige remuestreo, con una ganancia de más de 500 veces en velocidad frente al bootstrap y apenas 2 por ciento de probabilidad de divergir de él; cuando diverge, la diferencia queda por debajo de 7 por ciento. Spotify siguió otro camino, explorando las propiedades del bootstrap de Poisson para derivar algoritmos sin remuestreo, lo que permitió calcular intervalos de diferencia entre cuantiles en tests A/B con cientos de millones de observaciones.
¿El intervalo por estadísticas de orden resuelve el problema?
No, y esa es la trampa. El intervalo construido a partir de las estadísticas de orden es libre de distribución, es decir, no asume normalidad ni forma alguna para los datos. Pero sigue asumiendo independencia entre las observaciones. En el ejemplo de este artículo devolvió para el p50 un intervalo de 1,3989 a 1,4260 segundo, prácticamente idéntico al de la fórmula asintótica ingenua y casi la mitad del ancho correcto. Libre de distribución no es libre de dependencia.
¿Existe una salida simple cuando no se puede correr bootstrap?
Sí: cambie el cuantil por un indicador binario por usuario, del tipo "usuario que tuvo al menos una carga por encima de 3 segundos". Eso devuelve una proporción con una observación por usuario aleatorizado, que la calculadora de significancia estándar resuelve correctamente. En el ejemplo de este artículo el proxy pasó de 29,933 por ciento en el control a 32,083 por ciento en la variación, con valor p de 0,01090 e intervalo de 0,4953 a 3,8047 puntos porcentuales. El costo es que usted deja de saber de cuántos milisegundos fue el empeoramiento.