Tomada de decisão com Teste A/B

Uma prática e intuitiva introdução a técnicas e análises em Testes A/B!

Guilherme Reis Mendes
Data Hackers
15 min readOct 30, 2020

--

Teste A/B (Neil Patel)

O que é Teste A/B?

Basicamente, o teste A/B é um método para comparar 2 versões de algo uma contra a outra para descobrir qual é a mais bem-sucedida. O algo pode ser uma imagem, um botão, um título ou além.

Cada teste gera novos dados sobre o que funcionou e o que não funcionou. Sempre que algo funciona, isso pode ser incluído no site ou aplicativo e agora

script em proforma um design novo e aprimorado.

Porque é importante?

O teste A / B mede o desempenho ao vivo, com clientes reais. Desde que seja bem executado, sem viés entre as amostras das populações A e B, oferece a melhor estimativa do que aconteceria se você implantasse a versão B.

  • Análises sem especulações
  • Provar respostas rápidas e precisas
  • Permite iterar ideias rapidamente
  • É possível estabelecer relações casuais entre variáveis

Processo do teste A/B

  1. Desenvolver uma hipótese sobre o produto ou mercado
  2. Atribuir usuários aleatoriamente a dois grupos diferentes
  3. Grupo 1 para o estado atual do produto. Grupo 2 o produto a ser testado
  4. Escolha o que tem melhor desempenho para um conjunto de KPIs

A ideia do artigo é conseguir passar de um jeito prático e “hands-on” o que é necessário para que você, leitor, entenda e consiga desenvolver um Teste A/B com base e qualidade. Com isso, o progresso, será:

  1. Entendendo nossos usuários: Key Performance Indicators (KPI)
  2. Identificando tendências: Análise exploratória
  3. Otimização de performance: Design do Teste A/B
  4. Tomada de decisão baseada em dados: Análise do Teste A/B

O código e o dataset utilizado durante o artigo pode ser encontrado aqui.

1- Entendendo nossos usuários

Primeiramente, o que é um KPI?

Key Performace Indicator

Indicador-Chave de Desempenho ou KPI são simplesmente métricas importantes para uma organização.

É uma forma de medir se uma ação ou um conjunto de iniciativas está efetivamente atendendo aos objetivos propostos pela organização.

A ideia do Teste A/B é basicamente medir o impacto de mudanças pelo KPI.

Vamos explorar um dataset de clientes para identificar que métricas são importantes de uma maneira que intercale com o que faremos na grande arte de exploração de dados. E continuaremos com exemplos similares para mostrar como o processo de Teste A/B cresce a partir das ideias dos KPIs e da análise exploratória de dados.

Os dados que iremos explorar é a partir de um app que oferece serviços de meditação para uma assinatura paga, bem como compras únicas no aplicativo. Imagine que o aplicativo está crescendo bastante e queremos aumentar a taxa de conversão do usuário. Então o nosso KPI analisado será a taxa de conversão (pessoas que pagam a assinatura). Mas podemos imaginar outros KPIs, como a troca de usuários e compras de outros produtos.

Normalmente uma empresa terá vários KPIs, um para cada propósito.

# Importando nossos dados
>> import pandas as pd
# customer_data
>> customer_data = pd.read_csv('customer_data.csv')
>> print(customer_data.columns)
# app_purchases
>> app_purchases = pd.read_csv('inapp_purchases.csv')
>> print(app_purchases.columns)
Output:Index(['uid', 'date', 'device', 'gender', 'country', 'age'], dtype='object')
Index(['date', 'uid', 'sku', 'price'], dtype='object')

Uma questão para a definição do KPI é sobre qual intervalo devemos considerar. Seguindo a ideia da taxa de conversão, qual intervalo consideraremos? A conversão imediatamente após o termino do “free trial”? Uma semana depois? Um mês? Uma maneira de decidir isso é ver a generalização dessas estatísticas em diferentes grupos demográficos. A estabilidade é desejada, para que não seja necessário uma KPI personalizado para cada detalhamento. Outro ponto é verificar se um está mais correlacionado com fatores importantes como retenção ou gastos do que os outros. Para isso, vamos fazer um merge dos dados importados para explorar as relações.

# Merge no 'uid' e 'date'
>> customer_data['date']= pd.to_datetime(customer_data['date']).dt.date
>> app_purchases['date']= pd.to_datetime(app_purchases['date']).dt.date
>> uid_date_combined_data = app_purchases.merge(customer_data, on=['uid', 'date'], how='inner')
# Resultados
>> print(uid_date_combined_data.head())
>> print(len(uid_date_combined_data))
Output:35

