Segmentação de clientes com RFM

Mar 04 2023
Em um problema de negócios do mundo real
Em primeiro lugar, o que é RFM? O RFM é um indicador-chave composto por três métricas para entender os relacionamentos atuais dos clientes com as empresas. A análise de RFM é uma técnica amplamente utilizada, orientada por dados e baseada em regras, usada para segmentação de clientes com métricas de Recência, Frequência e Monetárias, utilizando os dados do cliente.

Em primeiro lugar, o que é RFM?

O RFM é um indicador-chave composto por três métricas para entender os relacionamentos atuais dos clientes com as empresas. A análise de RFM é uma técnica amplamente utilizada, orientada por dados e baseada em regras, usada para segmentação de clientes com métricas de Recência , Frequência e Métricas monetárias, utilizando os dados do cliente.

A análise RFM é realizada para atender melhor às necessidades de diferentes tipos de clientes separadamente. Os clientes são agrupados de acordo com seus hábitos de compra para que estratégias de negócios exclusivas possam ser desenvolvidas para esses grupos. Tratamentos individuais podem evitar a rotatividade de clientes e garantir que os clientes fiéis permaneçam assim.

Três fatores principais:

Recência refere-se à duração do tempo da última interação com o cliente. O menor valor de recência corresponde à última compra; então quanto menor melhor. Clientes mais recentes são mais valiosos.

Recência = Data da análise — Data da última compra

A frequência refere-se à frequência com que um cliente faz uma compra. Clientes frequentes são mais valiosos.

Monetário refere-se ao valor financeiro que cada cliente gastou nesta empresa.

Como comparar essas métricas?

Essas métricas são convertidas em pontuações para que sejam do mesmo tipo e possam ser comparáveis ​​entre si. Essa conversão também pode ser chamada de padronização. As pontuações provenientes das métricas são anexadas umas às outras e formam a pontuação RFM para cada cliente individual. Principalmente os clientes são classificados em relação ao valor que trazem para a empresa de 1 a 5.

As pontuações RFM podem estar em uma ampla faixa, portanto, um método é aplicado nas pontuações RFM para formar segmentos para que esses segmentos tenham insights significativos.

Segmentação através de pontuações RFM:

Tabela 1: Modelo RFM

A segmentação é comumente realizada através do gráfico 2-D mostrado na Tabela 1 . Dessa forma, as pontuações RFM fazem sentido. A análise RFM pode ajudar as empresas a conhecer seus clientes e melhorar suas estratégias de marketing de acordo.

Como visto, a pontuação monetária não está no gráfico, pois na análise de CRM a frequência e a atualidade são mais significativas do que a monetária. Quando você pensa sobre isso, a análise monetária de um cliente com poucas transações não é tão importante em comparação com clientes frequentes. Embora o valor monetário não seja explicitamente representado no gráfico, ainda é um componente importante da análise RFM e usado para fazer suposições.

Resolvendo um problema de negócios por meio do RFM:

Vamos ver como esses conceitos são aplicados em um conjunto de dados do mundo real, quais insights podem ser extraídos dos dados. Você pode acessar o código completo no meu perfil do GitHub para melhor demonstração.

Durante uma análise de dados, existem algumas etapas a serem seguidas.

1.Problema comercial

Uma empresa de comércio eletrônico com sede no Reino Unido deseja dividir seus clientes em segmentos e definir estratégias de marketing de acordo com esses segmentos. Existe um conjunto de dados que consiste nas vendas entre 12/01/2009 e 12/09/2011.

2. Compreendendo os dados

O conjunto de dados inclui 8 variáveis, a saber, fatura, código de estoque, descrição, quantidade, data da fatura, preço, ID do cliente e país. As faturas que começam com “C” são para transações canceladas. Para entender o que estamos enfrentando, precisamos dar uma olhada nos dados. A análise será feita para os anos de 2010–2011, mas também pode ser usada para os anos de 2009–2010, pois o processo será generalizado no final.

