1.1 Motivation: Clusteranalyse mit Hilfe Gaußscher Mischverteilungen
Als Datenbeispiel verwendent wir die palmerpenguins
Daten (Horst, Hill, und Gorman 2020).
Diese Daten stammen aus Vermessungen von Pinguinpopulationen auf dem Palmer-Archipel (Antarktische Halbinsel). Pinguine sind oft schwer von einander zu unterscheiden (Abbildung 1.1). Wir werden versuchen, mit Hilfe einer Gaußschen Mischverteilung Gruppierungen in den Pinguindaten (Flossenlänge) zu finden. Um solche Mischverteilungen schätzen zu können, führen wir den EM Algorithmus ein.

Abbildung 1.1: Frecher Pinguin bei der Tat.
Der folgende Code-Chunck bereitet die Daten auf.
Achtung: Wir haben zwar die Information zu den verschiedenen Pinguin-Arten (
Penguine_Art
) tun aber im Folgenden so, also ob wir diese Information nicht kennen würden. Wir wollen alleine auf Basis der Flossenlängen (Penguine_Flosse
) die Gruppenzugehörigkeiten per Clusteranalyse bestimmen. (Im Nachhinein können wir dann mit Hilfe der Daten inPenguine_Art
prüfen, wie gut unsere Clusteranalyse ist.)
library("palmerpenguins") # Pinguin-Daten
library("RColorBrewer") # Hübsche Farben
library("scales") # Für transparente Farben: alpha()
col_v <- RColorBrewer::brewer.pal(n = 3, name = "Set2")
## Vorbereitung der Daten:
Pinguine <- palmerpenguins::penguins %>% # Pinguin-Daten
tidyr::as_tibble() %>% # Datenformat: 'tibble'-dataframe
dplyr::filter(species!="Adelie") %>% # Pinguin-Art 'Adelie' löschen
droplevels() %>% # Lösche das nicht mehr benötigte Adelie-Level
tidyr::drop_na() %>% # NAs löschen
dplyr::mutate(Art = species, # Variablen umbenennen
Flosse = flipper_length_mm) %>%
dplyr::select(Art, Flosse) # Variablen auswählen
##
n <- nrow(Pinguine) # Stichprobenumfang
## Variable 'Penguine_Art' aus Pinguine-Daten "herausziehen"
Penguine_Art <- dplyr::pull(Pinguine, Art)
## Variable 'Penguine_Flosse' aus Pinguine-Daten "herausziehen"
Penguine_Flosse <- dplyr::pull(Pinguine, Flosse)
## Plot
## Histogramm:
hist(x = Penguine_Flosse, freq = FALSE,
xlab="Flossenlänge (mm)", main="Pinguine\n(Zwei Gruppen)",
col=gray(.65,.5), border=gray(.35,.5), ylim=c(0.0003, 0.039))
## Stipchart hinzufügen:
stripchart(x = Penguine_Flosse, method = "jitter",
jitter = .0005, at = .001,
pch = 21, col=alpha(col_v[3],.5),
bg=alpha(col_v[3],.5), cex=1.3, add = TRUE)
Das Clusterverfahren basierend auf Gaußschen Mischverteilungen:
- Gaußsche Mischverteilung (per EM Algorithmus) schätzen
- Die Datenpunkte \(x_i\) derjenigen Gruppe zuordnen, welche die „a-posteriori-Wahrscheinlichkeit“ maximiert (siehe Abbildung 1.2)

Abbildung 1.2: Clusteranalyse basierend auf einer Mischverteilung mit zwei gewichteten Normalverteilungen.
Abbildung 1.2 zeigt das Resultat einer Clusteranalyse basierend auf einer Mischverteilung zweier gewichteter Normalverteilungen. Cluster-Ergebnis: 95% der Pinguine konnten richtig zugeordnet werden - lediglich auf Basis ihrer Flossenlängen.
Mit Hilfe der folgenden R-Codes kann die obige Clusteranalyse und die Ergebnisgrafik repliziert werden:
## mclust R-Paket:
## Clusteranalyse mit Hilfe von Gaußschen Mischmodellen
suppressMessages(library("mclust"))
## Anzahl der Gruppen
G <- 2
## Schätzung des Gaußschen Mischmodells (per EM Algorithmus)
## und Clusteranalyse
mclust_obj <- mclust::Mclust(data = Penguine_Flosse, G=G,
modelNames = "V",
verbose = FALSE)
# summary(mclust_obj)
# str(mclust_obj)
## Geschätzte Gruppen-Zuordnungen (Cluster-Resultat)
class <- mclust_obj$classification
## Anteil der korrekten Zuordnungen:
# cbind(class, Penguine_Art)
round(sum(class == as.numeric(Penguine_Art))/n, 2)
## Geschätzte Mittelwerte
mean_m <- t(mclust_obj$parameters$mean)
## Geschätzte Varianzen (und evtl. Kovarianzen)
cov_l <- list("Cov1" = mclust_obj$parameters$variance$sigmasq[1],
"Cov2" = mclust_obj$parameters$variance$sigmasq[2])
## Geschätzte Gewichte (a-priori-Wahrscheinlichkeiten)
prop_v <- mclust_obj$parameters$pro
## Auswerten der Gaußsche Mischung-Dichtefunktion
np <- 100 # Anzahl der Auswertungspunkte
xxd <- seq(min(Penguine_Flosse)-3, max(Penguine_Flosse)+5, length.out = np)
## Mischungs-Dichte
yyd <- dnorm(xxd, mean_m[1], sqrt(cov_l[[1]]))*prop_v[1] +
dnorm(xxd, mean_m[2], sqrt(cov_l[[2]]))*prop_v[2]
## Einzel-Dichten
yyd1 <- dnorm(xxd, mean_m[1], sqrt(cov_l[[1]]))*prop_v[1]
yyd2 <- dnorm(xxd, mean_m[2], sqrt(cov_l[[2]]))*prop_v[2]
## Plot
hist(x = Penguine_Flosse, xlab="Flossenlänge (mm)", main="Pinguine\n(Zwei Gruppen)",
col=gray(.65,.5), border=gray(.35,.5), freq = FALSE, ylim=c(0, 0.04))
lines(x = xxd, y=yyd, lwd=2, col=gray(.35,.75))
lines(x = xxd, y=yyd1, lwd=2, col=gray(.35,.75), lty=2)
lines(x = xxd, y=yyd2, lwd=2, col=gray(.35,.75), lty=2)
stripchart(Penguine_Flosse[class==1], method = "jitter", jitter = .0005, at = .001,
pch = 21, col=alpha(col_v[1],.5), bg=alpha(col_v[1],.5), cex=1.3, add = TRUE)
stripchart(Penguine_Flosse[class==2], method = "jitter", jitter = .0005, at = .001,
pch = 21, col=alpha(col_v[2],.5), bg=alpha(col_v[2],.5), cex=1.3, add = TRUE)
Literatur
Horst, Allison Marie, Alison Presmanes Hill, und Kristen B Gorman. 2020. palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data. https://allisonhorst.github.io/palmerpenguins/.