Hands On
Schreibe einen Kommentar

Clusteranalyse mit R-echts?

Die Ausgangslage:

Im Rahmen eines kleineren Instituts-Projekts ist mir ein alter Bekannter wieder begegnet: Die Cluster-Analyse. Als ein in SPSS sozialisierter Mensch, eigentlich auch kein Problem. Eigentlich.

Dieses „eigentlich“ hat zwei Ursachen:

  1. Eine faktisch irrationale Ursache:
    Ausgehend von einem anderen Projekt habe ich scheinbar ein Faible für R entwickelt. Klingt komisch, ist aber so.
  2. Die nachvollziehbare Ursache:
    Der zu clusternde Datensatz umfasst ca. 30.000 Records und (hwst.) 8 Variablen. Ein erster Probelauf in SPSS mit einem vergleichbaren Datensatz führte zu regelmäßigen Abstürzen meines Rechers (4 GB RAM – von SPSS ruckzuck aufgefressen).

Wo ist das Problem, werden sich nun manche fragen? Stärkeren Rechner suchen und Variablen verdichten; Problem behoben. Ja und nein: Stärkeren Rechner suchen scheidet aufgrund sportlichen Ehrgeizes aus. Eine überschaubare Clusterung wie diese sollte auch auf einem Standard-Rechner möglich sein. Variablen verdichten ist ntürlich immer eine schlaue Idee, aber: a) es handelt sich um unkorrelierte Variablen (= nachvollziehbar) und b) Faktoren erschweren den Endverbraucher der Clusterung eine sinnvolle Interpretation (= ev. nachvollziehbar, statistisch eigentlich irrelevant).

Die Konklusio

Die Clusterung soll in R durchgeführt werden, was ich in den nächsten Zeilen kurz beschreiben möchte. Bevor es dazu aber kommt, noch einige allgemeine Anmerkungen:

  • Wer sich das Thema Clusterung wieder ins Gedächtnis rufen möchte: Googlen, Wikipedia nachschauen, oder wer eine für Nicht-Statistik-Profis verständliche Erklärung sucht:
    Backhaus, K.; Erichson, B.; Plinke, W. und Weiber, R. (2011): Multivariate Analysemethoden: eine anwendungsorientierte Einführung. 13. Aufl., Berlin, Springer.
  • Die verwendete Software R kann direkt über das R-Project bezogen werden.
  • Um die Bedienung von R etwas komfortabler zu gestalten, sei hier die Arbeitsumgebung „RStudio“ empfohlen.
  • In weiterer Folge wird die prinzipielle Vorgehensweise, nicht jedoch die konkreten Ergebnisse meiner Analyse vorgestellt.
  • Die beschriebene Vorgehensweise geht von unabhängigen (= nicht untereinander korrelierten) Variablen aus. Sollte diese Voraussetzung nicht erfüllt sein, müsste zuvor eine Verdichtung der Variablen mittlels Faktorenanalyse durchgeführt werden. Auch hier gilt wieder: Wer sich das Thema Faktorenanalyse wieder ins Gedächtnis rufen möchte: Googlen, Wikipedia oder bei Backhaus et al. (2011) nachlesen.
  • @ R-Profis: Ich weiß, der hier angeführte Code ist a) zusammengeklaut (vor allem von hier: http://www.statmethods.net/advstats/cluster.html), b) nicht perfekt und c) könnte viiiiiiiiiiiiiiiiiiel kürzer umgesetzt werden. Ja. Für die Erstellung des hier angeführten Codes war es jedoch wichtig, dass a) auch R-Dummies zumindest eine reale Chance haben, diesen lesen zu können und b) dieser für Standard-Fälle (wie man auch immer solche definieren möchte) zufriedenstellende Cluster-Lösungen liefert.
  • @ Statistik-Profis: Ich bins mir bewusst, hier nur sehr oberflächlich unterschiedliche Aspekte von Clusteranalysen abzudecken.

Und damit zur eigentlichen Action:

A) Der Daten-Import & deren Aufbereitung

Die verwendete Datensatz „testdata2.dbf“ beinhaltat Vektor-Rasterzellen der Statistik Austria mit Angaben zu HauptwohnsitzerInnen und u.a. deren höchsten Bildungsabschlüssen.

setwd("~/Dokumente/1___Work/Cluster_R")
library("foreign", lib.loc="/usr/lib/R/library")
# Import
temp = read.dbf("testdata2.dbf")

Über „setwd“ wird das Arbeitsverzeichnis von R festgesetzt, die Library „foreign“ beinhaltet einige benötigte Funktionen und mittels „read.dbf“ wird der Testdatensatz eingelesen.

