Estatística

Maturidade de Coorte em Teste A/B: ler D7 e D30

Quem entrou ontem não teve 7 dias para ficar. Como a maturidade de coorte distorce retenção D7 e D30, e como fechar a coorte sem perder o teste A/B.

Ilustração plana de seis barras horizontais de comprimentos diferentes começando em pontos escalonados à esquerda, todas cortadas por uma única linha vertical perto da borda direita

Num teste com entrada contínua de tráfego, o usuário que entrou ontem não teve sete dias para ficar, e mesmo assim ele entra na conta de retenção D7 como se tivesse tido. Na simulação deste guia isso derrubou a retenção lida de 29,5404 para 23,2103 por cento, e num cenário com lançamento em rampa chegou a inverter o vencedor: menos 5,99 por cento na leitura ingênua contra mais 8,22 por cento na leitura correta. Este guia mostra como a maturidade de coorte se forma, quando ela só erra o nível e quando ela erra o veredito, e como fechar a coorte sem inviabilizar o teste. Faz parte do nosso guia completo de teste A/B e complementa atraso de conversão e métricas de tempo até o evento.

O problema: o teste tem um começo, o usuário tem outro

Um experimento clínico recruta os participantes antes de começar. Todo mundo entra junto, todo mundo é acompanhado pelo mesmo período, e a métrica “sobreviveu 30 dias?” significa a mesma coisa para todos.

Teste A/B online não funciona assim. Kohavi, Deng, Frasca, Longbotham, Walker e Xu registram o ponto de forma direta: ao contrário da maioria dos experimentos offline, experimentos online recrutam usuários continuamente, em vez de terem um período de recrutamento antes do experimento, e como consequência o tamanho de amostra cresce enquanto o experimento roda.

Isso é uma virtude operacional e um problema de medição. Cada usuário tem um relógio próprio, que começa no dia em que ele entrou. Num teste de 28 dias:

Agora aplique a isso a métrica mais comum de produto: retenção em D7. Ela pergunta se o usuário estava ativo sete dias depois de entrar. Para quem entrou no dia 27, essa pergunta simplesmente não tem resposta ainda.

E aí acontece o erro que dá nome a este artigo: a consulta padrão soma “usuários retidos em D7” no numerador e “usuários que entraram no teste” no denominador. Quem não teve sete dias entra no denominador e não pode entrar no numerador. Ele não é contado como dado faltante, é contado como fracasso.

Coortes de entrada escalonadas dentro de um teste de 28 diasDiagrama com sete barras horizontais representando coortes que entraram no teste em dias diferentes. Cada barra começa no dia de entrada da coorte e vai até o dia 28, o fim do teste. A coorte do dia 1 tem 28 dias de acompanhamento, a do dia 8 tem 21, a do dia 15 tem 14, a do dia 22 tem 7, e as coortes que entraram nos dias 24, 26 e 28 têm respectivamente 5, 3 e 1 dia. Uma linha vertical tracejada no dia 22 separa as coortes que completaram sete dias de acompanhamento das que não completaram. As quatro barras à esquerda da linha são verdes e rotuladas como maduras para uma métrica de sete dias. As três barras à direita são laranjas e rotuladas como imaturas, e a legenda registra que elas correspondem a 21,43 por cento da amostra e entram na conta ingênua como se fossem usuários não retidos.Quem entrou depois do dia 22 não pode ter retenção D7 medidaúltimo dia com D7 completodia 128ddia 821ddia 1514ddia 227ddia 245ddia 263ddia 281ddia 1dia 15dia 28verde: coorte madura para D7 (78,57% da amostra)laranja: coorte imatura (21,43%), contada como “não retida” pela consulta ingênua
Cada coorte de entrada tem uma janela de acompanhamento diferente dentro do mesmo teste. A métrica com janela fixa só é calculável à esquerda da linha tracejada.

Caso 1: os dois braços recrutam igual, e só o nível quebra

Simulamos um teste de 28 dias, com 900 novos usuários por braço por dia, totalizando 25.200 por braço. A verdade do mundo simulado: retenção D7 de 30,00 por cento no controle e 32,40 por cento na variação, ou seja, a variação é 8 por cento melhor em termos relativos.

Os dois braços recrutam no mesmo ritmo, todo dia, sem rampa.

leitura controle variação lift relativo z valor-p IC 95% da diferença
ingênua (denominador = todos os inscritos) 5.849 / 25.200 (23,2103%) 6.484 / 25.200 (25,7302%) +10,86% 6,5793 abaixo de 1e-10 [1,7695 pp; 3,2702 pp]
coorte fechada (denominador = quem teve 7 dias) 5.849 / 19.800 (29,5404%) 6.484 / 19.800 (32,7475%) +10,86% 6,8908 abaixo de 1e-11 [2,2954 pp; 4,1187 pp]

