Segmentação de Clientes com RFM em Python

Larissa Gomes
11 min readNov 22, 2023

--

Neste artigo, compartilho um projeto sobre segmentação de clientes para um aplicativo de entrega de comida. Eu usei esse mesmo aplicativo por dois anos e recentemente me deparei com o case técnico da empresa para uma vaga de analista de dados.

⚡️ Wolt é um serviço de delivery muito popular em alguns países europeus e que me serviu muito bem enquanto vivi na Hungria. É uma app similar ao iFood no Brasil.
❤️ Alguns dos fatores que me mantiveram fiel a essa app (estamos falando de quase R$ 15.000,00 gastos!) foram um nível excelente de atendimento ao cliente ( funcionários proativos trazendo soluções antes mesmo de você notar o problema) e uma interface limpa, objetiva e fácil de usar, além dos frequentes cupons promocionais.

Minha análise foi feita em um notebook que pode ser encontrado no meu github. Ela utiliza de conceitos como RFM e K-Means, sendo o primeiro o único foco deste post. Você pode acompanhar o projeto completo neste 📙link.

Sumário
1. O que é exatamente o RFM?
2. Visão geral dos dados
3. Como calcular o Score RFM?
4. Segmentação e Próximos Passos
5. Considerações Finais

O que é exatamente o RFM?

Começando do início: a segmentação RFM é uma forma de agrupar clientes com base em seu comportamento de compra. Ele coloca um cliente em diferentes categorias, dependendo de quão recente foi sua última transação, da frequência com que compra e do valor monetário gasto. O que diferencia o RFM de outros métodos é que ele analisa apenas o comportamento do cliente com base em dados históricos (geralmente transações) e nada mais. Não são consideradas questões demográficas como localização, idade, sexo, hobbies ou outros aspectos dessa natureza.
É um sistema baseado em pontuação que cria uma classificação de clientes com base nas seguintes métricas: Recência, Frequência e Monetário. Vamos falar sobre cada uma dessas métricas.

Recência (recency) — refere-se ao tempo decorrido desde a última transação de um cliente. Ela mede a atualidade da compra de um cliente. Por exemplo, se um cliente fez um pedido pelo aplicativo no dia 1º de novembro e hoje é 1º de dezembro, a recência seria de 30 dias.

Frequência (frequency) — é uma medida da frequência com que os clientes fazem compras, que é determinada pelo número total de transações que eles realizam durante um período. Como exemplo, vamos considerar outro usuário do aplicativo que fez seu primeiro pedido no dia 7 de outubro e o segundo (e mais recente) no dia 6 de novembro. Neste caso, sua frequência é 2.

Valor Monetário (monetary) — refere-se à quantidade de dinheiro que um cliente gasta em compras. Como métrica essencial, ajuda a determinar o valor do cliente para o negócio. Para ilustrar, vamos considerar o cenário anterior em que o cliente fez duas compras — suponha $ 23 para o primeiro pedido e $ 17 para o segundo. Nesse caso, o valor monetário seria de $ 40.

As empresas podem aproveitar essas métricas para identificar seus clientes mais valiosos e seus padrões de compra, impulsionando campanhas de marketing direcionadas e comunicação personalizada de acordo com cada usuário.

Visão geral dos dados

O dataset com o qual estou trabalhando consiste em um csv com dados de usuário de um aplicativo de entrega de comida. Cada linha representa um cliente único que se cadastrou para utilizar o serviço de setembro de 2019 a outubro de 2020. Nesse período, os clientes podem ou não ter feito compras.

O arquivo em si está no formato JSON e foi parseado de forma a ser legível como dataframe com pandas.

.head() para visualizar as 5 primeiras linhas e, no rodapé, a quantidade de colunas

Valores Nulos e suas respectivas porcentagens

Algo que aprendi com o tempo é que toda vez que alguém menciona que “ coluna y tem muitos valores nulos”, isso é quase sempre seguido por uma pergunta como “a quantidade de nulos é expressiva em relação ao total?”.
Já sabendo disso, costumo adotar a seguinte função para entender melhor a porcentagem desses valores em cada coluna:

# retornar o tipo de dado em cada coluna e a porcentagem de nulos
def table_review(df):
isnull = df.isnull().sum()
type_columns = df.dtypes
pre = round((isnull/len(df))*100, 2)
dc = pd.DataFrame({"Type":type_columns,
"Isnull":isnull,
"Missing data ٪":pre})
print(dc.sort_values(by = "Missing data ٪", ascending = False))

É possível ver que temos colunas com uma quantidade considerável (>64%) de valores nulos. Apesar disso, as colunas que serão essenciais para a nossa análise não aparentam ter problemas que possam comprometer os resultados.

Limpeza dos Dados

A fim de que as colunas necessárias para a nossa análise estejam adequadas, os seguintes passos foram tomados:

  • purchase_count foi filtrado para mostrar apenas valores diferentes de zero, que corresponde aos usuários registrados que realizaram transações;
  • registration_date, first_purchase e last_purchase foram convertidos para datetime.

Análise Inicial

🛍️ Quanto tempo leva para um novo usuário realizar um pedido?

