![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
---|---|---|---|---|---|
R Studio | Ggplot2 | Plotly | Tidyverse | Caret | Readxl |
- RStudio: Ambiente integrado para desenvolvimento em R, oferecendo ferramentas para escrita, execução e depuração de código.
- Ggplot2: Pacote para criação de visualizações de dados elegantes e flexíveis em R.
- Plotly: Biblioteca interativa para criação de gráficos e visualizações em diversas linguagens.
- Tidyverse: Conjunto de pacotes para manipulação de dados, visualização e modelagem em R, seguindo o paradigma "tidy data".
- Caret: Pacote para treinamento e avaliação de modelos de machine learning em R.
- Readxl: Pacote para leitura de dados em formato Excel (XLSX/XLS) em R, facilitando a importação de planilhas para análise de dados.
Realizar a análise de cliente pelo método RFM :
- Recência: quão recente um cliente fez a compra;
- Frequência: com que frequência um cliente faz a compra;
- Valor Monetário: quanto dinheiro um cliente gasta em compras.
De acordo com essas métricas, é possível segmentar os clientes em grupos para entender quais deles compram muitas coisas com frequência, que compram poucas coisas, mas frequentemente, e que não compram nada há muito tempo.
Base de dados: https://archive.ics.uci.edu/dataset/502/online+retail+ii
# Ajustar as casas decimais
options(scipen = 999, digits = 4)
# Definir um espelho de CRAN
options(repos = "http://cran.rstudio.com/")
Esta seção apresenta a importando das bibliotecas necessárias para manipulações e tratamento dos dados e também a importação do arquivo excel (.xls) da base de dados.
library(dplyr)
# Lista dos pacotes necessários
pacotes <- c('tidyverse', 'ggplot2', 'caret', 'plotly',
'readxl', 'rfm', 'stats','factoextra','plyr')
# Verifica se NÃO está instalado, se for verdadeiro
# Instala e carrega o pacote
pacotes %>%
lapply(function(pacote){
if (!require(pacote, character.only = TRUE)) {
install.packages(pacote)
library(pacote, character.only = TRUE)
}
})
# Verificar os pacotes instalados
list(search())
# Carregar os dados da planilha
plan1 <- read_excel('online+retail+ii/online_retail_II.xlsx', sheet = 'Year 2009-2010')
plan2 <- read_excel('online+retail+ii/online_retail_II.xlsx', sheet = 'Year 2010-2011')
df <- rbind(plan1, plan2)
- InvoiceNo: Número da fatura. Nominal. Um número integral de 6 dígitos atribuído exclusivamente a cada transação. Se esse código começar com a letra 'c', ele indica um cancelamento;
- StockCode: Código do produto (item). Nominal. Um número integral de 5 dígitos atribuído exclusivamente a cada produto distinto;
- Description: Nome do produto (item);
- Quantity: As quantidades de cada produto (item) por transação. Numérico;
- InvoiceDate: Data e hora invictas. Numérico. O dia e a hora em que uma transação foi gerada;
- UnitPrice: Preço unitário. Numérico. Preço do produto por unidade em libras esterlinas (£);
- CustomerID: Número do cliente. Nominal. Um número integral de 5 dígitos atribuído exclusivamente a cada cliente;
- Country: Nome do país. Nominal. O nome do país onde o cliente reside.
Nesta seção será explorado as variáveis para identificar os possíveis padrões e comportamentos, valores nulos, outliers e engenharia de atributos, se necessário.
# Carregar as 10 primeiras entradas do dataset
head(df)
sample(df)
Invoice | StockCode | Description | Quantity | InvoiceDate | Price | Customer ID | Country |
---|---|---|---|---|---|---|---|
489434 | 85048 | 15CM CHRISTMAS GLASS BALL 20 LIGHTS | 12 | 2009-12-01 07:45:00 | 6.95 | 13085 | United Kingdom |
489434 | 79323P | PINK CHERRY LIGHTS | 12 | 2009-12-01 07:45:00 | 6.75 | 13085 | United Kingdom |
489434 | 79323W | WHITE CHERRY LIGHTS | 12 | 2009-12-01 07:45:00 | 6.75 | 13085 | United Kingdom |
489434 | 22041 | RECORD FRAME 7" SINGLE SIZE | 48 | 2009-12-01 07:45:00 | 2.10 | 13085 | United Kingdom |
489434 | 21232 | STRAWBERRY CERAMIC TRINKET BOX | 24 | 2009-12-01 07:45:00 | 1.25 | 13085 | United Kingdom |
489434 | 22064 | PINK DOUGHNUT TRINKET POT | 24 | 2009-12-01 07:45:00 | 1.65 | 13085 | United Kingdom |
# Analisar as dimensões do dataset (linhas x colunas)
dim(df)
[1] 1067371 8
# Verificar o nome das variáveis(colunas)
names(df)
[1] "Invoice" "StockCode" "Description" "Quantity"
[5] "InvoiceDate" "Price" "Customer ID" "Country"
# Verificar o tipo das variáveis
str(df)
tibble [1,067,371 × 8] (S3: tbl_df/tbl/data.frame)
- $ Invoice : chr [1:1067371] "489434" "489434" "489434" "489434" ...
- $ StockCode : chr [1:1067371] "85048" "79323P" "79323W" "22041" ...
- $ Description: chr [1:1067371] "15CM CHRISTMAS GLASS BALL 20 LIGHTS" "PINK CHERRY LIGHTS" "WHITE CHERRY LIGHTS" "RECORD FRAME 7" SINGLE SIZE" ...
- $ Quantity : num [1:1067371] 12 12 12 48 24 24 24 10 12 12 ...
- $ InvoiceDate: POSIXct[1:1067371], format: "2009-12-01 07:45:00" ...
- $ Price : num [1:1067371] 6.95 6.75 6.75 2.1 1.25 1.65 1.25 5.95 2.55 3.75 ...
- $ Customer ID: num [1:1067371] 13085 13085 13085 13085 13085 ...
- $ Country : chr [1:1067371] "United Kingdom" "United Kingdom" "United Kingdom" "United Kingdom" ...
# Transformando a variável "country" em factor, devido ser categórica nominal
table(df$Country)
df$Country <- as.factor(df$Country)
# Verificando os valores nulos das variáveis
colSums(is.na(df))
Invoice | StockCode | Description | Quantity | InvoiceDate | Price | Customer ID | Country |
---|---|---|---|---|---|---|---|
0 | 0 | 4382 | 0 | 0 | 0 | 243007 | 0 |
Como trabalharemos com operações matemáticas, será necessário que as variáveis não apresentem valores nulos, bem como a dimensão da base possui 1067371 linhas, então removeremos os valores ausentes das variáveis "Description" e "Customer ID", pois não podemos inputar nenhuma informação para suprir essas ausências, visto que irá influenciar nas estatísticas de compra do cliente e portanto na análise RFM.
# Criando uma coluna de Preço Total
df$Total_Price <- df$Quantity * df$Price
head(df$Total_Price)
[1] 83.4 81.0 81.0 100.8 30.0 39.6
# Criando uma cópia do dataset original
df_copy <- df
# Removendo os valores ausentes do dataset
df_copy <- na.omit(df)
# Seleciona os valores que NÃO são do tipo C na coluna "Invoice"
df_copy <- df_copy[!grepl("C",df_copy$Invoice),]
dim(df_copy)
# Resultado final do dataset após a limpeza
print(paste0("Foram removidas: ",
dim(df)[1] - dim(df_copy)[1],
"(",
round(((dim(df)[1] - dim(df_copy)[1])/dim(df)[1]) * 100, digits = 2),
"%) linhas após a limpeza"))
[1] 805620 9
[1] "Foram removidas: 261751(24.52%) linhas após a limpeza"
# Verificando a disposição da variável "Total_Price"
ggplot(
df_copy,
mapping = aes(x = Total_Price)) +
geom_density(fill = "#ff79ae", color = "#282a36", alpha = 3.5) +
labs(title = "Distribuição da variável Total_Price")
# Quantidade de transações
length(df_copy$`Customer ID`)
[1] 805620
# Quantidade de clientes
length(unique(df_copy$`Customer ID`))
[1] 5881
# Transformando em data table
df_copy <- data.table::data.table(df_copy)
# Valor Monetário por cliente
valor_monetario <- df_copy[,.(Total = sum(Total_Price)), by = `Customer ID`][order(desc(Total))]
print(valor_monetario)
Customer ID | Total |
---|---|
18102 | 608822 |
14646 | 528603 |
14156 | 313946 |
14911 | 295973 |
17450 | 246973 |
13694 | 196483 |
17511 | 175604 |
16446 | 168473 |
16684 | 147143 |
12415 | 144458 |
print(summary(valor_monetario$Total))
Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. |
---|---|---|---|---|---|
0 | 348 | 898 | 3017 | 2304 | 608822 |
# Cálculo da Recência
max(df_copy$InvoiceDate)
data_ref <- as.Date.character("25/12/2011", "%d/%m/%Y")
converter_data <- function(x){
options(digits.secs = 3)
return(as.Date(as.POSIXct(x$InvoiceDate,'GMT')))
}
# Alterando a coluna InvoiceDate para ocultar o horário
df_copy$InvoiceDate <- converter_data(df_copy)
head(df_copy)
# Calculando o RFM
calculo_rfm <- df_copy[,
.(Recencia = as.numeric(data_ref - max(InvoiceDate)),
Frequencia = .N,
Monetario = sum(Total_Price),
Primeira_compra = min(InvoiceDate)),
by = `Customer ID`]
calculo_rfm
Customer ID | Recencia | Frequencia | Monetario | Primeira_compra |
---|---|---|---|---|
13085 | 173 | 84 | 2433.28 | 2009-12-01 |
13078 | 19 | 801 | 29532.45 | 2009-12-01 |
15362 | 464 | 40 | 613.08 | 2009-12-01 |
18102 | 16 | 1058 | 608821.65 | 2009-12-01 |
12682 | 19 | 1039 | 24033.91 | 2009-12-01 |
18087 | 114 | 88 | 14761.52 | 2009-12-01 |
13635 | 83 | 162 | 2999.16 | 2009-12-01 |
14110 | 19 | 400 | 12987.95 | 2009-12-01 |
12636 | 754 | 1 | 141.00 | 2009-12-01 |
17519 | 33 | 222 | 5109.47 | 2009-12-01 |
# Removendo os Outliers (Valores muito distantes da média)
Q1 <- quantile(calculo_rfm$Monetario, .25)
Q3 <- quantile(calculo_rfm$Monetario, .75)
IQR <- IQR(calculo_rfm$Monetario)
calculo_rfm <- subset(
calculo_rfm,
calculo_rfm$Monetario >= (Q1 - 1.5*IQR) &
calculo_rfm$Monetario <= (Q3 + 1.5*IQR)
)
head(calculo_rfm)
Customer ID | Recencia | Frequencia | Monetario | Primeira_compra |
---|---|---|---|---|
13085 | 173 | 84 | 2433.3 | 2009-12-01 |
15362 | 464 | 40 | 613.1 | 2009-12-01 |
13635 | 83 | 162 | 2999.2 | 2009-12-01 |
12636 | 754 | 1 | 141.0 | 2009-12-01 |
17519 | 33 | 222 | 5109.5 | 2009-12-01 |
16321 | 88 | 23 | 604.6 | 2009-12-01 |
Nesta seção será criado um modelo de algoritmo não supervisionado do tipo Cluster Kmeans, na qual agrupa os dados em clusters (grupos) com base em suas características, sem a necessidade de rótulos prévios. O algoritmo tenta encontrar estruturas nos dados agrupando-os em um número pré-definido de clusters, minimizando a variação dentro de cada cluster e maximizando a variação entre os clusters.
# Set seed
set.seed(42)
# Cria uma lista
resultados <- list()
# Filtrando somente as colunas necessárias
dados_rfm <- calculo_rfm %>%
select(Recencia, Frequencia, Monetario)
dados_rfm
Recencia | Frequencia | Monetario |
---|---|---|
173 | 84 | 2433.28 |
464 | 40 | 613.08 |
83 | 162 | 2999.16 |
754 | 1 | 141.00 |
33 | 222 | 5109.47 |
88 | 23 | 604.55 |
430 | 63 | 1386.12 |
754 | 13 | 148.30 |
25 | 166 | 3472.41 |
443 | 115 | 1703.07 |
# Cria o modelo e divide em 5 grupos
# com base na distância entre os pontos
modelo_kmeans <- kmeans(dados_rfm,
centers = 5,
iter.max = 50)
# Verificando o modelo criado
modelo_kmeans
# Plot do modelo
resultados$plot <- fviz_cluster(modelo_kmeans,
data = dados_rfm,
geom = c('point'),
ellipse.type = 'euclid')
# Organiza os dados
# Retornando os dados do ID para identificar os clientes
dados_rfm$Customer_ID <- calculo_rfm$`Customer ID`
dados_rfm$clusters <- modelo_kmeans$cluster
resultados$data <- dados_rfm
grafico <- resultados[1]
grafico
tab <- as.data.frame(resultados[2])
head(tab)
Recencia | Frequencia | Monetario | Customer_ID | Clusters |
---|---|---|---|---|
173 | 84 | 2433.3 | 13085 | 1 |
464 | 40 | 613.1 | 15362 | 2 |
83 | 162 | 2999.2 | 13635 | 1 |
754 | 1 | 141.0 | 12636 | 2 |
33 | 222 | 5109.5 | 17519 | 5 |
88 | 23 | 604.6 | 16321 | 4 |
# Analisando os resultados da tabela dos cliente
clusters_clientes <- data.table::data.table(tab)
# Frequência dos clientes por Clusters
clusters_clientes[,
.(Total = .N),
by = data.clusters
][order(desc(Total))]
data.clusters | Total |
---|---|
2 | 2376 |
4 | 1352 |
3 | 734 |
1 | 473 |
5 | 318 |
# Média de Recencias por clusters
clusters_clientes[,
.(Media_recencia = median(data.Recencia),
Media_frequencia = median(data.Frequencia),
Media_monetario = median(data.Monetario)),
by = data.clusters
]
data.clusters | Media_recencia | Media_frequencia | Media_monetario |
---|---|---|---|
1 | 55.0 | 159 | 2951.1 |
2 | 349.5 | 19 | 293.6 |
5 | 47.0 | 228 | 4370.4 |
4 | 96.0 | 56 | 949.5 |
3 | 83.0 | 103 | 1823.7 |
# Plotagem dos gráficos de RFM
plotagem <- function(coluna){
titulo_coluna <- substr(coluna, 6, nchar(coluna))
# Criar o boxplot com Plotly
boxplot_plotly <- plot_ly(data = clusters_clientes,
x = ~data.clusters,
y = ~get(coluna),
type = "box"
) %>%
layout(title = paste("Boxplot de ", titulo_coluna, " por cluster"),
xaxis = list(title = "Cluster"),
yaxis = list(title = titulo_coluna))
# Exibir o boxplot
return(boxplot_plotly)
}
plotagem("data.Recencia")
plotagem("data.Frequencia")
plotagem("data.Monetario")
-
Recência Média: A recência média representa o quão recentemente os clientes de um cluster realizaram uma transação. Dentro deste contexto, o cluster 5 apresenta a melhor média (menor), indicando que são possíveis usuários mais ativos e/ou engajados com a marca. Em contrapartida, o cluster 2 apresenta uma média 7 vezes maior que o cluster 5, possivelmente este grupo não está envolvido com a marca ou estão se afastando;
-
Frequência Média: A frequência média indica com que frequência os clientes de um cluster realizam transações. O cluster 5 apresenta uma frequência média de 228, indicando clientes possivelmente fiéis e que retornam regularmente para realizarem novas compras. O cluster 2 apresenta um frequência de 19, indicando clientes menos engajados e que realizam compras de forma esporádicas;
-
Valor Monetário Médio: O valor monetário representa o valor médio das transações realizadas pelos clientes de um cluster. O cluster 5 apresenta uma média de 4370.4, demonstrando que os clientes estão gastando mais em cada transação, o que indica maior lealdade ou interesse em serviços e nos produtos da marca.