Ajustes primários (importando as bibliotecas e configurando as preferências de exibição de dados):

import datetime as dt
import pandas as pd
pd.set_option('display.max_columns', None) #to see all the columns
pd.set_option('display.float_format', lambda x: '%.3f' % x) #to have 3 decimal points

df_ = pd.read_excel("excel-file-destination.xlsx", sheet_name="Year 2010-2011")
df = df_.copy() #It takes time to read the file,thus a copy is taken after reading the file
                #so we do not have to read the file and have to wait repeatedly thoughout the analysis

df.head() #unless specified otherwise, returns the first 5 rows of the dataset
df.shape  #returns the number of the ows and columns
df.isnull().sum() #returns the number of null values in every column

      
                

Um grande conjunto de dados em questão com 541.910 linhas e 8 colunas. Mas devemos considerar todos os dados para a análise?

Temos valores ausentes principalmente nas variáveis ​​de ID e descrição do cliente. Isso significa que teremos que excluir as linhas de ID do cliente ausentes, pois a análise é específica do cliente, os dados ausentes não fornecem informações.

Vamos responder a algumas perguntas:

# Number of unique products
df["Description"].nunique()

# Number of products appearing in invoices()
df["Description"].value_counts().head()

# Most ordered product (including quantities)
df.groupby("Description").agg({"Quantity": "sum"}).sort_values("Quantity", ascending=False).head()

# Number of unique invoices
df["Invoice"].nunique()

# Add a new column for TotalPrice
df["TotalPrice"] = df["Quantity"] * df["Price"]

# Find the total cost in every invoice
df.groupby("Invoice").agg({"TotalPrice": "sum"}).head()
# needed for monetary metric

      
                

A preparação dos dados desempenha um papel importante na análise. Os dados precisam ser manipulados de forma que as inferências possam ser feitas. Os problemas neste conjunto de dados e as soluções são explicados abaixo no código.

df.shape # To observe the reducing number of rows as we make adjustments
df.isnull().sum()  # Observed problem: Missing Customer ID data, needed to be erased
df.describe().T  # Observed problem: Negative Quantitity values, no meaning, needed to be erased

df = df[(df['Quantity'] > 0)] # To solve Negative Quantitity values problem

df.dropna(inplace=True)
# To solve Missing Customer ID data problem
# Inplace makes the changes on dataset immediately without a need for assigning

df["Invoice"] = df["Invoice"].astype(str)
df = df[~df["Invoice"].str.contains("C", na=False)]
# Cancelled invoices do not need to be in the analysis, so they are erased.
# "~" means except this:

      
                

4. Cálculo de Métricas RFM

Até agora, basicamente preparamos os dados para que possamos realizar a análise RFM neles. Agora, vamos começar a análise calculando as métricas. Como não vivemos mais em 2010-2011, precisamos estabelecer uma data em que a análise será realizada. Para isso, vamos encontrar a última data e decidir um dia próximo a ela para realizar a análise.

Em seguida, as operações são feitas nas colunas InvoiceDate, Invoice e TotalPrice e agrupadas por ID do cliente para obter o quadro de dados RFM contendo métricas de Recência, Frequência e Monetárias, respectivamente.

df["InvoiceDate"].max()  # latest date on data

today_date = dt.datetime(2011, 12, 11)
# added 2 days to last day to form today's date
# utilized datetime library so that today_date's datatype is datetime

type(today_date)

rfm = df.groupby('Customer ID').agg({'InvoiceDate': lambda InvoiceDate: (today_date - InvoiceDate.max()).days,
                                     'Invoice': lambda Invoice: Invoice.nunique(),
                                     'TotalPrice': lambda TotalPrice: TotalPrice.sum()})

# In order, Recency, Frequency, Monetary are found.
# Recency is the difference in the today's date and last purchase on Customer ID level.
# Frequency is the number of unique invoices that belongs to the same customer.
# Monetary is summation of total prices of the same customer, so we know how much each customer brings to the company.