Agrupando nosso dados para futuras análises:

# Agrupando
>> grouped_purchase_data = purchase_data.groupby(by=['device', 'gender'])
# Agregando
>> purchase_summary = grouped_purchase_data.agg({'price': ['mean', 'median', 'std']})
>> print(purchase_summary)

Vamos analisar o valor médio pago por compra nos primeiros 28 dias de um usuário. Esse KPI pode fornecer uma noção da popularidade de diferentes pontos de preços de compra no aplicativo no primeiro mês. Primeiro, considere que nossa data atual é 17 de março de 2018, e calcule qual o último dia onde vamos considerar compras.

>> from datetime import datetime, timedelta>> current_date = pd.to_datetime('2018-03-17')>> max_purchase_date = current_date - timedelta(days=28)

Em seguida, filtre todos os usuários que se registraram nos últimos 28 dias, e apenas compras que ocorreram nos primeiros 28 dias, e encontre a média.

>> purchase_data_filt = purchase_data[purchase_data.date < max_purchase_date]>> purchase_data_filt = purchase_data_filt[(purchase_data_filt.date <= purchase_data_filt.date + timedelta(days=28))]>> print(purchase_data_filt.price.mean())Output:407.3279866546901

Vamos examinar o mesmo KPI, preço médio de compra, e um semelhante, preço mediano de compra, nos primeiros 28 dias. Além disso, vamos olhar para essas métricas não limitadas a 28 dias para comparar.

Podemos calcular essas métricas em um conjunto de grupos e ver quais diferenças surgem. Esta é uma tarefa útil, pois pode nos ajudar a entender como os comportamentos variam entre os grupos.

Observe que em nossos dados a variável de preço é dada em centavos.

>> max_reg_date = current_date - timedelta(days=28)# Ache o primeiro mês
>> month1 = np.where((purchase_data.reg_date < max_reg_date) &
(purchase_data.date < purchase_data.reg_date + timedelta(days=28)),
purchase_data.price,
np.NaN)

# Atualize os valores
>> purchase_data['month1'] = month1
# Agrupando
>> purchase_data_upd = purchase_data.groupby(by=['gender', 'device'], as_index=False)
# Agregando
>> purchase_summary = purchase_data_upd.agg(
{'month1': ['mean', 'median'],
'price': ['mean', 'median']})
>> print(purchase_summary)

Para concluir nossa discussão sobre KPIs, é importante observar que, embora existe um numero infinito de KPI precisamos escolher com cuidado em que confiar e que esteja de acordo com objetivos da organização. Um fator para prestar atenção é quanto tempo leva para obter informações sobre uma métrica.

2- Identificando tendências

Por enquanto só analisamos em espaços de tempo específicos, agora vamos dar um passo adiante e analisar esse valor ao longo do tempo, visualizando em gráficos temporais.

Outros gráficos de séries temporais de segmentação podem torná-los ainda mais poderosos. Isso pode fornecer informações sobre se as alterações estão impactando todos os usuários igualmente ou grupos diferentes de maneiras diferentes. Para muitas empresas, a divisão por pais ou dispositivo é particularmente útil, como esses grupos costumam ter experiências drasticamente diferentes com um produto.

Imagine que na tentativa de aumentar as compras, fizemos algumas mudanças nos preços introdutórios de compra no aplicativo. Vamos verificar o efeito no número de comprar feitas durante a primeira semana do usuário. A coluna “first_week_purchases” que é 1 para uma compra na primeira semana e 0, caso contrário, foi adicionada. Esta coluna é convertida para a média de compras feitas por dia pelos usuários na primeira semana.

# Agrupando os dados e a soma agregada
>> user_purchases = user_purchases.groupby(by=['reg_date', 'uid']).agg({'first_week_purchases': ['sum']})
# Reset_index
>> user_purchases.columns = user_purchases.columns.droplevel(level=1)
>> user_purchases.reset_index(inplace=True)
# Média do número de comprar por dia na primeira semana do usuário
>> user_purchases = user_purchases.groupby(by=['reg_date']).agg({'first_week_purchases': ['mean']})
>> user_purchases.columns = user_purchases.columns.droplevel(level=1)
>> user_purchases.reset_index(inplace=True)
# Pivot
>> device_pivot = pd.pivot_table(user_purchases_device, values=['first_week_purchases'], columns=['device'], index=['reg_date'])
>> print(device_pivot.head())
# Resultados por dispositivo
>> device_pivot.plot(x='reg_date', y=['and', 'iOS'])
>> plt.show()

