Auf räumlicher Nähe basierendes Clustering von Kunden

In diesem Beitrag betrachte ich in Codierungsbeispiels für das Erstellen von Kundenclustern basierend auf räumlicher Nähe. Mit diesem Algorithmus kann ich auch mehrere Schwerpunkte in der räumlichen Verteilung von Kundennachfrage identifizieren. Dies kann mir bspw. bei der Festlegung von Lagerstandorten von Nutzen sein. Die Logik und der grundlegende Ansatz sind dabei ähnlich zu üblicher entfernungsbasiertem Clustering.

Genauer: Ich wende k-means Clustering an um Kunden anhand ihrer räumlichen Entfernung zu gruppieren.

Der Algorithmus für das k-means Clustering wurde bereits von anderen Authoren gründlich und gut erklärt, bspw. in diesem Artikel: https://www.datanovia.com/de/lessons/k-means-clustering-in-r-algorith-and-practical-examples/

Zuerst definiere ich einen Datenrahmen mit zufälligen Längen- und Breitengradkoordinaten. Die Koordinaten stellen eine zufällige geographische Verteilung von Kundenstandorten dar.

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)

Nachstehend schaue ich mir den Kopf der erstellen Datentabelle an:

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

Der Standard k-means Clustering-Algorithmus wählt k zufällige Anfangspunkte aus und definiert diese als Cluster-Zentren.

Der Algorithmus ordnet dann jedem Clusterzentrum Datenpunkte zu, basierend auf minimaler Entfernung. In diesem Fall möchten wir später den Clustering-Algorithmus zur Lösung von Standortproblemen verwenden, wobei mehrere zu lokalisierende Lager berücksichtigt werden müssen. Ich halte es daher in diesem Fall stattdessen für angemessen Cluster-Zentren so auszuwählen dass diese weit voneinander entfernt sind. Dazu definiere ich eine Funktion, die die definierte Anzahl von Startzentren basierend auf der Längengraddimension des Geodatensatzes geographisch anordnet.

initial_centers <- function(customers,centers){
  quantiles <- c()
  for(i in 1:centers){
    quantiles <- c(quantiles,i*as.integer(nrow(customers)/centers))
  }
  quantiles
}

Wir können nun die obige Funktion in Kombination mit dem k-means Clustering-Algorithmus aus dem R-Basispaket anwenden. In diesem Beispiel leite ich vier Proximity-basierte Kundengruppen ab.

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

Oben zeige ich den Kopf des Ergebnisobjekts welches von der kmeans-Funktion zurückgegeben wird. Im Folgenden kombiniere ich die im kmeans-Objekt enthaltenen Cluster-Indizes mit dem Kundendatenrahmen, sodass wir in dem Kundendatenrahmen jetzt 3 Spalten haben. Dies ermöglicht es uns ggplots usw. zu erstellen – zwecks Visualisierung.

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

Ich vervollständige diesen Beitrag indem ich die Ergebnisse in einem ggplot visualisiere (Streudiagramm mit dem ggplot2 R-Paket). Zur Farbgebung verwende ich das Viridis-Paket in 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) 

Nachstehend führe ich einen zusätlichen Test mit 20 zu platzierenden Lagerstandorten durch.

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) 

Leave a Reply

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

Close

Meta