Um fator que despertou a minha curiosidade foi investigar as primeiras compras que os usuários fazem no aplicativo. Quando fiz o download da app eu já tinha — além da fome — intenção de fazer minha primeira compra. Entretanto cogitei a possibilidade de que outros usuários baixem o aplicativo, naveguem sem compromisso e deixem instalado “pra se um dia precisar”.

Assim, defini a função abaixo para analisar melhor quanto tempo leva para que um novo usuário faça sua primeira compra.

def first_order(df):
registr_date = df['registration_date']
order_date = df['first_purchase_day']
wating_day = order_date - registr_date
total = len(wating_day)
wating_table = pd.DataFrame({"Wating_day": wating_day, "count": 1})
count_wating_day = wating_table.groupby(["Wating_day"]).count().sort_values("count", ascending = False)
count_wating_day.reset_index(drop = True, inplace = True)
count_wating_day["percentage %"] = (count_wating_day["count"]/total)*100
return count_wating_day

Podemos constatar que quase metade dos clientes fazem o primeiro pedido no mesmo dia do cadastro. No entanto, o número de pedidos iniciais diminui rapidamente depois disso, seguindo um padrão semelhante ao de uma função exponencial.
No segundo dia, apenas 4% dos clientes fazem o primeiro pedido, e isso reduz ainda mais para menos de 2% no terceiro dia.

👉 Com base nesta tendência, o segundo dia oferece uma oportunidade ideal para a equipe de marketing envolver os clientes de forma proativa e incentivá-los a fazer um pedido. Neste ponto, os clientes ainda podem estar abertos a ofertas promocionais ou incentivos que possam motivá-los a fazer uma compra.

Como calcular o Score RFM?

Primeiramente, vamos definir o período da nossa análise e a data de referência que utilizaremos como parâmetro.

  • O dataset vai de setembro de 2019 a outubro de 2020, tendo como data mais recente 31–10–2020.
  • A data de referência today_dateque eu decidi adotar foi o dia 02–11–2020 por possibilitar valores consistentes com os nossos dados.

Em seguida, criamos uma nova tabela com as seguintes variáveis:

  • user_id — coluna já presente no nosso dataframe (df)
  • recency — subtração da variável today_date e last_purchase_day
  • frequency — equivalente à coluna purchase_count
  • monetary — equivalente à coluna total_purchases_eur
df["recency"] = (today_date - pd.to_datetime(df["last_purchase_day"])).dt.days
df["frequency"] = df["purchase_count"]
df["monetary"] = df["total_purchases_eur"]
rfm = df[["user_id", "recency", "frequency", "monetary"]]
rfm

O próximo passo é calcular o score. Para isso, temos que converter as métricas RFM (Recency, Frequency, Monetary) em pontuações para tornar a análise mais eficaz e precisa. A razão para isso é que não é possível comparar essas métricas diretamente.

Para converter valores RFM em pontuações, usamos a função qcut(), que é uma função de discretização baseada em quantil. No nosso caso, essa função categoriza os valores métricos em valores (score) de 1–2–3–4–5, dependendo da frequência de sua ocorrência. Quanto maior o score, mais valioso o cliente é para o negócio.

