Este es un conjunto de datos transaccionales que contiene todas las transacciones ocurridas entre el 01/12/2010 y el 09/12/2011 para un comercio minorista en línea no registrado y con sede en el Reino Unido.
La empresa vende principalmente regalos únicos para todas las ocasiones. Muchos clientes de la empresa son mayoristas.
Se pretende hacer una segmentacion Cluster global de todos los clientes de este dataset y de algun subsegmento especifico (cluster) en funcion de las conclusiones derivadas a tal efecto.
Para ello hemos abordado un analisis RFM (Recency,Frequency,Monetary Value), para luego poder sacar conclusiones de los posibles hallazgos e inclusive indicios de las posibles estrategias de marketing que podemos emplear dependiendo del segmento o subsegmento en cada caso que analicemos.
El Análisis RFM es una técnica de segmentación del comportamiento del cliente basada en datos.
La segmentación de clientes se utiliza en marketing para comprender mejor a los clientes de una empresa y dirigirse a ellos en consecuencia.
La idea es segmentar a los clientes en base a cuándo fue su última compra, con qué frecuencia han comprado en el pasado y cuánto han gastado en total.
Recency: Días transcurridos desde la última compra.
Frequency: Número de compras por período de tiempo, como promedio.
Monetary(Valor monetario): Valor de las compras totales realizadas por el cliente en el tiempo de análisis.
library(tidyverse)
## Warning: package 'tibble' was built under R version 4.1.3
library(NbClust)
library(cluster)
library(gmodels)
library(factoextra)
library(kableExtra)
library(cluster)
library(cowplot)
library(rpart)
library(rpart.plot)
library(clValid)
library(ggpubr)
## Warning: package 'ggpubr' was built under R version 4.1.3
-Cargamos los datos, ponemos como na los datos en blanco vacios, y eliminamos los na de nuestros datos.
ecommerce <- read.csv("data-2.csv", na= "")
colSums(is.na(ecommerce))
## InvoiceNo StockCode Description Quantity InvoiceDate UnitPrice
## 0 0 1454 0 0 0
## CustomerID Country
## 135080 0
ecom_dt <- na.omit(ecommerce)
colSums(is.na(ecom_dt))
## InvoiceNo StockCode Description Quantity InvoiceDate UnitPrice
## 0 0 0 0 0 0
## CustomerID Country
## 0 0
Eliminamos datos duplicados del dataset.
dt_ecom <- ecom_dt[!duplicated(ecom_dt), ]
dt_ecom$InvoiceDate <- as.POSIXct(dt_ecom$InvoiceDate, tryFormats = '%m/%d/%Y %H:%M')
kable_styling(kable(head(dt_ecom)))
| InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country |
|---|---|---|---|---|---|---|---|
| 536365 | 85123A | WHITE HANGING HEART T-LIGHT HOLDER | 6 | 2010-12-01 08:26:00 | 2.55 | 17850 | United Kingdom |
| 536365 | 71053 | WHITE METAL LANTERN | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 84406B | CREAM CUPID HEARTS COAT HANGER | 8 | 2010-12-01 08:26:00 | 2.75 | 17850 | United Kingdom |
| 536365 | 84029G | KNITTED UNION FLAG HOT WATER BOTTLE | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 84029E | RED WOOLLY HOTTIE WHITE HEART. | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 22752 | SET 7 BABUSHKA NESTING BOXES | 2 | 2010-12-01 08:26:00 | 7.65 | 17850 | United Kingdom |
str(dt_ecom)
## 'data.frame': 401604 obs. of 8 variables:
## $ InvoiceNo : chr "536365" "536365" "536365" "536365" ...
## $ StockCode : chr "85123A" "71053" "84406B" "84029G" ...
## $ Description: chr "WHITE HANGING HEART T-LIGHT HOLDER" "WHITE METAL LANTERN" "CREAM CUPID HEARTS COAT HANGER" "KNITTED UNION FLAG HOT WATER BOTTLE" ...
## $ Quantity : int 6 6 8 6 6 2 6 6 6 32 ...
## $ InvoiceDate: POSIXct, format: "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ UnitPrice : num 2.55 3.39 2.75 3.39 3.39 7.65 4.25 1.85 1.85 1.69 ...
## $ CustomerID : int 17850 17850 17850 17850 17850 17850 17850 17850 17850 13047 ...
## $ Country : chr "United Kingdom" "United Kingdom" "United Kingdom" "United Kingdom" ...
## - attr(*, "na.action")= 'omit' Named int [1:135080] 623 1444 1445 1446 1447 1448 1449 1450 1451 1452 ...
## ..- attr(*, "names")= chr [1:135080] "623" "1444" "1445" "1446" ...
-Constitucion de las columnas RFM por las cuales se hace la segmentacion:
Frequency_Customer
Freq_Customer <- dt_ecom %>%
group_by(CustomerID)%>%
summarise(Frequency = n())
Monetary Value
Mon_Value <- dt_ecom %>%
mutate(Revenue = Quantity * UnitPrice) %>%
group_by(CustomerID) %>%
summarise(M_Value=sum(Revenue))
Recency
Cust_Recency <- dt_ecom %>%
group_by(CustomerID) %>%
summarise(Last_Cust_Act = max(InvoiceDate)) %>%
mutate(Last_Invoice = max(Last_Cust_Act))
-A partir de aqui unimos las variables de interes de cliente y RFM, para trabajar a partir de estos datos, que se representan a continuacion:.
Cust_Recency$Recency<- round(as.numeric(difftime(Cust_Recency$Last_Invoice, Cust_Recency$Last_Cust_Act , units = c("days"))))
Cust_Recency <- Cust_Recency %>%
select(CustomerID, Recency)
dt_Customer <- cbind(Freq_Customer,Cust_Recency,Mon_Value)
dt_rfm <- dt_Customer %>%
select(c(1,2,4,6))
kable_styling(kable(head(dt_rfm)))
| CustomerID | Frequency | Recency | M_Value |
|---|---|---|---|
| 12346 | 2 | 325 | 0.00 |
| 12347 | 182 | 2 | 4310.00 |
| 12348 | 31 | 75 | 1797.24 |
| 12349 | 73 | 18 | 1757.55 |
| 12350 | 17 | 310 | 334.40 |
| 12352 | 95 | 36 | 1545.41 |
-Luego debemos identificar clientes con valor negativo en M_Value, para eliminarlos posteriormente de nuestros datos, como vemos en el histograma:
hist(dt_rfm$M_Value,col="red",xlab="M_Value",ylab="count", main="Histogram of M_Value")
-Asi pues convertimos a 0 los valores negativos:
dt_rfm$M_Value <- ifelse(dt_rfm$M_Value < 0, 0, dt_rfm$M_Value)
-Podemos comprobar que ya no hay valores negativos:
hist(dt_rfm$M_Value,col="red",xlab="M_Value",ylab="count", main="Histogram of M_Value")
Recency <-ggplot(data = dt_rfm, aes(x=Recency))+
geom_histogram(color="white", fill="blue")+
theme_bw() +
theme(legend.position = "none")
Frequency <- ggplot(data = dt_rfm, aes(x=Frequency))+
geom_histogram(color="white", fill="purple") +
theme_bw() +
theme(legend.position = "none")
M_Value <- ggplot(data = dt_rfm, aes(x=M_Value))+
geom_histogram(color="white", fill="red") +
theme_bw() +
theme(legend.position = "none")
plot_grid(Recency, Frequency, M_Value,labels = "AUTO")
log_R <- log(dt_rfm$Recency)
log_F <- log(dt_rfm$Frequency)
log_M <- log(dt_rfm$M_Value)
par(mfrow = c(1,3))
log_Recency <- hist(log_R,col="blue",xlab="Recency",ylab="count",main="Histogram log_Recency")
log_Frequency <- hist(log_F,col="purple",xlab="Frequency",ylab="count", main="Histogram log_Frequency")
log_Mvalue <- hist(log_M,col="red",xlab="M_Value",ylab="count", main="Histogram log_MValue")
par(mfrow = c(1,1))
-Ahora vamos a ver una seleccion top 5 de paises que se muestran a la cabeza en cuanto al numero de transacciones realizadas.
Country <- dt_ecom %>%
group_by(Country)%>%
summarise(Num.transactions=n())%>%
top_n(5)
## Selecting by Num.transactions
ggbarplot(Country, x = "Country", y = "Num.transactions",
fill = "Country", color = "Country", palette = "jco", sort.val="desc",sort.by.groups = FALSE,)+geom_text(aes(label=Num.transactions),vjust=-0.5)+
ggtitle('TOP 5 TRANSACCIONES POR PAIS')+labs(x='COUNTRIES', y='NUM_TRANSANCTIONS')
-y vemos de forma destacada que practicamente casi la totalidad de transacciones las realiza el Reino Unido(UK), con una amplia diferencia sobre el resto de paises.
-Nosotros podemos definir el numero de clusters que queramos en nuestros datos (en funcion del conocimiento de los mismos, entre otros) o bien a traves de una serie de metodos tratar de hallar el numero de clusters optimo para nuestros datos.Nosotros vamos a hacer esto ultimo.
-Vamos a mostrar diferentes metodos para seleccionar el numero optimo de clusters para nuestro caso concreto:
-Para restringir las diferencias entre los valores(pesos) de las distintas variables y asi representar la verdadera distancia entre variables.
-Escalamos nuestros datos, de tal forma que:
-Ahora vamos aplicar esta escala a nuestras variables de interes “RFM” para luego aplicar la clusterizacion Kmeans a nuestros datos.
rfm_var <- dt_rfm %>%
select(-CustomerID)
rfmvar <- as.data.frame(lapply(rfm_var,scale))
kable_styling(kable(head(rfmvar)))
| Frequency | Recency | M_Value |
|---|---|---|
| -0.3920111 | 2.3163029 | -0.2307913 |
| 0.3932484 | -0.8889481 | 0.2936909 |
| -0.2654971 | -0.1645415 | -0.0120859 |
| -0.0822699 | -0.7301740 | -0.0169157 |
| -0.3265728 | 2.1674523 | -0.1900983 |
| 0.0137063 | -0.5515532 | -0.0427310 |
set.seed(15)
fviz_nbclust(rfmvar, kmeans, method = "wss") +
geom_vline(xintercept = 3, linetype = 2)+
labs(subtitle = "Elbow method")
set.seed(15)
fviz_nbclust(rfmvar, kmeans, method = "silhouette")+
labs(subtitle = "Silhouette method")
set.seed(15)
ncopt<- NbClust(rfmvar, distance="euclidean", min.nc=2, max.nc=6, method="kmeans")
## *** : The Hubert index is a graphical method of determining the number of clusters.
## In the plot of Hubert index, we seek a significant knee that corresponds to a
## significant increase of the value of the measure i.e the significant peak in Hubert
## index second differences plot.
##
## *** : The D index is a graphical method of determining the number of clusters.
## In the plot of D index, we seek a significant knee (the significant peak in Dindex
## second differences plot) that corresponds to a significant increase of the value of
## the measure.
##
## *******************************************************************
## * Among all indices:
## * 6 proposed 2 as the best number of clusters
## * 13 proposed 3 as the best number of clusters
## * 5 proposed 6 as the best number of clusters
##
## ***** Conclusion *****
##
## * According to the majority rule, the best number of clusters is 3
##
##
## *******************************************************************
-Como se puede ver el numero optimo de clusters mas votado es 3.
-Por tanto una vez analizados diferentes metodos y con el resultado de este ultimo a mayores, concluimos que el numero de clusteres optimos para nuestros datos es 3.
-vamos ahora a ver la representacion de estos 3 clusters en un grafico.
set.seed(15)
rfm_clusters <- kmeans(rfmvar, 3, nstart = 500)
fviz_cluster(rfm_clusters, data = rfmvar, ellipse.type = "convex")+ theme_minimal()
-Hacemos tabla resumen union de nuestros datos(reales sin escalar) con cada numero de cluster correspondiente a cada fila de los mismos.
rfm_var$cluster <- as.factor(rfm_clusters$cluster)
kable_styling(kable(head(rfm_var)))
| Frequency | Recency | M_Value | cluster |
|---|---|---|---|
| 2 | 325 | 0.00 | 2 |
| 182 | 2 | 4310.00 | 1 |
| 31 | 75 | 1797.24 | 1 |
| 73 | 18 | 1757.55 | 1 |
| 17 | 310 | 334.40 | 2 |
| 95 | 36 | 1545.41 | 1 |
-Comprobamos graficamente el numero de clientes que corresponde a cada cluster:
Customers <- rfm_var%>%
group_by(cluster)%>%
summarise(Num_Customers= n())
ggbarplot(Customers, x = "cluster", y = "Num_Customers",
fill = "cluster", color = "cluster", palette = "jco", sort.val="desc",sort.by.groups = FALSE,)+geom_text(aes(label=Num_Customers),vjust=-0.5)+
ggtitle('NUM_CUSTOMERS/CLUSTER')+labs(x='CLUSTER', y='NUM_CUSTOMERS')
-Agrupamos los clusters en una tabla y analizamos la media de nuestros datos “RFM”.
KM_Results <- rfm_var %>%
group_by(cluster) %>%
summarise('Num_Users' = n(),
'Recency_Mean' = round(mean(Recency)),
'Freq_Mean' = scales::comma(round(mean(Frequency))),
'M_Value_Mean' = scales::dollar(round(mean(M_Value))),
'Cluster_Revenue' = scales::dollar(sum(M_Value))
)
kable_styling(kable(KM_Results))
| cluster | Num_Users | Recency_Mean | Freq_Mean | M_Value_Mean | Cluster_Revenue |
|---|---|---|---|---|---|
| 1 | 3260 | 40 | 104 | $1,948 | $6,348,924 |
| 2 | 1100 | 246 | 27 | $473 | $520,049 |
| 3 | 12 | 4 | 2,814 | $118,565 | $1,422,776 |
-Al analizar la tabla anterior nos encontramos con las siguiente clasificacion y caracteristicas segun el perfil del cliente segmentado:
-CLUSTER 3: NIVEL ALTO DE CLIENTE
-Muy pocos clientes pero selectos(el menor grupo de todos)
-Gran poder adquisitivo con el valor mas alto medio monetario de
compras realizadas
-Gran Frecuencia media de compra la mas alta de la comparativa con
diferencia.
-Muy poco retraso desde la ultima compra realizada.
-Ingresos totales del cluster muy altos en comparacion con el numero
de clientes que conforman el cluster.
-CLUSTER 1: NIVEL MEDIO DE CLIENTE
-Son la mayoria de clientes de todos los clusters segmentados.
-Frecuencia media de compra en la zona media con respecto a los
demas clusteres.Muy alejado del cluster 1.
-Valor monetario medio en la zona media con respecto a los demas
clusteres.Muy alejado del cluster 1.
-Retraso medio desde la ultima compra en la zona media con respecto
a los demas clusteres. Muy alejado del cluster 1.
-El que mayor nivel de ingresos totales tiene por cluster.
-CLUSTER 2: NIVEL BAJO DE CLIENTE
-Muchos dias de retraso desde la ultima compra, los que mas con
diferencia.
-Frecuencia media de compra la menor de todas las comparaciones.
-Valor monetario medio de compra aportado tambien el menor de todas
las comparaciones.
-Ingresos totales del cluster los mas bajos con diferencia.
-Numero de clientes 3 veces menor que el cliente de nivel medio, pero
muy alejado del numero de clientes de nivel alto.
ESTRATEGIAS DE MARKETING(Pauta que se podria seguir en base a los datos):
-LOS CLIENTES VIP (CLUSTER 3):Son clientes con frecuencia y con valor adquisitivo alto. Estos Clientes son muy importantes para el negocio y no se pueden perder,por lo que hay que intentar diseñar estrategias para seguirlos fidelizando al máximo.
-LOS CLIENTES DE NIVEL MEDIO(CLUSTER 1):Comparado con el segmento anterior, estos clientes tienen una frecuencia y valor monetario inferior, aunque significativo. Se podría diseñar una campaña de Marketing con el fin de “empujar” estos Clientes hacia el segmento VIP, o al menos conseguir maximizar en lo posible los resultados de frecuencia y compra del mismo.
-LOS CLIENTES CON BAJA FRECUENCIA,RECENCY ALTA,Y VALOR ADQUISITIVO ALTO/BAJO (CLUSTER 2):
El valor de Recency alto indica que ha pasado mucho tiempo desde la última visita.Junto con su baja frecuencia, estos Clientes se podrían considerar prácticamente perdidos,ya que es poco probable que vuelvan a la tienda. En este caso, se podría diseñar iniciativas de Marketing para volver a atraer su atención a la tienda y a sus productos.
-Para nuestro caso,entendiendo que el cluster mas numeroso(Cluster Nivel Medio de cliente) y ademas es el que proporciona el mayor numero de ingresos totales de todos (CLUSTER 1), -Vamos a hacer una subsegmentacion del mismo para hallar hallazgos que nos puedan ayudar a entender a este tipo de cliente(AGRUPACION JERARQUICA).
-La Agrupación Jerárquica se basa en el uso de estas técnicas de agrupación para encontrar una jerarquía de agrupaciones, donde esta jerarquía se asemeja a una estructura de árbol, llamada dendrograma.
-El agrupamiento jerárquico es un método de análisis de grupos puntuales, el cual busca construir una jerarquía de grupos.
-Asi pues disgregamos de nuestro conjunto, el cluster 1 de nuestros datos y desarrollamos nuestro arbol jerarquico:
dt_cj <- rfm_var%>%
filter(cluster==1)%>%
select(-cluster)
set.seed(15)
treepart <- rpart(M_Value ~ .,
data=dt_cj,
method = "anova",
control= rpart.control(cp=0.01))
rpart.plot(treepart, type=1,extra=1, box.palette=c("cyan","orange","yellow"))
-Como vemos el cluster 1 se ha subdivido despues de la subsegmentacion en 5 clusters, y estan ordenados a partir de los clientes de bajo valor hasta los de alto valor en relacion a sus promedios.
-La interpretacion de nuestro arbol la exponemos en una tabla a continuacion:
Segmentos <- c("Segmento 1", "Segmento 2", "Segmento 3", "Segmento 4", "Segmento 5")
Num.Customers <- c("1,916","944","260", "115", "25")
Purchase_Frequency <- c("<75","75-215",">215","215-579",">579")
Purchase_Recency <- c("-","-",">=5","<5","<5")
Monetary_Value <- c("$753","$2,464","$5,059","$7,894","$14000")
dt <- data.frame(Segmentos,Num.Customers,Purchase_Frequency,Purchase_Recency,Monetary_Value)
kable_styling(kable(dt))
| Segmentos | Num.Customers | Purchase_Frequency | Purchase_Recency | Monetary_Value |
|---|---|---|---|---|
| Segmento 1 | 1,916 | <75 |
|
$753 |
| Segmento 2 | 944 | 75-215 |
|
$2,464 |
| Segmento 3 | 260 | >215 | >=5 | $5,059 |
| Segmento 4 | 115 | 215-579 | <5 | $7,894 |
| Segmento 5 | 25 | >579 | <5 | $14000 |
-El segmento mas valioso lo conforman 25 clientes(segmento 5) con un valor monetario promedio que dobla prácticamente al segundo segmento mas valioso con 115 clientes(segmento 4), ambos segmentos son los mas destacables en total sumando unos 140 clientes con una frecuencia de compra inferior a 5 dias.
-A partir de aquí el equipo ejecutivo y de administración puede tomar decisiones y mas acciones estratégicas para aumentar el valor monetario promedio de los subsegmentos mas bajos dentro de este cluster de clientes.
-De esta forma elegimos a traves de una comparativa los metodos de algoritmos de agrupamientos mas adecuado para nuestros datos.
clmethods <- c("hierarchical","kmeans","pam","clara")
set.seed(15)
intern_stab <- clValid(rfmvar, nClust = 2:6,nrow(rfmvar),
clMethods = clmethods, validation = c("internal","stability"))
summary(intern_stab)
##
## Clustering Methods:
## hierarchical kmeans pam clara
##
## Cluster sizes:
## 2 3 4 5 6
##
## Validation Measures:
## 2 3 4 5 6
##
## hierarchical APN 0.0012 0.0007 0.0022 0.0027 0.0027
## AD 1.4514 1.4215 1.4156 1.3964 1.3933
## ADM 0.0387 0.0363 0.0426 0.0473 0.0468
## FOM 0.9777 0.9765 0.9475 0.9324 0.9298
## Connectivity 5.2869 10.5111 13.0444 22.2393 24.1976
## Dunn 0.2300 0.4763 0.4763 0.2329 0.2329
## Silhouette 0.9510 0.9467 0.9410 0.8866 0.8866
## kmeans APN 0.0009 0.1282 0.0450 0.1723 0.1253
## AD 1.4251 1.4140 1.2468 1.3814 1.0464
## ADM 0.0475 0.3025 0.6549 0.3280 0.4442
## FOM 0.9774 0.9577 0.9373 0.9283 0.9167
## Connectivity 13.9964 12.8440 65.3421 28.4115 81.1306
## Dunn 0.0293 0.1660 0.0007 0.0512 0.0014
## Silhouette 0.9345 0.9407 0.5981 0.8326 0.6099
## pam APN 0.1162 0.1757 0.3049 0.2929 0.2556
## AD 1.1161 1.0199 0.9463 0.8918 0.8321
## ADM 0.3220 0.3195 0.4786 0.4702 0.3682
## FOM 0.9738 0.9601 0.9425 0.9392 0.9156
## Connectivity 42.1873 162.6210 202.9504 269.1690 355.6183
## Dunn 0.0005 0.0003 0.0002 0.0003 0.0003
## Silhouette 0.5756 0.3063 0.4621 0.3582 0.3458
## clara APN 0.1080 0.3009 0.3319 0.3341 0.3146
## AD 1.1245 1.0705 0.9672 0.9154 0.8464
## ADM 0.3254 0.4391 0.5346 0.4767 0.4212
## FOM 0.9762 0.9637 0.9398 0.9426 0.9124
## Connectivity 60.0250 96.2742 225.6532 382.9972 432.9770
## Dunn 0.0005 0.0003 0.0003 0.0002 0.0001
## Silhouette 0.5796 0.4369 0.3714 0.2884 0.3416
##
## Optimal Scores:
##
## Score Method Clusters
## APN 0.0007 hierarchical 3
## AD 0.8321 pam 6
## ADM 0.0363 hierarchical 3
## FOM 0.9124 clara 6
## Connectivity 5.2869 hierarchical 2
## Dunn 0.4763 hierarchical 3
## Silhouette 0.9510 hierarchical 2
-Se puede ver que el cluster jerarquico con 3 clusters da la mejor puntuacion y es el que mejor desempeño tiene de la comparativa.