En este ejercicio se propone segmentar a los clientes de una determinada oficina de una entidad financiera que mantienen depósitos en tal oficina. El objetivo de la segmentación es encontrar distintos perfiles de depositantes a fin de establecer campañas de promoción de nuevos productos de depósito más personalizadas en el enfoque. Para ello se ha extraído una muestra aleatoria compuesta por 30 clientes, y se les ha preguntado sobre sus ingresos brutos mensuales y su edad.
Los datos se han generado aleatoriamente de acuerdo a ciertas distribuciones de probabilidad, para una muestra compuesta por 30 casos (clientes).
Las variables clasificadoras utilizadas son las siguientes:
head(datos)
## INGRESOS EDAD
## cliente 1 1766 37
## cliente 2 1754 35
## cliente 3 1583 46
## cliente 4 1192 49
## cliente 5 1314 48
## cliente 6 1441 37
summary(datos)
## INGRESOS EDAD
## Min. : 545.0 Min. :19.00
## 1st Qu.: 665.2 1st Qu.:26.50
## Median : 755.5 Median :45.00
## Mean : 985.3 Mean :44.00
## 3rd Qu.:1333.5 3rd Qu.:59.25
## Max. :1981.0 Max. :80.00
Aquí podemos ver un pequeño resumen de los datos, encontramos 30 observaciones correspondientes a 30 clientes en las que estudiamos dos variables; ingresos, que se sitúa entre 545€ y 1981€, con una media de 755,5€, y la otra variable, edad, la cual se encuentra en un rango comprendido entre 19 y 80 años, con una media de 44 años.
par(mfrow = c(1, 2))
hist(datos$INGRESOS,breaks="Sturges",labels=TRUE, main = "Ingresos", xlab = "Euros", ylab="Frecuencias",col = "gold",
border="tomato1")
hist(datos$EDAD,col = "gold",
border="tomato1", main = "Edad",labels=TRUE, xlab = "Años",ylab="Frecuencias")
Representando los histogramas sobre nuestras dos variables podemos hacernos una idea de cómo se distribuyen estos datos. La variable ingresos tiene más observaciones en el intervalo 500-1000 €, lo que podríamos considerar como un perfil de clientes de ingresos bajos. Si nos centramos en la variable edad, el tramo de edad que más observaciones aglutina es de 20-30 años, donde encontramos 8 clientes, seguido de cerca del tramo 60-70 años, con 6 clientes.
par(mfrow = c(1, 2))
boxplot(datos$INGRESOS,border="steelblue", col="gold",main = "Ingresos",ylab="Euros")
boxplot(datos$EDAD,col="gold",border="steelblue",main = "Edad",ylab="Años")
Estos boxplots muestran como nueva información que existe una mayor dispersion en la variable ingresos en compraración con la variable edad. También podemos observar que no existe ningún outlier en ninguna de nuestras dos variables. Vemos como los datos están expresados en diferentes escalas, motivo que supone la posibilidad de que necesitemos escalarlos según el análisis que necesitemos realizar con ellos.
Zdatos <- scale(datos)
library(scales)
par(mfrow = c(1, 1))
plot(Zdatos, col = alpha("steelblue", 0.4), pch = 19, las = 1)
text(Zdatos, rownames(Zdatos), pos = 3, cex = .6)
Así, en un primer momento se escalan los datos, y posteriormente realizamos el gráfico de dispersión. A primera vista parece que lo óptimo será establecer tres grupos, el primero de baja edad y bajos ingresos, el segundo de bajos ingresos y alta edad y el tercero de altos ingresos y edad intermedia, aunque no obligatoriamente en este orden. Es necesario y aconsejable realizar algunos análisis adicionales para confirmar esta división de los grupos.
d <- dist(Zdatos, method = "euclidean")
fit <- hclust(d, method="ward.D")
plot(fit, cex = .6, xlab = "", ylab = "Distancia entre grupos", sub = "Cluster jerárquico por el método de Ward para los clientes")
Numgrupos <- 3
library(RColorBrewer)
plot(fit, cex = .6, xlab = "", ylab = "Distancia entre grupos", sub = "Cluster jerárquico por el método de Ward para los clientes")
rect.hclust(fit, k = Numgrupos, border = brewer.pal(Numgrupos, "Dark2"))
Atendiendo a este gráfico, que sigue el criterio de las distancias euclídeas y el método de Ward parece una buena decisión dividir la muestra en tres grupos, como ya habíamos supuesto, quedando recogidos 10 clientes en cada grupo.
grupos <- cutree(fit, k = Numgrupos)
grupos
## cliente 1 cliente 2 cliente 3 cliente 4 cliente 5 cliente 6
## 1 1 1 1 1 1
## cliente 7 cliente 8 cliente 9 cliente 10 cliente 11 cliente 12
## 1 1 1 1 2 2
## cliente 13 cliente 14 cliente 15 cliente 16 cliente 17 cliente 18
## 2 2 2 2 2 2
## cliente 19 cliente 20 cliente 21 cliente 22 cliente 23 cliente 24
## 2 2 3 3 3 3
## cliente 25 cliente 26 cliente 27 cliente 28 cliente 29 cliente 30
## 3 3 3 3 3 3
datos$GRUPO <- factor(grupos)
palette(brewer.pal(Numgrupos, "Dark2"))
plot(INGRESOS ~ EDAD, col = alpha(GRUPO, 0.75), pch = 19, data = datos, las = 1)
text(datos, rownames(datos), pos = 3, cex = .6)
Como se comenta en apartados anteriores encontramos tres grupos. Uno de ellos con ingresos bajos, en este caso el grupo 2, con unos ingresos situados entre 545 € y 754 €, una edad mínima de 19 años y una máxima de 30 años. El grupo de bajos ingresos y alta edad, en este caso es el grupo 3, los ingresos se sitúan entre los 557 y los 913 €, mientras la edad mínima es de 52 años y la máxima de 80. Por tanto, el último grupo, que corresponde con el de altos ingresos y edad intermedia, será el grupo 1, en nuestro caso concreto. Con unos ingresos mínimos de 1192 € y unos máximos de 1981 €, la edad estará entre los 35 y 54 años.
Adicionalmente, vamos a intentar una nueva división de grupos para comparar la anteriormente calculada y ver si existen cambios de grupos de algunos de los clientes. Se hará realizando la agrupación mediante el método de la vinculación inter-grupos en lugar de utilizar el método de Ward.
fit2 <- hclust(d, method = "average")
plot(fit2, cex=.6)
Numgrupos <- 3
rect.hclust(fit2, k = Numgrupos, border = "red")
datos$GRUPO2 <- cutree(fit2, Numgrupos)
datos
## INGRESOS EDAD GRUPO GRUPO2
## cliente 1 1766 37 1 1
## cliente 2 1754 35 1 1
## cliente 3 1583 46 1 1
## cliente 4 1192 49 1 1
## cliente 5 1314 48 1 1
## cliente 6 1441 37 1 1
## cliente 7 1499 50 1 1
## cliente 8 1981 38 1 1
## cliente 9 1653 54 1 1
## cliente 10 1340 44 1 1
## cliente 11 557 23 2 2
## cliente 12 664 22 2 2
## cliente 13 663 20 2 2
## cliente 14 649 21 2 2
## cliente 15 732 19 2 2
## cliente 16 589 30 2 2
## cliente 17 754 28 2 2
## cliente 18 545 24 2 2
## cliente 19 672 26 2 2
## cliente 20 747 23 2 2
## cliente 21 770 80 3 3
## cliente 22 871 60 3 3
## cliente 23 741 65 3 3
## cliente 24 826 67 3 3
## cliente 25 913 69 3 3
## cliente 26 646 64 3 3
## cliente 27 557 52 3 3
## cliente 28 757 57 3 3
## cliente 29 715 67 3 3
## cliente 30 669 65 3 3
palette(brewer.pal(Numgrupos, "Dark2"))
plot(INGRESOS ~ EDAD, col = alpha(GRUPO2, 0.75), pch = 19, data = datos, las = 1)
text(datos, rownames(datos), pos = 3, cex = .6)
Se observa como, aunque cambiemos el método de agrupación, ninguna observación cambia de grupo, lo que puede significar que los grupos están muy bien definidos, es decir, los grupos son muy distintos unos de otros, y los clientes (observaciones) que hay dentro de cada grupo son muy parecidos entre sí.
Data.km <- kmeans(Zdatos, Numgrupos)
Data.km
## K-means clustering with 3 clusters of sizes 10, 10, 10
##
## Cluster means:
## INGRESOS EDAD
## 1 -0.5462543 1.14310698
## 2 -0.7504992 -1.13200885
## 3 1.2967535 -0.01109813
##
## Clustering vector:
## cliente 1 cliente 2 cliente 3 cliente 4 cliente 5 cliente 6
## 3 3 3 3 3 3
## cliente 7 cliente 8 cliente 9 cliente 10 cliente 11 cliente 12
## 3 3 3 3 2 2
## cliente 13 cliente 14 cliente 15 cliente 16 cliente 17 cliente 18
## 2 2 2 2 2 2
## cliente 19 cliente 20 cliente 21 cliente 22 cliente 23 cliente 24
## 2 2 1 1 1 1
## cliente 25 cliente 26 cliente 27 cliente 28 cliente 29 cliente 30
## 1 1 1 1 1 1
##
## Within cluster sum of squares by cluster:
## [1] 2.0994027 0.6050381 3.9808276
## (between_SS / total_SS = 88.5 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss"
## [5] "tot.withinss" "betweenss" "size" "iter"
## [9] "ifault"
datasize <- Data.km$size
datasize
## [1] 10 10 10
ZDatag <- data.frame(Zdatos, GRUPO = factor(Data.km$cluster))
plot(EDAD ~ INGRESOS, col = alpha(GRUPO, 0.75), pch = 19, data = ZDatag, las = 1)
text(ZDatag, rownames(ZDatag), pos = 3, cex = .6)
points(Data.km$centers, pch = 17,col = 1:Numgrupos, cex = 2)
Se puede observar como tampoco se modifica la composición de los grupos si lo hacemos a través del método de las k-medias con un número predefinido de 3 grupos. Seguimos encontrando los mismos perfiles, el primero de baja edad y bajos ingresos, el segundo de bajos ingresos y alta edad y el tercero de altos ingresos y edad intermedia.
datos$GRUPO3 <- factor(Data.km$cluster)
datos
## INGRESOS EDAD GRUPO GRUPO2 GRUPO3
## cliente 1 1766 37 1 1 3
## cliente 2 1754 35 1 1 3
## cliente 3 1583 46 1 1 3
## cliente 4 1192 49 1 1 3
## cliente 5 1314 48 1 1 3
## cliente 6 1441 37 1 1 3
## cliente 7 1499 50 1 1 3
## cliente 8 1981 38 1 1 3
## cliente 9 1653 54 1 1 3
## cliente 10 1340 44 1 1 3
## cliente 11 557 23 2 2 2
## cliente 12 664 22 2 2 2
## cliente 13 663 20 2 2 2
## cliente 14 649 21 2 2 2
## cliente 15 732 19 2 2 2
## cliente 16 589 30 2 2 2
## cliente 17 754 28 2 2 2
## cliente 18 545 24 2 2 2
## cliente 19 672 26 2 2 2
## cliente 20 747 23 2 2 2
## cliente 21 770 80 3 3 1
## cliente 22 871 60 3 3 1
## cliente 23 741 65 3 3 1
## cliente 24 826 67 3 3 1
## cliente 25 913 69 3 3 1
## cliente 26 646 64 3 3 1
## cliente 27 557 52 3 3 1
## cliente 28 757 57 3 3 1
## cliente 29 715 67 3 3 1
## cliente 30 669 65 3 3 1
Se está comparando la composición de los grupos según los 2 métodos jerárquicos (Ward y average) y el método no jerárquico (K-means), pero no hay trasvase entre grupos sea cual sea el método utilizado, lo que reafirma la teoría anteriormente expuesta de que los grupos son muy distintos unos de otros, y los clientes que hay dentro de cada grupo son muy parecidos entre sí. Podríamos afirmar que diferenciar en tres grupos estas observaciones tiene una gran utilidad y que ésta es la división óptima.
aggregate(cbind(INGRESOS, EDAD) ~ GRUPO3, data = datos, FUN = mean)
## GRUPO3 INGRESOS EDAD
## 1 1 746.5 64.6
## 2 2 657.2 23.6
## 3 3 1552.3 43.8
Vemos de forma númerica lo ya mostrado en apartados precedentes, como los ingresos entre el grupo 2 y 3 son parecidos pero difieren mucho en edad. El grupo 1, sin embargo, presenta una media de ingresos mucho mayor y una edad intermedia.
par(mfrow = c(1, 2))
boxplot(INGRESOS ~ GRUPO3, main = "Boxplot de los ingresos", col = 1:3, data = datos, las = 1)
boxplot(EDAD ~ GRUPO3, main = "Boxplot de la edad", col = 1:3, data = datos, las = 1)
En el boxplot de los ingresos podemos ver como es muy probable que haya diferencias significativas entre los grupos 1-3 y entre los grupos 1-2. Sin embargo, no queda tan claro que la diferencia en los grupos 2-3 sea significativa, de modo que será necesario confirmar estas diferencias de forma analítica mediante análisis de la varianza (ANOVA). En cuanto al boxplot de la edad parece mostrar diferencias significativas entre todas las combinaciones posibles de los tres grupos, aunque también trataremos de confirmarlo mediante ANOVA.
modelo.aov <- aov(INGRESOS ~ GRUPO3, data = datos)
summary(modelo.aov)
## Df Sum Sq Mean Sq F value Pr(>F)
## GRUPO3 2 4861640 2430820 96.23 5.19e-13 ***
## Residuals 27 682040 25261
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(modelo.aov)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = INGRESOS ~ GRUPO3, data = datos)
##
## $GRUPO3
## diff lwr upr p adj
## 2-1 -89.3 -265.5332 86.93323 0.4314325
## 3-1 805.8 629.5668 982.03323 0.0000000
## 3-2 895.1 718.8668 1071.33323 0.0000000
Efectivamente y como suponíamos, para las combinaciones de grupos 1-3 y 1-2 en cuanto a ingresos se refiere el p-valor es de 0, por lo que podemos asumir que hay diferencias significativas entre estos grupos. Sin embargo, el p-valor para la combinacion de grupos 2-3 es mucho mayor a 0.05 por lo que asumimos una media de ingresos iguales para esos grupos.
modelo.aov2 <- aov(EDAD ~ GRUPO3, data = datos)
summary(modelo.aov2)
## Df Sum Sq Mean Sq F value Pr(>F)
## GRUPO3 2 8406 4203 112.1 8.39e-14 ***
## Residuals 27 1012 37
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(modelo.aov2)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = EDAD ~ GRUPO3, data = datos)
##
## $GRUPO3
## diff lwr upr p adj
## 2-1 -41.0 -47.78983 -34.21017 0e+00
## 3-1 -20.8 -27.58983 -14.01017 1e-07
## 3-2 20.2 13.41017 26.98983 2e-07
En cuanto a las edades se refiere, todos los p-valores son menores a 0.05 de manera que asumiremos la media de edad distinta para todas las combinaciones de grupos.
A la vista de estos resultados del ANOVA podemos considerar que las diferencias entre grupos son más que suficientes como para asumir la utilidad de aplicar esta técnica.
Para el primer grupo (ingresos y edad baja), crearíamos una campaña de promoción enfocada al ahorro a largo plazo, puesto que es para gente joven y la edad del grupo está entre los 19 y los 30 años, con inversiones con algo más de riesgo puesto que el horizonte de inversión es muy grande y con un límite mínimo de ahorro muy bajo puesto que este grupo dispone de unos ingresos muy bajos, de forma que este límite mínimo de ahorro mensual sería de 30 €.
La campaña para el segundo grupo (ingresos bajos y edad alta), sería una campaña orientada a un ahorro a muy corto plazo, puesto que mucho de los clientes están muy cerca de la jubilación y necesitarán pronto este ahorro, por tanto se basaría en una campaña promocionando depósitos garantizados, también con un límite mínimo muy pequeño ya que este grupo también presenta unos ingresos muy reducidos.
Para el tercer grupo (ingresos altos y edad intermedia), se promocionaría un producto de ahorro con un límite mínimo de aportaciones mensuales mayor a los anteriores, 150 €, puesto que la media de ingresos en este grupo es mayor, y un horizonte de la inversión medio porque es un grupo que aún posee un elevado margen de tiempo para alcanzar la jubilación.