Métricas de Quantil em Teste A/B: mediana e p90
Métricas de quantil como p90 de tempo de carregamento quebram a fórmula padrão. Por que a leitura ingênua deu 31% de falso positivo e como ler direito.

📚 Este artigo faz parte do guia Significância Estatística em Teste A/B: O Guia.
Quando a métrica é um percentil e não uma média, a fórmula padrão de erro-padrão para de valer, porque ela assume que cada observação é independente e pageviews do mesmo usuário não são. O preço é medível: na simulação deste artigo, a leitura ingênua de um quantil produziu resultado significante em 31,20 por cento dos testes A/A no p50 e em 28,13 por cento no p90, contra um alvo nominal de 5 por cento. Não é um detalhe teórico, é a diferença entre publicar uma otimização de desempenho que existe e publicar uma que nunca existiu. Este guia mostra por que a média não serve para desempenho, o que exatamente quebra na conta, como corrigir com bootstrap na unidade certa, e qual é o proxy barato quando bootstrap não é viável. Faz parte do nosso guia completo de teste A/B e complementa métricas de razão e tamanho de amostra para métricas contínuas.
Métricas de quantil: por que desempenho não se mede pela média
O time de experimentação do LinkedIn abre o artigo deles sobre o assunto com um exemplo hipotético que resolve a discussão em duas frases. Imagine dois sites com exatamente o mesmo tempo médio de carregamento de 0,5 segundo. O site A carrega todas as páginas em 0,5 segundo. O site B carrega 10 por cento das páginas em 5 segundos e os outros 90 por cento em 0 segundo.
A média é idêntica. A experiência não é: o site A é percebido como rápido porque toda página carrega num piscar de olhos, e o site B é percebido como lento porque o usuário frequentemente precisa esperar 5 segundos antes de a página aparecer. A conclusão dos autores é direta: para otimizar a experiência de velocidade é preciso reduzir o tempo dos carregamentos mais lentos, e não reduzir a média deixando as páginas rápidas ainda mais rápidas.
Rodando os quantis desse mesmo exemplo, a diferença aparece na hora:
| site | média | p50 | p95 |
|---|---|---|---|
| A: todas as páginas em 0,5 s | 0,50 s | 0,50 s | 0,50 s |
| B: 10% em 5 s, 90% em 0 s | 0,50 s | 0,00 s | 5,00 s |
O p50 e o p95 separam completamente os dois sites que a média declara empatados. (O p90 do site B cai exatamente na fronteira entre o grupo rápido e o lento, então ele é justamente o percentil que não distingue os dois neste exemplo específico: escolher o percentil certo faz parte do trabalho.) Segundo o LinkedIn, o padrão da indústria para medir tempo de carregamento é o quantil, com o p90 monitorando a cauda como métrica final a otimizar e o p50 monitorando o desempenho geral. Antes de a plataforma deles suportar quantis, o tempo médio era usado como substituto do p50, e não existia substituto nenhum para o p90.
O que exatamente quebra na conta
Existe uma fórmula assintótica clássica para o erro-padrão de um quantil amostral. Ela funciona, e funciona bem, sob uma condição: as observações precisam ser independentes e igualmente distribuídas.
Num teste A/B de desempenho, essa condição é falsa por construção. Você sorteia usuários, e cada usuário gera vários pageviews. Como os autores do LinkedIn colocam, tempos de carregamento do mesmo membro tendem a ser positivamente correlacionados, porque pageviews de um membro com aparelho e rede rápidos provavelmente serão todos mais rápidos, e vice-versa.
O resultado é conhecido e grande. O LinkedIn mediu contra o bootstrap, que eles tratam como referência por ser não viesado, e encontrou uma subestimação mediana de 74 por cento no desvio-padrão do quantil. A consequência que eles publicam é direta: quando o valor-p estimado é 0,05, o valor-p verdadeiro é na realidade 0,61, o que infla a taxa de falso positivo em 12 vezes e expõe o experimentador a 61 por cento de falsos positivos quando a taxa nominal é de 5 por cento.
O preço, medido numa simulação reproduzível
Reproduzimos o fenômeno num cenário controlado, para poder mostrar as duas contas lado a lado. O desenho: 6.000 usuários por braço; cada usuário tem um efeito persistente próprio (o aparelho e a rede dele) somado a um ruído por pageview; o número de pageviews por usuário é aleatório, com média perto de 5. Isso produziu 26.755 pageviews no controle e 26.729 na variação.
Primeiro, o teste A/A. Geramos os dois braços exatamente da mesma distribuição e lemos o quantil com a fórmula assintótica sob independência. Qualquer resultado significante aqui é falso positivo:
| quantil | falso positivo real da leitura ingênua | alvo nominal | réplicas A/A |
|---|---|---|---|
| p50 | 31,20% | 5% | 3.000 |
| p90 | 28,13% | 5% | 3.000 |
Seis vezes o nível prometido na mediana. A magnitude ficou abaixo dos 61 por cento que o LinkedIn observa em dados reais, o que é esperado: a correlação intra-usuário do nosso cenário simulado é mais fraca que a de tempos de carregamento reais. O sinal e a ordem de grandeza são os mesmos.
Depois, o teste A/B propriamente dito, com um deslocamento pequeno introduzido na variação:
| quantil | diferença observada | erro-padrão ingênuo | valor-p ingênuo | erro-padrão por bootstrap de usuário | valor-p correto | subestimação |
|---|---|---|---|---|---|---|
| p50 | mais 0,0485 s | 0,01092 | 0,00001 | 0,02058 | 0,01856 | 47,0% |
| p90 | mais 0,1259 s | 0,03656 | 0,00057 | 0,05878 | 0,03216 | 37,8% |
Nos dois casos o efeito é real e as duas contas concordam sobre o veredito. O que muda é a confiança declarada. No p50, a conta ingênua reporta um valor-p de 0,00001, o tipo de número que numa reunião vira “praticamente impossível ser acaso”. A conta correta reporta 0,01856, que é significante mas modesto. O intervalo de 95 por cento correto vai de 0,0086 a 0,0899 segundo, enquanto o ingênuo vai de 0,0271 a 0,0698. A leitura ingênua não só declara mais certeza do que tem, como declara um efeito mais preciso do que mediu.
O jeito certo: bootstrap na unidade de sorteio
A correção não é sofisticada, ela é conceitual: reamostre na mesma unidade em que você sorteou. Como o LinkedIn descreve o procedimento, a reamostragem precisa acontecer no nível do membro para preservar a estrutura de dependência, porque tempos de carregamento do mesmo membro não são necessariamente independentes, mas membros são independentes entre si.
Na prática:
// Bootstrap do quantil no nivel do usuario sorteado.
// usuarios = array de arrays; cada elemento reune TODOS os eventos de um 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 inteiro, com reposicao
for (const x of u) amostra.push(x); // todos os eventos dele junto
}
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))],
};
}
O erro comum e caríssimo é reamostrar pageviews individuais com reposição em vez de usuários. Isso quebra a dependência do mesmo jeito que a fórmula i.i.d. quebra, e devolve exatamente o erro-padrão pequeno demais que você estava tentando evitar. O bootstrap não conserta nada sozinho: o que conserta é reamostrar na unidade certa. É o mesmo princípio que descrevemos em unidade de sorteio.
Para o valor-p, o companheiro natural é o teste de permutação, embaralhando usuários inteiros entre os dois braços. A diferença entre quantis não tem fórmula fechada confortável, e a dupla permutação para o valor-p e bootstrap para o intervalo cobre os dois lados.
A armadilha do intervalo livre de distribuição
Existe uma construção elegante e antiga para o intervalo de confiança de um quantil que não assume normalidade nem forma nenhuma: o intervalo pelas estatísticas de ordem. Você calcula quais posições da amostra ordenada delimitam o quantil com a confiança desejada, usando a distribuição binomial, e lê os valores dessas posições. A Spotify registra que esse tipo de intervalo exato e livre de distribuição para quantis populacionais é conhecido há muito tempo e pode ser construído usando apenas estatísticas de ordem.
Aplicando ao braço de controle do nosso exemplo:
| quantil | intervalo de 95% pelas estatísticas de ordem | posições usadas |
|---|---|---|
| p50 | de 1,3989 a 1,4260 s | 13.217 e 13.539 de 26.755 |
| p90 | de 3,4618 a 3,5503 s | 23.983 e 24.177 de 26.755 |
A meia largura do intervalo do p50 aqui é 0,0136 segundo, quase exatamente 1,96 vezes o erro-padrão ingênuo de 0,00717 segundo. Ou seja: o intervalo livre de distribuição reproduz o intervalo ingênuo, porque ele também assume independência. Ele dispensa a suposição de normalidade e mantém intacta a suposição que está errada no seu caso.
Vale registrar a limitação prática que a Spotify aponta junto: esses intervalos por estatística de ordem destravam o caso de uma amostra só para amostras enormes, mas não se estendem diretamente ao caso de duas amostras, que é a diferença entre quantis, que é justamente o que um teste A/B precisa.
Quando bootstrap não cabe no orçamento
O bootstrap é caro. A Spotify quantifica: a complexidade do algoritmo de bootstrap de Poisson é da ordem do produto entre o custo do estimador e o número de reamostragens, e como estimadores de quantil se baseiam em estatísticas de ordem, o custo por reamostragem já é linear no tamanho da amostra. Multiplique por mil reamostragens e por centenas de milhões de observações e a conta deixa de fechar.
As duas soluções publicadas atacam o custo, não a validade:
- LinkedIn, expressão assintótica em forma fechada. Eles derivam a distribuição assintótica do quantil amostral sem a suposição i.i.d., exigindo apenas que tempos de carregamento de membros diferentes sejam independentes, o que é verdade sempre que o membro é a unidade de sorteio. O resultado, validado em 242 experimentos reais com populações, janelas de data, plataformas e quantis diferentes: mais de 500 vezes mais rápido que o bootstrap, com apenas 2 por cento de chance de a estimativa de desvio-padrão divergir da do bootstrap e, quando diverge, diferença abaixo de 7 por cento. A taxa real de falso positivo resultante fica em no máximo 5,1 por cento quando a nominal é 5 por cento.
- Spotify, bootstrap de Poisson sem reamostragem. Eles usam as propriedades da distribuição de Poisson e dos estimadores de quantil baseados em estatísticas de ordem para derivar algoritmos que produzem o mesmo intervalo sem executar as reamostragens, e sem suposições adicionais. Os autores registram que isso destravou o cálculo de intervalos de bootstrap para quantis e para diferenças entre quantis em testes A/B com centenas de milhões de observações.
Se você não tem escala de LinkedIn nem de Spotify, a boa notícia é que o bootstrap simples resolve o seu caso. Alguns milhares de usuários e mil reamostragens rodam em segundos, como rodaram para gerar as tabelas deste artigo.
O proxy binário, quando nada disso cabe
A saída mais barata de todas troca o quantil por um indicador por usuário: em vez de “p90 do tempo de carregamento”, medir “usuário que teve pelo menos um carregamento acima de 3 segundos”. Isso resolve o problema da dependência de raiz, porque passa a existir uma observação por usuário sorteado, e devolve o problema para a conta de duas proporções, que toda ferramenta faz.
Teste z bilateral de duas proporções. "Sem significância" quase sempre quer dizer que falta amostra, não que as versões são iguais.
No nosso cenário, 1.796 dos 6.000 usuários do controle tiveram ao menos um carregamento acima de 3 segundos (29,933 por cento), contra 1.925 dos 6.000 da variação (32,083 por cento). Colando esses quatro números na calculadora acima: z de 2,5460, valor-p de 0,01090, diferença de 2,1500 pontos percentuais e intervalo de 95 por cento de 0,4953 a 3,8047 pontos percentuais.
O que você ganha: uma conta correta, com fórmula fechada, sem bootstrap e sem risco de subestimar erro-padrão. O que você perde: o tamanho do efeito em milissegundos. O proxy diz que a proporção de usuários afetados subiu 2,15 pontos, e não diz que o p90 subiu 126 milissegundos. Para uma métrica de guardrail, em que a pergunta é binária (“piorou o suficiente para eu abortar?”), o proxy costuma ser suficiente, e é assim que ele aparece na nossa peça sobre métricas de guardrail. Para uma métrica de sucesso de um projeto de performance, em que a pergunta é “quanto melhorou”, ele não serve.
Uma armadilha do proxy: o limiar tem que ser escolhido antes de olhar os dados. Testar 2, 3 e 5 segundos e reportar o que deu significante é um problema de múltiplas métricas disfarçado de escolha técnica.
Checklist
- Escolha o quantil pelo que a métrica precisa mostrar, não por hábito. p50 para desempenho geral, p90 ou p95 para a cauda.
- Nunca leia um quantil com a fórmula assintótica i.i.d. se a unidade de sorteio for o usuário e a unidade de medida for o pageview.
- Bootstrap reamostrando usuários inteiros, com todos os eventos deles juntos. Mil reamostragens já dão uma estimativa estável.
- Desconfie do intervalo por estatística de ordem. Livre de distribuição não é livre de dependência.
- Rode um A/A antes de confiar no pipeline de quantis. Se ele der significante muito mais que 5 por cento das vezes, a conta está errada, não o produto.
- Se não puder bootstrapar, use o proxy binário por usuário, com limiar declarado antes de olhar os dados.
- Ao publicar, diga qual conta você usou. Um p90 com valor-p sem método declarado é um número sem procedência.
Faça isso automático na Donnu
O motivo pelo qual quase nenhuma ferramenta de teste A/B reporta quantis não é falta de interesse, é a arquitetura: para calcular um quantil corretamente você precisa manter os eventos ligados ao usuário que os gerou, e a maior parte das plataformas agrega tudo em contadores no momento da coleta. Depois de agregar, a informação necessária já não existe.
A Donnu mantém o evento ligado ao usuário sorteado, que é a condição para reamostrar na unidade certa e para o proxy binário por usuário sair correto sem gambiarra. Se o seu projeto atual é de desempenho e a sua ferramenta só reporta média, o passo imediato e barato é montar o indicador binário por usuário e rodar a calculadora de valor-p com ele, em vez de comparar médias que escondem a cauda.
Referências
- Liu, M., Sun, X., Varshney, M. e Xu, Y. Large-Scale Online Experimentation with Quantile Metrics. arXiv 1903.08762, 2019. Fonte do exemplo dos dois sites com 0,5 segundo de média e experiências opostas; do registro de que o padrão da indústria para tempo de carregamento é o quantil, com p90 monitorando a cauda e p50 o desempenho geral, e de que antes desse trabalho não havia substituto para o p90; da constatação de que o bootstrap é estatisticamente válido mas leva dias, enquanto a estimativa assintótica sob independência é escalável e subestima a variância em ordem de grandeza; da subestimação mediana de 74 por cento do desvio-padrão, com valor-p estimado de 0,05 correspondendo a valor-p verdadeiro de 0,61, inflando o falso positivo em 12 vezes e chegando a 61 por cento quando o nominal é 5 por cento; da exigência de que a reamostragem no bootstrap aconteça no nível do membro para preservar a dependência; e dos resultados do método proposto (mais de 500 vezes mais rápido que o bootstrap, 2 por cento de chance de divergir, diferença abaixo de 7 por cento quando diverge, falso positivo real de no máximo 5,1 por cento, validado em 242 experimentos reais). arxiv.org.
- Schultzberg, M. e Ankargren, S. Resampling-free bootstrap inference for quantiles. arXiv 2202.10992, Spotify Experimentation Platform Team, março de 2022. Fonte do enquadramento de que a natureza computacionalmente intensiva do bootstrap tornava a inferência inviável em experimentos de larga escala; da complexidade do bootstrap de Poisson ser da ordem do produto entre o custo do estimador e o número de reamostragens, com estimadores de quantil sendo lineares no tamanho da amostra por dependerem de estatísticas de ordem; do registro de que intervalos exatos e livres de distribuição para quantis populacionais podem ser construídos apenas com estatísticas de ordem, mas não se estendem diretamente ao caso de duas amostras da diferença entre quantis; e do resultado de que os algoritmos sem reamostragem propostos destravaram o cálculo de intervalos para quantis e diferenças entre quantis em testes A/B com centenas de milhões de observações. arxiv.org.
- Kohavi, R., Deng, A., Longbotham, R. e Xu, Y. Seven Rules of Thumb for Web Site Experimenters. KDD 2014. Fonte do enquadramento de que metodologias de experimentação normalmente se apoiam em médias supostamente normais, de que muitas métricas de interesse em experimentos online são assimétricas e por isso exigem um limite inferior maior de amostra, e da recomendação de recorrer a técnicas de bootstrap para distribuições assimétricas com amostras pequenas. exp-platform.com.
- Deng, A., Knoblich, U. e Lu, J. Applying the Delta Method in Metric Analytics: A Practical Guide with Novel Ideas. KDD 2018. Fonte do contexto de por que plataformas de experimentação em escala perseguem estimadores analíticos de variância para métricas que não são médias simples, e de por que o custo do bootstrap é o obstáculo prático à sua adoção em produção. arxiv.org.
Leia também: Teste de permutação · Métricas de razão · Métricas de contagem · Unidade de sorteio · Métricas de guardrail · Calculadora de valor-p · Read in English
Perguntas frequentes
- O que é uma métrica de quantil em teste A/B?
- É uma métrica definida por uma posição na distribuição em vez de por uma média: a mediana do tempo de carregamento, o percentil 90 da latência, o percentil 95 do tempo de resposta de uma busca. Ela existe porque a média esconde exatamente o que importa em desempenho. O padrão da indústria para medir tempo de carregamento é o quantil, e não a média, segundo o time de experimentação do LinkedIn: o p90 monitora a cauda e é a métrica final a otimizar, enquanto o p50 monitora o desempenho geral.
- Por que a fórmula padrão erra num quantil?
- Porque ela assume que as observações são independentes, e pageviews do mesmo usuário não são. Quem tem aparelho e rede rápidos carrega tudo rápido; quem tem aparelho lento carrega tudo devagar. O erro-padrão calculado sob independência sai pequeno demais. Na simulação deste artigo ele saiu 47 por cento menor que o correto no p50 e 37,8 por cento menor no p90, e a taxa real de falso positivo em testes A/A foi de 31,20 por cento no p50, contra um alvo nominal de 5 por cento.
- Como calcular o intervalo de confiança de um quantil corretamente?
- Com bootstrap reamostrando no nível da unidade de sorteio. Se você sorteou usuários, cada reamostragem sorteia usuários inteiros com reposição, junta todos os pageviews deles e recalcula o quantil. Repita algumas centenas ou milhares de vezes e use o desvio-padrão dessas estimativas como erro-padrão, ou os percentis 2,5 e 97,5 como intervalo. Foi esse procedimento que devolveu erro-padrão de 0,02058 segundo no p50 do exemplo, contra 0,01092 da conta ingênua.
- O bootstrap não é lento demais para dados de verdade?
- É, e por isso as duas grandes soluções publicadas atacam o custo, não a validade. O LinkedIn derivou uma expressão assintótica em forma fechada que não exige reamostragem, com ganho de mais de 500 vezes em velocidade contra o bootstrap e apenas 2 por cento de chance de divergir dele; quando diverge, a diferença fica abaixo de 7 por cento. A Spotify seguiu outro caminho, explorando as propriedades do bootstrap de Poisson para derivar algoritmos sem reamostragem, o que permitiu calcular intervalos de diferença entre quantis em testes A/B com centenas de milhões de observações.
- O intervalo por estatística de ordem resolve o problema?
- Não, e essa é a armadilha. O intervalo construído a partir das estatísticas de ordem é livre de distribuição, ou seja, não assume normalidade nem forma nenhuma para os dados. Mas ele continua assumindo independência entre as observações. No exemplo deste artigo ele devolveu para o p50 um intervalo de 1,3989 a 1,4260 segundo, praticamente idêntico ao da fórmula assintótica ingênua e quase metade da largura correta. Livre de distribuição não é livre de dependência.
- Existe uma saída simples quando não dá para rodar bootstrap?
- Sim: troque o quantil por um indicador binário por usuário, do tipo "usuário que teve pelo menos um carregamento acima de 3 segundos". Isso devolve uma proporção com uma observação por usuário sorteado, que a calculadora de significância padrão resolve corretamente. No exemplo deste artigo o proxy foi de 29,933 por cento no controle para 32,083 por cento na variação, com valor-p de 0,01090 e intervalo de 0,4953 a 3,8047 pontos percentuais. O custo é que você deixa de saber de quantos milissegundos foi a piora.