Como você viu, parece haver um aumento no número de compras por usuários na primeira semana nos dois dispositivos.

Frequentemente, plotar um gráfico não é o suficiente e é necessário pré-processamento adicional para descobrir tendências. Muitas métricas terão sazonalidade e podem ofuscar as tendências. Podemos corrigir esse movimento calculando uma média móvel sobre nossos dados. Média móvel (trailling average) é uma técnica de suavização que define o valor para um determinado dia como a média nos últimos n dias.

Decomposição da série temporal

Vamos analisar os dados de renda de nosso aplicativo de meditação. Vimos um crescimento nas compras de um produto, e agora queremos ver se isso está aumentando a nossa renda. Esperamos que a renda é muito sazonal, por isso temos que corrigir isso. Iremos corrigir a sazonalidade semanal, mensal e anual e representá-la em nossos dados brutos. Isso pode revelar tendências importantes. Podemos usar o método .rolling do pandas.

Os dados foram importados no dataframe “daily_revenue”.

# Janela de 7 dias
>> daily_revenue['7_day_rev'] = daily_revenue.revenue.rolling(window=7,center=False).mean()

# Janela de 28 dias
>> daily_revenue['28_day_rev'] = daily_revenue.revenue.rolling(window=28,center=False).mean()

# Janela de 1 ano
>> daily_revenue['365_day_rev'] = daily_revenue.revenue.rolling(window=365,center=False).mean()

# Resultado
>> daily_revenue.plot(x='date', y=['revenue', '7_day_rev', '28_day_rev', '365_day_rev', ])
>> plt.show()

Achou estranho? As compras do produto aumentou mas a renda geral continua estável. Vamos analisar melhor isso.

Além da sazonalidade, os dados podem ter “ruídos”, podemos aplicar uma média móvel exponencial para verificar se existem tendências ocultas nesse ruído. Esse tipo de média pesa os pontos de maneira que os anteriores terão pesos menores que os mais recentes em nossa janela. Isso puxa nossos dados de volta para qualquer tendência central, mantendo os movimentos recentes.

Vimos que a renda é estável ao longo do tempo. Analisaremos a renda de um único produto de compra no aplicativo que estamos vendendo para ver se isso revela alguma tendência. Como isso terá menos dados do que olhando para a renda geral, terá muito ruído. Para compensar isso, suavizaremos os dados usando uma média móvel exponencial. Podemos utilizar o método .ewm para achar essas janelas.

# Calculamos 'small_scale'
>> daily_revenue['small_scale'] = daily_revenue.revenue.ewm(span=10).mean()
# Calculamos 'medium_scale'
>> daily_revenue['medium_scale'] = daily_revenue.revenue.ewm(span=100).mean()
# Calculamos 'large_scale'
>> daily_revenue['large_scale'] = daily_revenue.revenue.ewm(span=500).mean()
# Resultados
>> daily_revenue.plot(x = 'date', y =['revenue','small_scale', 'medium_scale', 'large_scale'])
>> plt.show()

Observe que a renda parece estar crescendo neste produto, então não deve ser a causa da tendência estável da renda geral!

Mesmo sendo um caso simples, mostra o poder que a visualização tem para descobrir tendências e analises importantes. Isso pode revelar relações óbvias, mas não permite testes científicos de ideias diferentes ou mostrar a causalidade dos resultados, e ai começa o Teste A/B.

3- Otimização de performance

Vamos começar esclarecendo alguns detalhes do Teste A/B.

Testaremos o estado atual (controle), em relação a uma variante (tratamento ou teste). Para isso é preciso selecionar aleatoriamente um subconjunto de usuários, mostrar a mudança feita, e monitorar o comportamento desse grupo em comparação ao grupo controle. Mas existem casos que o Teste A/B não será útil.

Separação dos grupos para o Teste A/B

Problemas bons para Teste A/B:

  • Usuários são impactados individualmente
  • Testar mudanças que impactam diretamente no comportamento

Problemas ruins para Teste A/B:

  • Quando é difícil segmentar os usuários em grupos
  • Quando é difícil desvendar o impacto do teste

