Como estruturar um teste A/B: um pouco de teoria e exemplo no R
Fala Pessoal, tudo bem?
Em primeiro lugar para quem me acompanha e queria saber mais sobre A/B testing, peço desculpas! Estou uma semana atrasado aqui no artigo 🙁 .
Há duas semanas fiz uma pesquisa sobre o que as pessoas gostariam de ver aprofundamento analítico e os grandes vencedores foram o A/B testing e detecção de fraudes por Lei de Benford. Como todo bom brasileiro, vou “pagar” parcelado, e começar com A/B Testing.
O que é um A/B test e para que serve?
Em miúdos, o A/B test é uma ferramenta para provar experimentos. Basicamente entre as alternativas, A e B você quer saber qual gera o melhor resultado.
Essa ferramenta é largamente usada por empresas de tecnologia ao desenvolver suas soluções, e a prática foi um dos grandes trunfos do Google e Facebook no desenvolvimento de seus produtos. Ao que se sabe, ambos rodam muitos milhares de testes A/B diariamente.
Como eles fazem?
De modo simples, digamos que eles queiram mudar a fonte de um botão, ou mesmo a posição de um anúncio na tela. Eles conversam entre eles e fazem o que acharem melhor em consenso?
Não.
Eles segmentam sua audiência e colocam escolhas diferentes para grupos comparáveis. Coletam o resultado e comprovam: o link B ou o layout de anúncio B tem resultados superiores ao atual, A.
Vamos a um exemplo: Campanha Instagram para um Abrigo de Animais.
Digamos que você seja responsável por uma ONG de adoção de cachorros. Diariamente você consegue um lar para, em média, 5 cachorros. Com uma nova campanha via Instagram, você tem conseguido lar para, em média, 7 cachorros/dia no ultimo mês.
Ora, é simples! Se com a campanha a média é maior, está provado que ela funcionou!
Como nosso filósofo brasileiro, Compadre Washington diria: sabe de nada, inocente!
Por que? No teste, você garantiu sucesso dele mesmo, mas isso não significa ainda que você tem provas de que sempre funcionará.
Simplificando, porque não há como garantir reprodutibilidade, ou seja, até o momento não há como sabermos se, ao repetir o experimento, teremos resultados superiores à média-base, que é 5.
Vamos então buscar a prova.
Para isso, usaremos um conceito da estatística chamado Teste de Hipótese. Ele serve para determinar, com um certo grau de certeza (significância), se o valor encontrado é realmente diferente da média que observamos.
Um teste de hipótese começa com: hipóteses (uau).
A primeira hipótese, a que usamos como ponto de partida, é chamada nula, que defende a posição mais conservadora, ou seja, dizer que não há diferença entre a média de adoções sem campanha e com campanha.
A segunda hipótese, a que buscamos prova, é chamada alternativa, a qual queremos buscar que, sem sombra de dúvida, há mais adoções quando há campanha no Instagram.
Formulamos assim:
H0: As médias de adoções são estatisticamente iguais.
H1: As média2 (com campanha) é maior que a média1 (sem campanha).
Agora, é basicamente um cálculo de comparação, entre o que eu observei versus um score que determina se eu deveria rejeitar ou não a hipótese.
É como um salto em altura. Se o que eu observei passou da barra (o Score de Rejeição), aprovado. Se não passou, está rejeitado.
O que eu observei e como calcular:
O T-score é a diferença das médias (7 e 5) dividido pela raiz dos desvios-padrão/observações de cada uma das amostras (com campanha e sem campanha).
Nesse caso, o T-Score deu -0,82.
Para fazer esse cálculo sem sofrer, basta habilitar no Excel o Suplemento Análise de dados e selecionar o teste T.
Como fazer está aqui.
Score de Rejeição.
Aqui trabalhamos com uma questão: qual será a significância do meu teste, ou seja, se eu reproduzí-lo infinitas vezes, qual a probabilidade de se ter esses mesmos resultados?
Normalmente, utilizamos 90% ou 95% ou 97,5%. Vamos usar 97,5%. Para encontrar esse score facilmente, basta colocar no Excel:
=INV.T(PROBABILIDADE, (#obs1+#obs2 - 2))
Para o caso de 0,975 (97,5%) , encontramos o valor de 2,44 (distribuição T para 6 graus de liberdade, 4+4-2).
Nesse caso, precisávamos de um T-Score maior que 2,44 para alegar diferenças, e não o encontramos.
Ou seja, não temos evidências de melhores resultados com a campanha no Instagram. H0 não é rejeitada.
Um pouco mais sobre teoria dos testes de hipóteses aqui.
Feito tudo isso, vamos para o R.
Usando o R: mesmo raciocínio.
Para manter simples, vamos utilizar o RStudio e um dataset já carregado dentro do R.
Assim, utilizaremos o dataset mtcars, com dados de veículos. É um clássico e super simples.
A ideia é que verificaremos uma série de hipóteses comparando veículos com 4, 6 e 8 cilindros.
Vamos usar as seguintes colunas do dataset:
- Cyl: número de cilindros, podendo ser 4, 6 ou 8.
- qsec: quantidade de segundos para cumprir 1/4 de milha. Uma forma de medir velocidade. Quanto menos, mais rápido.
- mpg: miles per gallon. Unidade de consumo de combustível. Quanto mais alto, mas econômico é o veículo.
Primeiro passo: carregar o Dataset.
data('mtcars')
Esse passo é bem simples, pois usaremos um dataset que já vem carregado no R. Para carregar outros datasets no RStudio, você pode ir a File -> Import Dataset e seguir o caminho proposto.
options(scipen = 999)
Esse código ajuda ao retirarmos a notação científica dos resultados, o que dificulta a leitura caso tenhamos resultados numéricos pequenos.
install.packages('GGally')
Esse passo é para criar visualizações, e já vem o famoso ggplot2 com esse install “y algunas cositas más”.
library('GGally')
Lembrando que o install deixa o pacote disponível, mas não ativo. Esse comando o “ativa”.
mtcars$cyl <- as.factor(mtcars$cyl)
Aqui estamos fazendo uma transformação. Como os cilindros são valores numéricos (4, 6 e 8), é necessário usar essa transformação para que o R entenda como classes de veículos.
ggpairs(mtcars, aes(color = cyl))
Aqui estou criando um gráfico pareado – super útil para explorar características do Dataset – separado em cores para cada classe de cilindros (4, 6 ou 8).
Aqui podemos brincar com algumas hipóteses, vou criar três principais perguntas.
1) Será que os veículos de com mais cilindros são mais rápidos (qsec menor) que o com menos?
2) Será que os veículos de 8 cilindros “bebem” mais (mpg maior) que o de 6?
3) Será que os veículos de 4 cilindros tem menos potência (hp maior) que o de 8?
Vamos primeiro dividir cada uma das classes de cilindros em um novo set.
four_cyl <- subset(mtcars, mtcars$cyl == 4) six_cyl <- subset(mtcars, mtcars$cyl == 6) eight_cyl <- subset(mtcars, mtcars$cyl == 8)
Agora que temos cada um deles separados, podemos testá-los.
1) Verificando se mais cilindros = mais velocidade.
ggplot(mtcars, aes(x = cyl, y = mpg, fill = cyl))+geom_violin(trim = FALSE)
Primeiro vamos verificar visualmente.
Aparentemente, há associação entre velocidade e cilindrada. Porém, quando verificando 6 cilindros versus 8, parece que há bastante sobreposição.
Como formular esse teste?
H0: A média de qsec para 6 cilindros é igual a qsec para 8 cilindros;
H1: q sec para 6 cilindros é maior que qsec para 8 (ou seja, 8 cilindros é mais rápido).
test <- t.test(six_cyl$qsec, eight_cyl$qsec, alternative = "greater", var.equal = F, conf.level = 0.95) test
Ao realizar o teste, encontramos esses resultados. Vamos olhar o chamado p-value.
O p-value é uma outra forma de olharmos um teste. Ele tem que ser menor do que a chance de rejeitarmos H0. Se nosso confidence level é 95%, o p-value deveria ser abaixo de 0,05 para rejeitarmos H0.
Portanto, não há diferença relevante na velocidade dos veículos de 6 e 8 cilindros.
2) Verificando se mais cilindros = maior consumo.
Igualmente, vamos para hipótese
H0: Veículos de 6 e 8 cilindros têm consumo similar de combustível.
H1: Veículos de 6 e 8 cilindros tem consumos diferentes.
test2 <- t.test(six_cyl$mpg, eight_cyl$mpg, alternative = "two.sided", var.equal = F, conf.level = 0.95) test2
Dessa vez o p-value indica que sim (H0 rejeitada), os consumos são diferentes para cada um dos tipos de veículo.
3) Verificando se mais cilindros = mais potência.
Finalmente, vamos testar potência, mas agora de forma bem fácil! Queremos comparar HP entre veículos de 4 versus 8 cilindros (quem manja um pouco de carros já sabe o resultado).
H0: veículos de 4 e 8 cilindros têm potência similar
H1: veículos de 4 cilindros têm potência inferior
test3 <- t.test(four_cyl$hp, eight_cyl$hp, alternative = 'less', var.equal = F, conf.level = 0.95) test3
Dessa vez o p-valor foi super baixo. Ou seja, H0 rejeitada by a long mile.
Pronto! Agora você sabe a lógica de como validar estatisticamente um experimento!
Considerações Finais.
Resolvi escrever esse artigo pois, por diversas vezes escutei sobre A/B testing como forma de provar hipóteses (principalmente de desenvolvimento de produto), mas que, ao final do experimento, apenas verificou desempenho do teste.
Como no primeiro exemplo do abrigo de animais, B foi melhor que A na média, então tudo certo! Só que não, como demonstrei.
Obviamente, esse artigo não vai te salvar em todas as situações para um A/B testing e nem é essa a ideia. Mas principalmente, como recomendações:
1) Teste coisas isoladamente! Testar um pacotão A versus um pacotão B pode te mostrar que A é melhor que B ou vice-versa, mas não saberá o que no pacotão deu resultado ou não.
2) Cada teste tem uma característica! Se há muitos ou poucos dados, variâncias semelhantes ou diferentes, se você quer ver se uma distribuição segue comportamento conhecido ou não. Aqui temos uma “colinha” que pode ajudar!
3) Procure sempre criar uma ou mais visualizações pré-teste. Podem te ajudar a entender a linha do “aha, faz sentido”.
4) Se possível, aprenda e ajude os demais. Afinal de contas, a vida é muito curta para produzirmos a partir de hipóteses não validadas.
Um abraço!
** Este texto não reflete, necessariamente, a opinião da Escola de IA