Proporcionar un ejemplo de codificación sobre cómo realizar la agrupación de clientes de proximidad espacial, aplicable p. cuando se buscan múltiples centros de gravedad (es decir, cuando se desea ubicar varios almacenes). La lógica y el enfoque son los mismos que en cualquier tipo de problema de agrupamiento basado en la distancia.
Aplicaré la agrupación en clústeres de k-medias para agrupar clientes en función de su distancia espacial.
El algoritmo para la agrupación de k-medias está bien explicado, p. Ej. por este artículo: https://www.datanovia.com/en/lessons/k-means-clustering-in-r-algorith-and-practical-examples/
Primero defino un marco de datos que contiene coordenadas de latitud y longitud aleatorias, que representan clientes distribuidos al azar.
customer_df <- as.data.frame(matrix(nrow=1000,ncol=2))
colnames(customer_df) <- c("lat","long")
customer_df$lat <- runif(n=1000,min=-90,max=90)
customer_df$long <- runif(n=1000,min=-180,max=180)
Aquí ves el encabezado del marco de datos:
head(customer_df)
## lat long
## 1 -42.69660 58.067160
## 2 37.31715 179.655272
## 3 -28.68660 -3.025719
## 4 -76.15463 117.119388
## 5 -14.84898 -162.408406
## 6 54.19468 -128.476143
El algoritmo de agrupación de k-medias estándar selecciona k puntos iniciales aleatorios y los define como los centros de agrupación. Luego, el algoritmo asigna puntos de datos a cada centro de grupo, basándose en una distancia mínima.
En este caso, queremos utilizar más adelante el algoritmo de agrupación en clústeres para resolver problemas de ubicación de instalaciones, considerando varios almacenes para ubicar. Por tanto, me parece más apropiado seleccionar centros de conglomerados que estén razonablemente distanciados entre sí. Para esto, defino una función que elige el número definido de centros de inicio en función de la dimensión de longitud del conjunto de datos espaciales:
initial_centers <- function(customers,centers){
quantiles <- c()
for(i in 1:centers){
quantiles <- c(quantiles,i*as.integer(nrow(customers)/centers))
}
quantiles
}
Ahora podemos aplicar la función anterior, en combinación con la función kmeans del paquete base R. En este ejemplo, obtengo cuatro grupos de clientes basados en la proximidad.
cluster_obj <- kmeans(customer_df,centers=customer_df[initial_centers(customer_df,4),])
head(cluster_obj)
## $cluster
## [1] 1 4 2 1 3 3 3 1 2 1 3 2 2 4 3 4 4 4 3 4 3 2 3 4 2 3 2 3 1 4 4 4 1 1 4 2 2
## [38] 2 4 4 3 3 1 2 4 1 2 1 3 1 2 2 3 3 4 1 4 2 3 3 2 4 2 2 3 2 1 4 2 2 2 4 4 2
## [75] 4 3 3 4 1 1 1 3 3 2 1 1 3 3 4 4 3 1 2 4 3 1 3 2 2 2 3 2 3 4 4 2 3 3 1 3 1
## [112] 2 2 4 1 1 1 3 4 1 2 3 3 3 1 1 2 3 3 2 1 3 4 2 2 3 2 2 1 2 1 2 2 2 2 3 2 3
## [149] 1 2 2 1 2 3 2 2 1 4 2 4 3 3 3 2 1 1 2 2 3 3 4 1 2 4 1 2 1 2 3 2 2 2 3 3 2
## [186] 1 1 1 4 3 4 4 2 1 3 2 4 2 2 3 3 1 3 2 3 2 4 2 3 2 4 1 1 3 1 2 1 3 4 2 4 3
## [223] 4 2 4 3 4 2 4 2 1 2 1 3 4 2 2 3 2 4 2 1 2 3 3 2 2 3 3 1 3 4 4 3 4 1 1 2 3
## [260] 3 4 2 1 1 1 2 2 2 1 4 4 3 1 2 4 3 3 3 3 3 3 3 2 3 3 3 3 2 2 3 3 1 4 1 2 1
## [297] 4 2 2 3 1 4 4 2 3 3 2 4 4 3 2 1 2 3 2 2 4 4 2 2 2 3 2 2 2 2 2 2 2 1 2 2 4
## [334] 3 3 2 2 3 3 1 2 4 2 1 3 3 4 1 2 4 1 4 4 4 1 2 3 1 3 1 3 3 2 3 4 1 2 2 2 2
## [371] 1 2 2 2 1 3 2 1 2 2 2 4 3 2 2 3 1 3 3 4 1 1 3 4 2 4 1 1 4 4 2 4 2 3 3 2 4
## [408] 4 4 3 2 1 3 3 4 1 3 3 1 3 4 2 3 2 2 3 2 2 2 1 2 3 4 3 4 3 4 4 2 1 3 2 3 1
## [445] 3 1 1 2 3 3 2 2 3 4 1 1 3 1 2 4 2 2 2 3 1 3 2 1 4 2 3 2 4 1 4 3 1 1 4 4 3
## [482] 1 2 4 3 3 2 1 4 2 3 2 4 3 4 4 1 2 2 2 3 3 4 4 1 3 2 3 2 4 1 2 4 1 2 3 1 3
## [519] 2 3 3 3 1 3 2 4 1 3 4 3 4 4 3 4 4 2 1 1 3 3 3 3 3 4 2 1 3 3 1 1 4 1 4 2 2
## [556] 1 1 4 4 3 3 4 3 1 4 3 1 2 3 3 2 4 1 2 3 3 1 2 2 1 3 1 4 4 3 2 4 3 1 4 2 3
## [593] 3 2 2 1 1 2 4 2 3 3 2 1 4 1 4 3 3 3 3 3 3 2 2 2 1 1 2 3 2 1 1 2 1 1 1 1 1
## [630] 2 4 2 1 1 3 1 4 2 4 2 2 1 4 1 2 2 3 1 1 3 1 1 3 4 3 2 4 1 1 1 2 1 1 1 2 3
## [667] 4 3 2 4 4 4 2 4 4 3 2 1 2 2 3 3 3 4 2 4 3 1 2 4 2 3 1 3 3 1 4 3 4 4 1 2 3
## [704] 3 4 4 2 2 1 2 2 1 3 4 1 2 2 3 4 4 2 3 1 2 4 3 1 2 2 2 1 4 1 3 1 4 2 2 1 1
## [741] 2 2 2 2 1 2 4 3 3 3 1 3 4 1 1 3 2 1 4 4 2 4 2 3 2 3 3 4 2 1 2 3 2 1 1 1 3
## [778] 2 3 4 3 2 2 4 1 4 4 2 2 1 1 2 3 1 2 2 2 1 4 3 3 3 1 2 1 3 2 4 2 3 4 1 4 3
## [815] 1 3 2 2 1 1 2 3 4 4 4 3 1 2 4 2 2 2 1 3 4 4 2 2 3 2 4 3 4 2 2 2 3 3 3 4 2
## [852] 3 3 3 1 1 3 1 1 2 2 1 3 3 4 3 3 3 2 2 1 3 2 3 1 4 3 2 4 1 4 3 3 2 3 4 4 1
## [889] 3 1 2 4 4 3 2 1 2 3 2 1 1 2 3 2 1 1 3 3 4 3 3 4 3 3 3 2 2 1 2 3 1 1 1 4 2
## [926] 3 4 2 4 1 4 3 4 4 1 3 2 2 1 2 2 4 2 4 1 4 1 2 1 2 4 3 4 2 4 4 4 2 4 1 2 3
## [963] 3 2 4 4 4 2 4 4 3 2 1 2 4 3 2 3 1 2 3 4 1 4 3 4 2 1 4 1 4 2 3 3 1 1 2 2 2
## [1000] 4
##
## $centers
## lat long
## 1 -44.672042 103.20907
## 2 9.621406 -22.15262
## 3 -4.487789 -127.84173
## 4 48.358322 110.24174
##
## $totss
## [1] 13417586
##
## $withinss
## [1] 557304.2 1006745.4 962130.0 492832.8
##
## $tot.withinss
## [1] 3019012
##
## $betweenss
## [1] 10398574
Arriba verá el encabezado del objeto de resultado devuelto por la función kmeans. A continuación, combino los índices de clúster contenidos por el objeto kmeans con el marco de datos del cliente, de modo que ahora tenemos 3 columnas. Esto nos permitirá hacer ggplots, etc.
result_df <- customer_df
result_df$group <- cluster_obj$cluster
head(result_df)
## lat long group
## 1 -42.69660 58.067160 1
## 2 37.31715 179.655272 4
## 3 -28.68660 -3.025719 2
## 4 -76.15463 117.119388 1
## 5 -14.84898 -162.408406 3
## 6 54.19468 -128.476143 3
Completo esta publicación visualizando los resultados en un ggplot (diagrama de dispersión usando el paquete ggplot2 R). Para colorear utilicé el paquete viridis en R:
library(ggplot2)
library(viridis)
## Loading required package: viridisLite
ggplot(result_df) + geom_point(mapping = aes(x=lat,y=long,color=group)) +
xlim(-90,90) + ylim(-180,180) + scale_color_viridis(discrete = FALSE, option = "D") + scale_fill_viridis(discrete = FALSE)
Hagamos otra prueba con 20 almacenes:
cluster_obj <- kmeans(customer_df,centers=customer_df[initial_centers(customer_df,20),])
result_df$group <- cluster_obj$cluster
ggplot(result_df) + geom_point(mapping = aes(x=lat,y=long,color=group)) +
xlim(-90,90) + ylim(-180,180) + scale_color_viridis(discrete = FALSE, option = "D") + scale_fill_viridis(discrete = FALSE)
Ingeniero industrial especializado en optimización y simulación (R, Python, SQL, VBA)
Leave a Reply