Confira as duas linhas na calculadora, colando os quatro números de cada uma:

Calculadora de significância estatística
Controle (A)
Variação (B)
Controle (A) · Taxa-
Variação (B) · Taxa-
Melhora relativa-
valor-p-
IC 95% da diferença-

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.

Duas leituras da tabela, e a segunda é a que interessa.

O nível está errado por 6,3301 pontos. A leitura ingênua devolve 23,2103 por cento de retenção D7 onde o valor real é 29,5404 por cento. Isso é uma subestimação de 21,43 por cento do valor verdadeiro, e não é coincidência: 21,43 por cento é exatamente a fração da amostra que está imatura (5.400 de 25.200). O viés de nível é aritmeticamente igual à fração imatura, porque cada usuário imaturo entra como um zero garantido.

O lift relativo, por outro lado, sobreviveu. Os dois braços perderam a mesma fração, então a razão entre as taxas é a mesma nas duas linhas: mais 10,86 por cento em ambas. Só o intervalo de confiança muda, e para melhor na leitura fechada, porque o denominador menor é também mais honesto.

Vale registrar que o lift observado de mais 10,86 por cento fica acima da verdade de mais 8,00 por cento. Isso é ruído amostral comum, não viés: o intervalo de confiança da leitura fechada, de 2,2954 a 4,1187 pontos, contém a diferença verdadeira de 2,40 pontos sem apertar.

Então, quando os dois braços recrutam igual, a maturidade de coorte é um problema de nível, não de comparação. E problema de nível ainda é problema:

Caso 2: um braço em rampa, e o veredito inverte

Agora a versão perigosa. Mesmo teste, mesma verdade (variação 8 por cento melhor), com uma única mudança: a variação foi liberada em rampa, ou seja, com 10 por cento do tráfego na primeira semana, 60 por cento na segunda e 100 por cento depois.

Isso não é um cenário exótico. É rollout progressivo, a prática recomendada para reduzir risco de lançamento, e a mais comum em times que usam feature flags.

leitura controle variação lift relativo z valor-p IC 95% da diferença
ingênua 5.941 / 25.200 (23,5754%) 3.770 / 17.010 (22,1634%) menos 5,99% menos 3,3808 0,000723 [menos 2,2270 pp; menos 0,5969 pp]
coorte fechada 5.941 / 19.800 (30,0051%) 3.770 / 11.610 (32,4720%) mais 8,22% 4,5666 0,000005 [1,4025 pp; 3,5314 pp]

Leia com calma, porque as duas linhas são o mesmo teste, os mesmos usuários e os mesmos eventos.

A leitura ingênua diz que a variação perdeu por 5,99 por cento, com valor-p de 0,000723. É significativa. Um time disciplinado, com plano de análise e limiar de 0,05, mataria essa variação com justificativa formal.

A leitura de coorte fechada diz que a variação ganhou por 8,22 por cento, com valor-p de 0,000005. Também significativa, e o valor está praticamente em cima da verdade de mais 8,00 por cento.

Inversão de sinal entre a leitura ingênua e a leitura de coorte fechadaGráfico com um eixo horizontal centrado no zero e duas barras horizontais. A barra da leitura ingênua vai para a esquerda do zero, marcando um lift relativo de menos 5,99 por cento com valor-p de 0,000723, e está pintada em laranja de alerta. A barra da leitura de coorte fechada vai para a direita do zero, marcando mais 8,22 por cento com valor-p de 0,000005, e está pintada em verde. Uma linha tracejada vertical marca a verdade do mundo simulado, mais 8,00 por cento, praticamente colada no fim da barra verde. A legenda registra que as duas leituras usam os mesmos usuários e os mesmos eventos, e que a diferença entre elas é apenas o denominador.Mesmos usuários, mesmos eventos, vereditos opostos0%verdade: mais 8,00%leitura ingênuamenos 5,99%valor-p 0,000723, significativa e erradacoorte fechadamais 8,22%valor-p 0,000005menos 10%mais 12%A única diferença entre as duas linhas é o denominador: 25.200 e 17.010 contra 19.800 e 11.610.A rampa deixou 68,25% da variação madura contra 78,57% do controle, e a leitura ingênua leu essadiferença de idade como diferença de qualidade.
A inversão não vem de ruído: os dois valores-p são pequenos. Vem de comparar coortes de idades diferentes como se fossem comparáveis.