Nun zur Aufbereitung der Daten:

mydataRAW <- temp[c("HWS01","BILDUNG_AK","BILDUNG_MA","BILDUNG_NI")]
mydata <- scale(mydataRAW)

Da der importierte Datensatz mehr Variablen enthält, als für die Clusterung nötig, werden die cluster-relevanten Variablen in das Datenset „mydataRAW“ ausgespielt. Um Verzerrungen durch unterschiedliche absolute Merkmalsausprägungen zwischen den Variablen zu vermeiden, werden die Variablen mittels „scale“ z-transformiert (= Mittelwert: 0, Standardabweichung: 1).

B) Anzahl der Cluster ermitteln

Nach der Aufbereitung der Daten bleibt die Frage zu klären, in wie viele Cluster diese Daten sinnvollerweise unterteilt werden sollten. Analog zur Ausgabe einer Proximity Matrix in SPSS kann auch in R Thorndikes „Elbow-Rule“ angewandt werden. Basis dafür bildet ein „Scree-Plot„:

scree

@ Interpretation des Scree-Plots: Auf der Abszisse die Cluster-Lösungen für 1 bis 14 Cluster, auf der Ordinate die „Heterogenität“ (= Summe der quad. Abweichungen in den Clustern) der jeweiligen Cluster-Lösungen. Der „Elbow“ ist jene Cluster-Lösung, nach der ein starkes Ansteigen der Heterogenität beobachtbar ist. Das Auffinden des Elbows ist somit eine Interpretationsleistung der/des BearbeiterIn. Im vorliegenden Fall würde ich mich für eine Lösung mit 4 Clustern entscheiden.

Im Unterschied zu SPSS (kennt hier jemand einen Trick?) kann der Scree-Plot in R dirket erstellt werden:

wss <- (nrow(mydata)-1)*sum(apply(mydata,2,var))
for (i in 2:14) wss[i] <- sum(kmeans(mydata,centers=i)$withinss)
plot(1:14, wss, type="b", xlab="Anzahl Cluster",ylab="Sum of squares within groups")

Die Anzahl der zu berücksichtigenden Cluster-Lösungen wird zweimal angegeben: Bei der Berechnung der Cluster-Lösungen („for (i in 2:14) …“) und bei der Visualisierung („plot(1:14, …“).

C) Cluster-Zuordnungen (mittels k-Means etc.)

Die so ermittete Anzahl der Cluster (= 4) geht dann direkt in die finale Clusterung mittels k-Means ein:

# K-Means Clusterung
cl4 <- kmeans(mydata, 4)

Als Alternative kann natürlich auch eine andere Strategie der Clusterbildung verwendet werden, beispielsweise hierarchische Clusterung (hier: mittels Ward-Fusionierung):

# Distanzmatrix erzeugen
d <- dist(mydata, method = "euclidean")
# Clusterung
cl4 <- hclust(d, method="ward")
# Dendogramm ausgeben
plot(cl4)
# Finale Cluster abgrenzen
groups <- cutree(cl4, k=4)

Egal nach welchem Verfahren die Cluster erzeugt wurden (hier: k-Means), die Zuordnung der Records zu den Clustern sollte noch in der Datentabelle abgelegt werden. Um die Charakterisierung der Cluster auch anhand der ursprünglichen (nicht-z-transformierten) Werte zu ermöglichen, wird die Cluster-Zuordnung auch in die Tabelle der Ausgangsdaten eingetragen:

# Cluster-Zuordnung in Datentabelle (z-tranformiert) eintragen
mydata <- data.frame(mydata, cl4$cluster)
#Cluster-Zuordnung in nicht-transformierte Datentabelle eintragen
mydataRAW$cl4 <- mydata$cl4

D) Trennschärfe der gefundenen Cluster-Lösung(en) einschätzen

Einen spannenden – mir bisher nicht bekannten – Zugang zur Abschätzung der Trennschärfe der gefundenen Cluster bietet die Funktion „clusplot“ aus der Library „cluster“:
Anhand einer zweidimensionale Hauptkomponentenanalyse (auf neudeutsch: PCA) werden dabei die einzelnen Cluster visualisiert. Mehr Hintergrund zum Thema PCA findet sich auf Wikipedia oder wieder einmal bei Backhaus et al. (2011).

# Cluster auf den ersten beiden "pricipal components" visulaisieruen
library(cluster)
clusplot(mydata, cl4$cluster, color=TRUE, shade=TRUE, labels=4, lines=0)