Em um Teste A/B, temos que definir uma variável de resposta que usaremos para medir nosso impacto, ou seja, um KPI, como vimos na parte 1 e 2. Em seguida, temos um conjunto de fatores que afetam nossa resposta, como a cor de um paywall nas compras por exemplo. As variantes são as possíveis mudanças desse fator em particular, como um paywall azul ou vermelho. E temos nossa unidade experimental, essa é a unidade que as métricas são medidas antes da agregação no grupo de controle ou no de tratamento em geral. Por exemplo, se estivéssemos vendo as compras de um produto como nossa resposta, poderíamos usar usuários como nossa unidade experimental e comparara o numero médio de comprar por usuário em nossos dois grupos.

Em quase qualquer circunstância, queremos randomizar por usuário, independentemente da nosso unidade experimental. Caso contrario, o usuário poderá ter uma experiência inconsistente que poderá impactar os resultados.

Considerações no design do Teste:

  1. Nosso teste pode ser executado bem na prática?
  2. Seremos capazes de obter resultados significativos a partir dele?

Agora vamos preparar nosso Teste!

Um bom ponto de partida é perguntar qual mudança percentual seria significativa para detectar em sua variável resposta, 1%? 20%? O nível mínimo de mudança que queremos ser capazes de detectar em nosso teste se chama sensibilidade.

Vamos trabalhar com a taxa de conversão. Especificamente, examinar o que esse valor se torna sob diferentes sensibilidades e ver em quantas conversões a mais por dia essa mudança resultaria. Primeiro, é preciso calcular o número médio de visualizações e compras que foram feitas por dia em nossa amostra.

# Merge nos datasets e calcule as métricas diarias
>> purchase_data = demographics_data.merge(paywall_views, how='inner', on=['uid'])
>> purchase_data.date = purchase_data.date.dt.floor('d')
# Agrupar e agregar nosso dataset
>> daily_purchase_data = purchase_data.groupby(by=['date'], as_index=False)
>> daily_purchase_data = daily_purchase_data.agg({'purchase': ['sum', 'count']})
# Ache a média dos campos e multiplique por 1000 para escalar
>> daily_purchases = daily_purchase_data.purchase['sum'].mean()
>> daily_paywall_views = daily_purchase_data.purchase['count'].mean()
>> daily_purchases = daily_purchases * 1000
>> daily_paywall_views = daily_paywall_views * 1000
>> print(daily_purchases)
>> print(daily_paywall_views)
Output:3181.8181818181815
91731.86409550045

Agora vamos testar algumas sensibilidades.

>> sensitivity = [0.1,0.2,0.5]# Baseline
>> conversion_rate = daily_purchases/daily_paywall_views
>> for i in sensitivity:

# Taxa de conversão quando mutiplicado pela sensibilidade
conversion = conversion_rate * (1 + i)
# Aplique a nova taxa para achar quantos usuários adquiriram
purchase = daily_paywall_views * conversion
# Diminua com a original para ver o aumento
purchaser_lift = purchase - daily_purchases
print('Sensibilidade: {}, Conversão: {}, Compras: {}, Aumento: {}'.format(i,conversion,purchase,purchaser_lift))Output:Sensibilidade: 0.1, Conversão: 0.03814800000000001, Compras: 3499.384706400001, Aumento: 317.58470640000087Sensibilidade: 0.2, Conversão: 0.041616, Compras: 3817.5105888000003, Aumento: 635.7105888000001Sensibilidade: 0.5, Conversão: 0.052020000000000004, Compras: 4771.888236000001, Aumento: 1590.0882360000005

Pelos resultados, parece que um aumento de 50% pode ser muito drástico, as sensibilidades pequenas e médias parecem mais razoáveis.

Precisamos definir o tamanho da amostra necessário para o Teste, ou seja, qual é o mínimo de pessoas que preciso no meu grupo de tratamento?

Primeiro, precisamos discutir sobre nossa hipótese nula, essa é a hipótese que nosso controle e tratamento tem o mesmo impacto na variável de resposta (KPI) e qualquer diferença é devido à aleatoriedade. Se concluirmos que esse não é o caso, rejeitamos a hipótese e dizemos que há diferença entre o controle e o tratamento. Definimos o nível de confiança, nossa probabilidade de rejeitar a hipótese nula, quanto maior o valor, maior a amostra que precisaremos (valor comum de 0.95). Relacionado a isso está o conceito de poder estatístico, é a probabilidade de encontrar resultados estatisticamente significativos quando a hipótese nula é rejeitada.

Teste de Hipótese

São conceitos estatísticos importantes, mas que não vamos entrar em detalhe, sugiro que busque informações nos milhares de textos relacionados.