rfm.head()
# check the data
rfm.columns = ['recency', 'frequency', 'monetary']
# change the column names

rfm.describe().T # to see if there is an unsual situation

rfm = rfm[rfm["monetary"] > 0]
# min monetary = 0 is unusual, so they are excluded.

rfm.shape

      
                

5. Cálculo de pontuações de RFM:

Ao calcular as pontuações RFM, a primeira coisa a considerar é que as pontuações de recência são atribuídas para trás em comparação com a frequência e monetária por causa de seus significados.

rfm["recency_score"] = pd.qcut(rfm['recency'], 5, labels=[5, 4, 3, 2, 1])
# recency metrics divided 5 equal parts acoording to their sizes and
# labelled such a way that greatest recency got 1, the smallest recency got 5.

rfm["frequency_score"] = pd.qcut(rfm['frequency'].rank(method="first"), 5, labels=[1, 2, 3, 4, 5])
# the problem in frequency is some numbers are too repetitive that
# qcut can not label the same frequency number diffently
# rank method solves this problem by assigning the first comer number to first label.

rfm["monetary_score"] = pd.qcut(rfm['monetary'], 5, labels=[1, 2, 3, 4, 5])

rfm["RFM_SCORE"] = (rfm['recency_score'].astype(str) +
                    rfm['frequency_score'].astype(str))
# by RFM definition, string is created with recency and frequency score
# and formed final RFM Score
# monetary score is necessary for observation, but it is not used in forming RFM Score

rfm.describe().T
# newly created scores did not apper with describe function
# since they are strings and not integers

rfm[rfm["RFM_SCORE"] == "55"]
# champions

rfm[rfm["RFM_SCORE"] == "11"]
# hibernating

      
                

Para aumentar a legibilidade da tabela, vamos adicionar o que cada segmento significa para nós de acordo com a Tabela 1 .

RegEx (expressões regulares) contém correspondências que obedecem a um determinado padrão dentro de uma série. Esta é a parte em que extraímos insights dos dados.

# regex
# RFM Naming (Pattern Matching)
seg_map = {
    r'[1-2][1-2]': 'hibernating',
    r'[1-2][3-4]': 'at_Risk',
    r'[1-2]5': 'cant_loose',
    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'
}
#  Basically the R-F table is coded using regex.

rfm['segment'] = rfm['RFM_SCORE'].replace(seg_map, regex=True)
segment_analysis = rfm[["segment", "recency", "frequency", "monetary"]].groupby("segment").agg(["mean", "count"])


rfm[rfm["segment"] == "cant_loose"].head()
cant_loose_customers = rfm[rfm["segment"] == "cant_loose"].index
#  A list of customers which the company should be more careful with is formed.
#  This way, every segment of customers is accesible. 

new_df = pd.DataFrame()
#  Empty dataframe is formed

new_df["new_customer_id"] = rfm[rfm["segment"] == "new_customers"].index
new_df["new_customer_id"] = new_df["new_customer_id"].astype(int)
#  To get rid of the decimals

new_df.to_csv("new_customers.csv")
rfm.to_csv("rfm.csv")
#  Segment information is extracted into an excel file.

      
                

De acordo com os princípios básicos de programação, como DRY (Don't Repeat Yourself), a funcionalização de todo esse processo é obrigatória. Assim, podemos usar esta função, daí a Análise RFM, em diferentes quadros de dados repetidamente.

Versão limpa de todos os dados acima escritos na função abaixo em nome de create_rfm com a opção de criar um arquivo csv.

def create_rfm(dataframe, csv=False):

PS Muito obrigado por dedicar seu tempo para ler tudo isso. Eu compartilho enquanto aprendo, então um novo artigo relacionado à ciência de dados será lançado toda semana. Espero que este post ajude você também. Não hesite em deixar um comentário :) Boa sorte em sua própria jornada de ciência de dados.

Conecte-se comigo no LinkedIn

Conecte-se comigo no Medium

Referência:

  • Vídeos de palestras Miuul