Und das sieht dann so aus:

pca

@ Interpretation: Cluster 1 weist die höchste, Cluster 2 die geringste interne Homogenität auf. Alle vier Cluster weisen keine Überschneidungen sowie deutliche Distanzen zueinander auf, was auf eine gute inhaltliche Unterschiedbarkeit der Cluster hinweist.

E) Beschreibung der gefundenen Cluster

Um die gefundenen Cluster inhaltlich besser zu verstehen, bietet sich deren Beschreibung anhand der jeweiligen Variablen an. Dazu besteht die Möglichkeit mittels „aggregate“ tabellarische Auswertungen von Lage- und Streuungsmaßen vorzunehmen:

# metr. Variablen: Mittelwert (z-transformiert) je Cluster
ClusterMeans <- aggregate(mydata,by=list(cl4$cluster),FUN=mean)
ClusterMeans
# metr. Variablen: Mittelwert je Cluster ClusterMeansRAW <- aggregate(mydataRAW,by=list(mydataRAW$cl4),FUN=mean)
ClusterMeansRAW

Diese Tabellen sehen dann in etwa so aus:

table

Alternativ können auch graphische Zugänge, beispielsweise Box-Plots oder Balkendiagramme, verwendet werden. Dazu bietet sich eine Batch-Erstellung mittels „lapply“ an:

# Auswahl der Variablen (hier: Varialben 1 bis 4; von links nach rechts)
theVarList <- c(1:4)
# für jede ausgew. Variable: Bar- & Box-Plot
lapply(theVarList, function(x){
 boxplot(mydataRAW[[x]]~mydataRAW$cl4, main=colnames(mydataRAW)[x], xlab = "Cluster")
 # Mittelwerte
 seMeans <- tapply(mydataRAW[[x]], mydataRAW$cl4, FUN=mean)
 barplot(seMeans, main=colnames(mydataRAW)[x], xlab = "Cluster", ylab = "Mean")
 })

Je ausgewählter Variable gibt das dann folgende zwei Plots:
Einen Bar-Plot der jeweiligen Cluster-Mittelwerte.

bar

Und wer sich für die Streuung der Variable innerhalb der jeweiligen Cluster interessiert, wird mit dem Box-Plot glücklich werden.

Box

Wer mit ordinalen oder nominalen Daten arbeitet, wird zur Beschreibung der Cluster auf Häufigkeitsauswertungen zurückgreifen müssen. Dazu bietet R folgende (Basis-)Funktionen an:

# Kreuztabelle mit Häufigkeiten 
KTable <- table(mydataRAW$F8,mydataRAW$cl4)
KTable

#Kreuztabelle mit Relativwerten
prop.table(KTable)
# Kreuztabelle mit Zeilensummen 
margin.table(KTable,1)
# Kreuztabelle mit Spaltensummen margin.table(KTable,2)

F) Exportieren der gefundenen Cluster-Zuordnungen

Wer die Cluster-Zuordnung in anderen Programmen nutzen möchte, kann auf eine Fülle von Exportformaten zurückgreifen. Handelt es sich bei den Records um räumliche Einheiten – beispielsweise Gemeinden, Rasterzellen etc. – bietet sich ein Export in Richtung GIS an. Dafür bieten sich die Formate CSV bzw. DBF an:

# den Namen & Location (relativ) des zu erzeugenden Files
exportFile = "___OUTPUT/cluster_V1"
# das File schreiben als a) csv, b) dbf
write.table(mydataRAW, paste(exportFile,".csv", sep=""), sep = ",",
            col.names = NA,
            qmethod = "double")
write.dbf(mydataRAW, paste(exportFile,".dbf", sep=""), factor2char = FALSE)

Fazit: R hat’s drauf

Alle, die bis hierher gelesen haben, werden es schon bemerkt haben: R erfordert ein wenig Code-Getipsel. Wenn man sich jedoch einmal eine grobe Analysestrategie samt Code zurecht gelegt hat, lassen sich Analysevarianten sehr schnell umsetzen. Darin findet sich aber noch kein deutlicher Unterschied zu einer Skript-basierten Herangehensweise an SPSS. Die zentralen Stärken von R im Bereich Cluster-Analyse liegen aus meiner Sicht in drei Punkten:

  • Der automatischen Erstellung von Scree-Plots;
  • Der Möglichkeit zur Visulalisierung der Trennschärfe von Cluster-Lösungen mittels PCA;
  • Der freien Verfügbarkeit und Performanz von R.

Kommentar verfassen