Para estimar a amostra necessária, temos que escolher:

  • Nível de sensibilidade
  • Nível de confiança
  • Poder estatístico
  • Calcular o desvio padrão

Vamos calcular nosso tamanho da amostra. Considerando:

  • Baseline (taxa de conversão): 0.03468
  • Nível de confiança: 0.95
  • Poder: 0.80
  • Sensibilidade: 0.1
# Calculo do poder estatístico
>> def get_power(n, p1, p2, cl):
alpha = 1 - cl
qu = stats.norm.ppf(1 - alpha/2)
diff = abs(p2 - p1)
bp = (p1 + p2) / 2
power = power_part_one + power_part_two
return(power)
# Calculo do tamanho da amostra
>> def get_sample_size(power, p1, p2, cl, max_n = 1000000):
n = 1
while n <= max_n:
tmp_power = get_power(n, p1, p2, cl)
if tmp_power >= power:
return n
else:
n = n + 1
# Calculando..
>> sample_size_per_group = get_sample_size(0.8, conversion_rate, conversion_rate * 1.1, 0.95)
>> print(sample_size_per_group)
Output:45788

Existem maneiras de diminuir a amostra, uma é alternar a unidade de resposta de uma maneira que reduza o desvio padrão (variabilidade). Outra é excluir usuários irrelevantes para o processo.

4- Tomada de decisão baseada em dados

Paywall

Vamos avaliar os dois paywalls medindo o impacto sobre a taxa de compra dos usuários que encontraram esse novo design de paywall.

Antes de tudo, temos que garantir que nosso teste foi feito corretamente. Embora nem sempre você vai estar em posição de determinar isso diretamente, você pode garantir que os dados sejam suficientemente aleatório.

# Encontre os usuários únicos em cada grupo
>> results = ab_test_results.groupby(by=['group', 'device', 'gender']).agg({'uid': pd.Series.nunique})
# Encontre o número total de usuários exclusivos
>> unique_users = len(ab_test_results.uid.unique())
# Encontre a porcentagem em cada grupo
>> results = results / unique_users * 100
>> print(results)
Output: group device gender
C and F 14.896625
M 13.518289
iOS F 11.309419
M 10.196148
V and F 14.861283
M 13.659657
iOS F 10.920657
M 10.637922

Estamos prontos para prosseguir com as análises!

Agora vamos encontrar a conversão média para cada um dos grupos. O próximo passo é determinar se essa diferença é estatisticamente significativa. Ou seja, medir se os valores diferem mais do que seria esperado devido à aleatoriedade. Se for esse o caso, podemos rejeitar a hipótese nula. Para fazer isso, devemos calcular o p-valor. P-valor é a probabilidade de observar um valor mais extremo que o da hipótese nula. Se esse valor for baixo, significar que nosso poder é baixo ou a probabilidade de observar esse valor se a hipótese nula for verdadeira é baixa.

Significância estatística

Vamos ganhar um intuição da significância estatística. Para isso vamos ver como ela varia conforme alteramos alguns parâmetros.

# Função para calculo de p-valor
>>def get_pvalue(con_conv, test_conv, con_size, test_size):
lift = - abs(test_conv - con_conv)

scale_one = con_conv * (1 - con_conv) * (1 / con_size)
scale_two = test_conv * (1 - test_conv) * (1 / test_size)
scale_val = (scale_one + scale_two)**0.5

p_value = 2 * stats.norm.cdf(lift, loc = 0, scale = scale_val )

return p_value
# Ache o p-valor
>> p_value = get_pvalue(con_conv=0.1, test_conv=0.17, con_size=1000, test_size=1000)
>> print(p_value)# Ache o p-valor
>> p_value = get_pvalue(con_conv=0.1, test_conv=0.15, con_size=100, test_size=100)
>> print(p_value)# Ache o p-valor
>> p_value = get_pvalue(con_conv=0.48, test_conv=0.50, con_size=1000, test_size=1000)
>> print(p_value)Output:4.131297741047306e-06
0.28366948940702086
0.370901935824383

Observamos que um grande aumento na taxa de conversão gera confiança nos resultados, enquanto um tamanho de amostra pequeno não; e alta variância pode levar a um p-valor alto!

Vamos ver para o nosso Teste A/B, considere:

  • cont_conv: 0.09
  • test_conv: 0.10
  • cont_size: 5329
  • test_size: 5748