O mecanismo é simples de enunciar depois de visto. A rampa fez a variação recrutar mais tarde, então a coorte dela é mais jovem: só 68,25 por cento dos usuários da variação chegaram a completar sete dias, contra 78,57 por cento do controle. Dez pontos a mais de usuários imaturos, cada um entrando como um zero, derrubam a taxa observada da variação abaixo da do controle.

O elo com SRM, que não substitui esta checagem

Um leitor atento vai reparar que os braços têm tamanhos diferentes, 25.200 contra 17.010, e que isso dispararia um alarme de divisão desigual de tráfego. Está certo, e vale separar as duas coisas com cuidado:

A checagem certa não é comparar o número de usuários por braço, é comparar a distribuição de datas de entrada por braço. Se as duas distribuições não são iguais, e a métrica tem janela, feche a coorte.

O conserto da maturidade de coorte: fechar a coorte

A regra é uma linha: só entram na análise os usuários que entraram até o dia final do teste menos a janela da métrica. Num teste de 28 dias com métrica D7, analise quem entrou nos primeiros 22 dias. Todo mundo no denominador teve exatamente a mesma oportunidade.

O Spotify usa exatamente esse desenho no corpus de validação da métrica de tempo até a inatividade: Chandar e coautores registram que, em cada experimento, existe um período de entrada de 7 dias e apenas usuários expostos durante esse período entram na análise, com a janela posterior à exposição usada para calcular a métrica. A retenção semanal deles na semana 2, por exemplo, usa os dados dos 14 dias desde a exposição, não os 14 primeiros dias do calendário do teste.

O que isso custa em amostra

duração do teste fração aproveitável para métrica D7 fração aproveitável para métrica D30
10 dias 40,00% 0,00%
14 dias 57,14% 0,00%
21 dias 71,43% 0,00%
28 dias 78,57% 0,00%
35 dias 82,86% 17,14%
42 dias 85,71% 30,95%
56 dias 89,29% 48,21%

A linha que mais surpreende times é a de D30: um teste de 28 dias tem zero por cento de amostra aproveitável para uma métrica de 30 dias. Nenhum usuário teve trinta dias. Se o seu relatório mostra retenção D30 de um teste de quatro semanas, aquele número foi construído de alguma forma que não é a que o nome sugere.

E o custo em recrutamento, usando o mesmo cenário da simulação (base de 30,00 por cento, detectar mais 8,00 por cento relativo, 95 por cento de confiança e 80 por cento de poder):

duração do teste N por variação exigido pela estatística usuários a recrutar por variação
14 dias 5.849 10.236
28 dias 5.849 7.445
42 dias 5.849 6.824

O padrão é claro e é útil na hora de negociar prazo: a perda por imaturidade cai rápido nos primeiros dias e depois estagna. Ir de 14 para 28 dias economiza 2.791 usuários por variação; ir de 28 para 42 economiza só mais 621. O ponto de virada costuma estar entre três e quatro vezes a janela da métrica.

Para rodar essa conta com os seus números, use a calculadora de tamanho de amostra para obter o N e depois divida pela fração aproveitável da tabela acima. A calculadora de duração fecha o ciclo com o tráfego semanal real.

Rodar mais tempo resolve tudo? Não

Existe uma leitura otimista deste artigo que diz “então é só rodar mais tempo”. Ela é parcialmente verdadeira e vale corrigir, porque Kohavi e coautores mediram exatamente o limite dessa ideia.

Para métricas limitadas, como taxa de clique, o intervalo de confiança do efeito percentual realmente encolhe com a duração, e rodar mais tempo aumenta o poder. Mas para métricas como sessões por usuário eles observaram que o intervalo de confiança do efeito percentual não encolhe com o tempo. A explicação é que a largura do intervalo é governada pelo coeficiente de variação dividido pela raiz do tamanho de amostra, e o coeficiente de variação dessas métricas cresce ao longo do experimento, porque o desvio-padrão cresce mais rápido que a média. Nos dados deles, a razão entre coeficiente de variação e raiz da amostra ficou praticamente constante ao longo de 31 dias, com variação menor que 10 por cento.

A tradução prática, nas palavras deles: para métricas como sessões por usuário, o poder estatístico não necessariamente aumenta conforme o experimento roda mais tempo, e quando se quer detectar efeito nessas métricas é preciso rodar com mais usuários por dia, não com mais dias.

Então a resposta correta é uma combinação:

Rodar semanas inteiras continua obrigatório pelo motivo de sempre, o efeito de dia da semana, tratado em ciclo semanal. Uma semana é o mínimo para enxergar esse efeito.