# Recency score
rfm["recency_score"] = pd.qcut(rfm["recency"], q= 5, labels=[5,4,3,2,1]
# Frequency Score
rfm["frequency_score"] = pd.qcut(rfm["frequency"].rank(method="first"), 5, labels=[1, 2, 3, 4, 5])
# Monetary Score
rfm["monetary_score"] = pd.qcut(rfm["monetary"], 5, labels=[1, 2, 3, 4, 5])
# RFM Score
rfm["rfm_score"] = (rfm['recency_score'].astype(str) + rfm['frequency_score'].astype(str))
  • recency_score — foi dividido em 5 partes iguais e classificados de forma decrescente (quanto menor a recência, maior a pontuação).
  • frequency_score — os números de frequency tendem a ser repetitivos a ponto de a função qcut não conseguir decidir em que categoria encaixar a mesma frequência. Para tal, durante o processo de cálculo de frequência, empregamos rank(method=”first”) para identificar a ocorrência inicial e atribuí-la como valor do quartil. Essa abordagem resolve efetivamente o problema em questão.
  • monteary_score — divido em 5 partes iguais de forma que quanto maior o monetary , maior o score.
  • rfm_score — é um string resultante da concatenação dos scores de recency e frequency. Nesta análise optamos por não utilizar o monetary_score .

Segmentação dos RFM Scores

A frequência das transações tende a ser o fator mais importante. Isso se dá porque um cliente que interage com a marca gera mais oportunidades de lucro com a implementação de estratégias que levam ao aumento das vendas. Dessa forma, por mais alto que seja o valor monetário, ele se torna menos significante para um consumidor com baixa frequência e, portanto, com baixa probabilidade de transações.

Portanto, a nossa segmentação é focada em dois fatores: recency e frequency.

seg_map = {
r'[1-2][1-2]': 'hibernating',
r'[1-2][3-4]': 'at_risk',
r'[1-2]5': 'cant_lose',
r'3[1-2]': 'about_to_sleep',
r'33': 'need_attention',
r'[3-4][4-5]': 'loyal_customers',
r'41': 'promising',
r'51': 'new_customers',
r'[4-5][2-3]': 'potential_loyalists',
r'5[4-5]': 'champions'
}
rfm['segment'] = rfm['rfm_score'].replace(seg_map, regex=True)

Finalmente, classificamos os intervalos de segmentos de RFM com regex. Substituímos então os scores pelos segmentos correspondentes abaixo, que farão parte do resto da análise.

Champions — compraram recentemente, compram com frequência e gastam mais.
Loyal Customers — gastam um bom dinheiro e respondem bem às promoções.
Potential Loyalists — clientes recentes, que gastaram uma boa quantia e compraram mais de uma vez.
New Customers — compraram recentemente, mas não com frequência.
Promissing — compradores recentes, mas que não gastaram muito.
Need Attention — recência, frequência e valores monetários acima da média; mas podem não ter comprado muito recentemente.
About To Sleep — recência, frequência e valores monetários abaixo da média; serão perdidos se não forem reativados.
At Risk — gastaram muito dinheiro e compraram com frequência, mas há muito tempo; é preciso trazê-los de volta.
Can’t Lose Them — fizeram compras grandes e muitas vezes, mas não voltam a realizar transações há muito tempo.
Hibernating — a última compra foi há muito tempo, pouco gastadores e baixo número de pedidos.

Treemap gerado com Plotly Express.

Outra forma de visualização é com um heatmap. Abaixo temos os valores médios das nossas métricas para cada um dos segmentos.

Heatmap gerado com Plotly Express.

Segmentação e Próximos Passos

O modelo RFM pode ajudar as empresas a ver os clientes novos e existentes sob uma luz diferente. Isso ajuda a criar condições favoráveis para maximizar o valor de vida do cliente. É importante encontrar o equilíbrio certo entre focar nos clientes novos e existentes, bem como reconhecer as nuances do seu comportamento. Isso permite que as empresas criem personalizações personalizadas, gerando confiança e fidelidade à marca.

💡 Tomando nossa análise como exemplo, destaquei ações que podem ser tomadas para os três maiores segmentos:

  • Hibernating — como representam nosso maior grupo (29% do total), seria interessante interagir com esse segmento. Já que a recency é grande, temos que focar em construir valor para a marca novamente. A recomendação de produtos relevantes e descontos especiais podem despertar novamente o interesse desse tipo de cliente.
  • Loyal Customers — programas de fidelidade e recomendação são fortes aliados aqui. Podemos oferecer um desconto por cada novo usuário que esses clientes recomendarem. Além disso, podemos criar um sistema de colecionamento de recompensas como por exemplo: se o cliente efetuar 5 diferentes pedidos em uma rede de cafeterias, recebe um capuccino grátis na próxima compra.
  • Champions — por serem os melhores clientes, é essencial recompensá-los. Recomendo fazer com que eles se sintam especiais! Podemos mostrar recomendações de restaurantes de acordo com o histórico de compras, criar ofertas de aniversário e priorizá-los em testes de novos produtos.

É importante ressaltar que podemos criar campanhas para os segmentos menos expressivos também, mas pra não me alongar optei pelos descritos acima.

🍝 Considerações finais

A análise RFM é uma dentre diversas outras formas de segmentar clientes, possuindo naturalmente vantagens e desvantagens em relação a outros métodos.

Gosto de encerrar meus projetos pensando o que eu tera feito de diferente se tivesse mais tempo. Neste caso, como temos um dataset com com diversas colunas que carecterizam os clientes, eu teria levantado as seguintes questões:

  • Existe relação entre o número de pedidos e a distância média entre o restaurante e a casa do cliente?
  • Quão abertos são os usuários a explorar novos restaurantes?
  • Quem pede café da manhã tende a pedir almoço? Existe relação entre pedir diferentes combinações de refeições durante o dia ?
  • Quem são os usuários que pedem mais comida na hora do almoço?

Este mesmo projeto conta ainda com segmentação por K-Means, que eu vou compartilhar num próximo post.

✨ Agora a conclusão que mais importa (pra mim): já que eu sou (fui) usuária desse app, em que segmento eu me encaixaria?
Tendo feito 341 pedidos, gastado mais de 1 milhão de forints e não tendo efetuado compras nos últimos 12 meses, penso que estou na categoria “At Risk”, mas imagino que quando ainda estava ativa, fui categorizada como “Champion”.

Ao abrir a interface web, notei algumas campanhas que aparentam ter cunho direcionado:

À esquerda: um convite para estar entre os primeiros a testar por 1 mês grátis a subscrição. À direita: campanha de recomendação.
Após uma grande frequência de compras, o Wolt criou minha lista de favoritos, que por coincidência (ou não) tem descontos ❤️

☕️ Gostou? Então fala comigo 🙂 !

  • Você pode ver esse projeto no meu Github.
  • Estou disponível no Linkedin.

📊 Convido-te também a ver esse meu dashboard no Tableau com tudo que eu mais pedi no Wolt!

--

--