# Calcule p-valor
>> p_value = get_pvalue(cont_conv, test_conv, cont_size, test_size)
>> print(p_value)
# Veja a significância estatística
>> if p_value >= 0.05:
>> print("Não significativo")
>> else:
>> print("Significativo")
Output:0.04900185792087508
Significativo

Vamos explorar alguns parâmetros e ver como afeta nosso intervalo de confiança.

# Nível de confiança
>>def get_ci(value, cl, sd):
loc = sci.norm.ppf(1 - cl/2)
rng_val = sci.norm.cdf(loc - value/sd)

lwr_bnd = value - rng_val
upr_bnd = value + rng_val

return_val = (lwr_bnd, upr_bnd)
return(return_val)
>> confidence_interval = get_ci(1, 0.975, 0.5)
>> print(confidence_interval)
Output:(0.9755040421682947, 1.0244959578317054)(0.6690506448818785, 1.3309493551181215)(1.0, 1.0)

À medida que nosso desvio padrão (sd) diminui, também diminui a largura de nosso intervalo de confiança.

Agora você vai calcular os intervalos de confiança para os resultados do teste A/B com os quatro valores que foram considerados antes.

# Calcule a média de nossa distribuição
>> lift_mean = test_conv - cont_conv
# Calcular a variância e o desvio padrão
>> lift_variance = (1 - test_conv) * test_conv /test_size + (1 - cont_conv) * cont_conv / cont_size
>> lift_sd = lift_variance**0.5
# Encontre os intervalos de confiança com cl = 0,95
>> confidence_interval = get_ci(lift_mean, 0.95, lift_sd)
>> print(confidence_interval)
Output:(0.011039999822042502, 0.011040000177957487)

Observe que nosso intervalo é muito estreito por causa do grande aumento da taxa de conversão e ao grande tamanho da amostra.

Depois de concluir sua análise com sucesso, é importante comunicar os resultados com eficiência. O primeiro passo é decidir quais dados serão relatados.

1- O tamanho da amostra para cada grupo

2- Quanto tempo o teste foi realizado

3- A média e a variação de seus dois grupos, bem como os intervalos estimados de elevação e confiança

4- Fornecer alguma indicação sobre se o teste foi estatisticamente significativo ou não

Visualizar os resultados também pode ser muito útil.

# Calcule os desvios padrão
>> control_sd = cont_var**0.5
>>test_sd = test_var**0.5
# Crie o intervalo de x valores>> control_line = np.linspace(cont_conv - 3 * control_sd, cont_conv + 3 * control_sd, 100)
>> test_line = np.linspace(test_conv - 3 * test_sd ,test_conv + 3 * test_sd, 100)
# Plot
>> plt.plot(control_line, mlab.normpdf(control_line, cont_conv, control_sd))
>> plt.plot(test_line, mlab.normpdf(test_line, test_conv, test_sd))
>> plt.show()

Não vemos nenhuma sobreposição, o que intuitivamente implica que nossas taxas de conversão de teste e controle são significativamente distintas!

Agora vamos plotar a distribuição de diferença de nossos resultados, ou seja, a distribuição do aumento da taxa.

# Encontre o aumento
>> lift_mean = test_conv - cont_conv
>> lift_sd = (test_var + cont_var) ** 0.5
# Crie o intervalo de x valores
>>lift_line = np.linspace(lift_mean - 3 * lift_sd, lift_mean + 3 * lift_sd, 100)
# Plot
>> plt.plot(lift_line, mlab.normpdf(lift_line, lift_mean, lift_sd))
# Linha de anotação
>> plt.axvline(x = lift_mean, color = 'green')
>> plt.axvline(x = lwr_ci, color = 'red')
>> plt.axvline(x = upr_ci, color = 'red')
>> plt.show()

Isso contextualiza o aumento que observamos e fornece mais informações do que apenas a estimativa numérica de pontos faria. Para reforçar, nossos valores do intervalo de confiança calculados antes ficou em cima da linha que representa a média do aumento.

Bom, isso é tudo para esse artigo 🙌.

Agora você será capaz de obter insights sobre o comportamento do cliente. Definir e calcular KPIs, explorar métricas e medidas ao longo do tempo e acima de tudo: projetar e analisar um Teste A/B.

Muito obrigado pela atenção, e se gostou, deixe seu 👏!

Alguns dos exercícios foram retirados do curso de Teste A/B no Datacamp. Então se quer saber mais, não deixe de conferir!

Minhas redes: LinkdIn, GitHub

--

--