Roteiro de maturidade de coorte em cinco passos

  1. Para toda métrica com janela, escreva a janela. “Retenção” não é uma métrica; “ativo entre o dia 6 e o dia 8 após a entrada” é. Sem isso, ninguém sabe se a coorte está madura.
  2. Compare a distribuição de datas de entrada entre os braços, não só o total por braço. Um histograma resolve. Distribuições diferentes com métrica de janela significam coorte fechada obrigatória.
  3. Fixe a regra de corte no plano de análise, antes de rodar. Escolher entre leitura ingênua e leitura fechada depois de ver as duas é escolher o resultado.
  4. Reporte o denominador junto da taxa. “29,54 por cento de retenção D7 sobre 19.800 usuários maduros de 25.200 inscritos” é uma frase completa. “23,2 por cento de retenção” não é.
  5. Dimensione o teste com a fração aproveitável já descontada. O N que a calculadora devolve é o que você precisa analisar, não o que precisa expor.

Erros comuns

Faça isso automático na Donnu

O motivo de essa distorção passar batida quase nunca é falta de rigor, é a forma do dado: a maioria dos painéis de teste A/B guarda um sinalizador de conversão ou retenção por usuário e não guarda a data de entrada dele no experimento. Sem a data de entrada não existe idade de coorte, e sem idade de coorte não existe como fechar a coorte.

A Donnu guarda a data de sorteio de cada usuário junto do resultado dele, o que torna a leitura de coorte fechada um filtro e não uma reconstrução. Se a sua montagem atual não guarda, o passo imediato é começar a gravar a data de entrada hoje, e enquanto isso adotar a regra conservadora: para qualquer métrica com janela, só ler o teste depois de decorrida a janela contada a partir da última entrada. Para dimensionar o teste já com o desconto da coorte imatura, a calculadora de tamanho de amostra dá o N e a tabela deste artigo dá o divisor.

Referências

Leia também: Atraso de conversão · Métricas de tempo até o evento · SRM e divisão desigual · Rollout progressivo · Ciclo semanal · Calculadora de tamanho de amostra · Read in English

Perguntas frequentes

O que é maturidade de coorte em teste A/B?
É quanto tempo de acompanhamento cada usuário teve depois de entrar no teste. Num teste com entrada contínua de tráfego, quem entrou no primeiro dia de um teste de 28 dias tem 28 dias de acompanhamento e quem entrou no dia 27 tem um. Uma métrica que exige uma janela fixa, como retenção em D7, só é calculável para quem já completou essa janela.
Por que a retenção D7 aparece menor do que é de verdade?
Porque o denominador padrão inclui todo mundo que entrou no teste, inclusive quem ainda não teve sete dias, e essas pessoas entram no cálculo como não retidas por falta de dado, não por comportamento. Na simulação deste guia, a retenção D7 verdadeira era de 29,5404 por cento e a leitura ingênua devolveu 23,2103 por cento, uma subestimação de 6,3301 pontos, ou 21,43 por cento do valor real.
Se a distorção atinge os dois braços igualmente, o teste continua válido?
A comparação relativa sobrevive quando os dois braços recrutam no mesmo ritmo. O que não sobrevive é o nível, então qualquer comparação com meta, com histórico ou com benchmark de mercado fica errada. E basta um braço recrutar em ritmo diferente para a comparação também quebrar.
Como um lançamento em rampa inverte o resultado?
Porque a rampa deixa a coorte do braço liberado mais tarde sistematicamente mais jovem. Na segunda simulação deste guia, a variação era genuinamente 8 por cento melhor e a leitura ingênua devolveu menos 5,99 por cento com valor-p de 0,000723, ou seja, uma derrota estatisticamente significativa. A mesma leitura restrita à coorte madura devolveu mais 8,22 por cento com valor-p de 0,000005. O sinal inverteu.
Qual é o conserto?
Fechar a coorte: só entram na análise os usuários que entraram até o dia final menos a janela da métrica. Num teste de 28 dias com métrica D7, isso significa analisar quem entrou nos primeiros 22 dias, cada um com seus sete dias completos. O custo é a amostra descartada, que nesse exemplo é de 21,43 por cento.
Quanto tempo a mais o teste precisa rodar?
A fração aproveitável é a duração do teste menos a janela, mais um, dividida pela duração. Para uma métrica D7, um teste de 14 dias aproveita 57,14 por cento da amostra e um de 42 dias aproveita 85,71 por cento. Na simulação deste guia, o N de 5.849 por variação vira 10.236 usuários a recrutar num teste de 14 dias e 6.824 num de 42.