_Explorative Verfahren
Prof. Dr. Armin Eichinger
TH Deggendorf
05.11.2025
Entsprechung: Faktorwerte
Unterschied: MDS beruht auf subjektiv empfunden Un-/Ähnlichkeiten; Faktorenanalyse beruht auf Ausprägungen der Objekte auf ausgewiesenen Attributen
Vorteile MDS:
Nachteile MDS:
STRESS-Maß misst, wie gut die Distanzen die Ähnlichkeiten repräsentieren
Formel:
\(\text{Stress} = \sqrt{\frac{\sum_{i < j} \left( d_{ij} - \hat{d}_{ij} \right)^2}{\sum_{i < j} d_{ij}^2}}\)
Dabei ist:
Erklärung der Formel
Zähler \(\sum_{i < j} \left( d_{ij} - \hat{d}_{ij} \right)^2\): Der Zähler summiert die quadrierten Unterschiede zwischen den ursprünglichen Distanzen \(d_{ij}\) und den Distanzen \(\hat{d}_{ij}\) im MDS-Raum. Je größer diese Unterschiede sind, desto größer wird der Stress-Wert, was auf eine schlechtere Anpassung der MDS-Lösung hinweist.
Nenner \(\sum_{i < j} d_{ij}^2\): Der Nenner ist die Summe der quadrierten ursprünglichen Distanzen. Dieser dient zur Normalisierung, sodass der Stress-Wert unabhängig von der absoluten Skalierung der Distanzen ist.
Quadratwurzel: Die Quadratwurzel wird genommen, um den Stress-Wert in denselben Einheiten wie die Distanzen auszudrücken.
Interpretation des Stress-Werts
Anmerkung: Manchmal wird auch ein Stressmaß erzeugt, das 100mal größer ist. Es kann dann als Prozent Stress interpretiert werden.
Verdichtungskoeffizient \(Q = \frac{O(O-1)/2}{O \cdot k} = \frac{Zahl \: der \: Ähnlichkeiten}{Zahl \: der \: Koordinaten}\)
mit \(O\): Zahl der Objekte; \(k\): Zahl der Dimesionen
Handreichung (aus Backhaus, 2015): Werte ab 2.0
Q-Werte für k=2 & k=3:
| Anzahl Objekte | Dimensionen k=2 | Dimensionen k=3 |
|---|---|---|
| 7 | 1,50 | 1,00 |
| 8 | 1,75 | 1,17 |
| 9 | 2,00 | 1,33 |
| 10 | 2,25 | 1,50 |
| 11 | 2,50 | 1,67 |
| 12 | 2,75 | 1,83 |
| 13 | 3,00 | 2,00 |
Übung:
Übung:
Ausgangsdaten
# CSV-Datei einlesen
similarities <- read.csv("./data/eissorten_similarities.csv", row.names = 1, sep=";", dec = ",")
#similarities <- read.csv("https://bookdown.org/Armin_E/explorativ-multivariat-mds/data/eissorten_similarities.csv",
#row.names = 1, sep=";", dec = ",")
similarities Vanille Schokolade Erdbeer Stracciatella Joghurt Kaffee Zitrone
Vanille 7.00 NA NA NA NA NA NA
Schokolade 3.45 7.00 NA NA NA NA NA
Erdbeer 2.55 2.09 7.00 NA NA NA NA
Stracciatella 4.18 4.64 2.00 7.00 NA NA NA
Joghurt 3.36 2.45 3.73 4.18 7.00 NA NA
Kaffee 3.45 4.36 1.73 3.45 2.09 7.00 NA
Zitrone 2.00 1.64 2.91 2.09 3.36 1.45 7.00
Haselnuss 3.36 4.73 2.00 3.18 2.09 4.00 1.82
Himbeer 3.09 1.91 5.64 1.82 2.91 2.00 3.55
Haselnuss Himbeer
Vanille NA NA
Schokolade NA NA
Erdbeer NA NA
Stracciatella NA NA
Joghurt NA NA
Kaffee NA NA
Zitrone NA NA
Haselnuss 7 NA
Himbeer 2 7
Symmetrische Ähnlichkeitsmatrix
# DataFrame in eine Matrix umwandeln
similarities_matrix <- as.matrix(similarities)
# Die Matrix symmetrisieren: untere Dreiecksmatrix nach oben kopieren
symmetrized_matrix <- similarities_matrix
symmetrized_matrix[upper.tri(symmetrized_matrix)] <- t(symmetrized_matrix)[upper.tri(symmetrized_matrix)]
# Die symmetrisierte Matrix der Ähnlichkeiten anzeigen
similarities <- symmetrized_matrix
similarities Vanille Schokolade Erdbeer Stracciatella Joghurt Kaffee Zitrone
Vanille 7.00 3.45 2.55 4.18 3.36 3.45 2.00
Schokolade 3.45 7.00 2.09 4.64 2.45 4.36 1.64
Erdbeer 2.55 2.09 7.00 2.00 3.73 1.73 2.91
Stracciatella 4.18 4.64 2.00 7.00 4.18 3.45 2.09
Joghurt 3.36 2.45 3.73 4.18 7.00 2.09 3.36
Kaffee 3.45 4.36 1.73 3.45 2.09 7.00 1.45
Zitrone 2.00 1.64 2.91 2.09 3.36 1.45 7.00
Haselnuss 3.36 4.73 2.00 3.18 2.09 4.00 1.82
Himbeer 3.09 1.91 5.64 1.82 2.91 2.00 3.55
Haselnuss Himbeer
Vanille 3.36 3.09
Schokolade 4.73 1.91
Erdbeer 2.00 5.64
Stracciatella 3.18 1.82
Joghurt 2.09 2.91
Kaffee 4.00 2.00
Zitrone 1.82 3.55
Haselnuss 7.00 2.00
Himbeer 2.00 7.00
Distanzen
# Maximale Ähnlichkeit bestimmen
max_value <- max(similarities)
# Ab jetzt: Distanzen
distances <- max_value - similarities
distances Vanille Schokolade Erdbeer Stracciatella Joghurt Kaffee Zitrone
Vanille 0.00 3.55 4.45 2.82 3.64 3.55 5.00
Schokolade 3.55 0.00 4.91 2.36 4.55 2.64 5.36
Erdbeer 4.45 4.91 0.00 5.00 3.27 5.27 4.09
Stracciatella 2.82 2.36 5.00 0.00 2.82 3.55 4.91
Joghurt 3.64 4.55 3.27 2.82 0.00 4.91 3.64
Kaffee 3.55 2.64 5.27 3.55 4.91 0.00 5.55
Zitrone 5.00 5.36 4.09 4.91 3.64 5.55 0.00
Haselnuss 3.64 2.27 5.00 3.82 4.91 3.00 5.18
Himbeer 3.91 5.09 1.36 5.18 4.09 5.00 3.45
Haselnuss Himbeer
Vanille 3.64 3.91
Schokolade 2.27 5.09
Erdbeer 5.00 1.36
Stracciatella 3.82 5.18
Joghurt 4.91 4.09
Kaffee 3.00 5.00
Zitrone 5.18 3.45
Haselnuss 0.00 5.00
Himbeer 5.00 0.00
MDS für k=2 und k=1
library(MASS) #hier finden wir die Funktion isoMDS()
# Herzstück: Durchführung der MDS für k=2 und k=1
# isoMDS(): nichtmetrische MDS
mds_result <- isoMDS(distances, k=2, trace = FALSE)
mds_result_1 <- isoMDS(distances, k=1, trace = FALSE)
# Roh-Stress-Werte explizit anzeigen
mds_result$stress[1] 7.034366
[1] 17.67899
# Zur Interpretation: STRESS-1-Werte
stress1_zweidim <- sqrt(mds_result$stress / sum(distances^2))
stress1_eindim <- sqrt(mds_result_1$stress / sum(distances^2))
stress1_zweidim[1] 0.07432124
[1] 0.1178228
##### unwichtig: nur Aufhübschen ###########
# Ermittlung der Ausdehnung der Punkte für k=2
xrange <- range(mds_result$points[, 1])
yrange <- range(mds_result$points[, 2])
# Erweiterung der Ränder, damit Labels nicht abgeschnitten werden
xlim <- xrange + c(-1, 1) * diff(xrange) * 0.2
ylim <- yrange + c(-1, 1) * diff(yrange) * 0.2
########################################Plot für k=2
# Ergebnisse plotten für k=2
plot(mds_result$points, type = "p", main = "MDS Eissorten (k=2)", xlab = "Dimension 1",
ylab = "Dimension 2", xlim = xlim, ylim = ylim)
text(mds_result$points, labels = rownames(distances), cex = 0.8, pos = 1)
Plot für k=1
##### Plot für k=1 ###########
# Extrahieren der MDS-Koordinaten für k=1
mds_points_1 <- mds_result_1$points[, 1]
# Da k=1 nur eine Dimension hat, plottet man diese entlang der x-Achse
# rep(0, length(mds_points_1)) setzt die Y-Werte auf 0
plot(mds_points_1, rep(0, length(mds_points_1)), type = "p",
main = "MDS Eissorten (k=1)", xlab = "Dimension 1", ylab = "",
xlim = range(mds_points_1), ylim = c(-1, 1))
# Namen der Eissorten hinzufügen
text(mds_points_1, rep(0, length(mds_points_1)), labels = rownames(distances), cex = 0.8, pos = 1)
# Zur Interpretation: STRESS-1-Werte
#stress1_zweidim <- sqrt(mds_result$stress / sum(distances^2))
#stress1_eindim <- sqrt(mds_result_1$stress / sum(distances^2))
# Berechnung der Stress-Werte für verschiedene Dimensionen
stress_values <- sapply(1:5, function(k) {
sqrt(isoMDS(distances, k = k, trace = FALSE)$stress / sum(distances^2))
})
plot(1:5, stress_values, type = "b",
main = "Stress-Plot",
xlab = "Anzahl der Dimensionen", ylab = "Stress")
Distanz = max(Ähnlichkeit) - Ähnlichkeit
Aggregation der Ausgangswerte: Mittwelwerte (vgl. Beispiel Eissorten), Medianbildung
Alternativ: Je Person eine MDS; Aggregation (Mittelwerte) der Koordinaten
Das meint ChatGPT: Wenn die Erhaltung individueller Unterschiede wichtig ist, scheint die zweite Methode (separate MDS pro Person und Aggregation der Koordinaten) besser geeignet. Bei eher homogenen Gruppen oder wenn eine schnellere, einfachere Berechnung bevorzugt wird, kann die Aggregation der Ausgangswerte (Mittelwert oder Median) ausreichen.
Call:
lm(formula = Milchanteil ~ MDS1 + MDS2, data = data)
Residuals:
Min 1Q Median 3Q Max
-15.7391 -8.0975 0.5086 6.6030 15.7917
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 40.000 3.840 10.417 4.59e-05 ***
MDS1 5.461 1.686 3.240 0.0177 *
MDS2 3.483 3.460 1.006 0.3530
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 11.52 on 6 degrees of freedom
Multiple R-squared: 0.6938, Adjusted R-squared: 0.5917
F-statistic: 6.797 on 2 and 6 DF, p-value: 0.02872
# Beispiel-Daten: Milchanteile für die Eissorten
milchanteile <- c(60, 50, 30, 50, 40, 50, 0, 50, 30) # Schätzwerte für die genannten Sorten
# Erstellen eines Dataframes mit den MDS-Koordinaten und Milchanteilen
data <- data.frame(MDS1 = mds_result$points[, 1], MDS2 = mds_result$points[, 2], Milchanteil = milchanteile)
# Durchführung der linearen Regression
regression_model <- lm(Milchanteil ~ MDS1 + MDS2, data=data)
# Zusammenfassung des Regressionsmodells anzeigen
summary(regression_model)
# Speichern der Steigung und des Intercepts
b0 <- 0
b1 <- coef(regression_model)[3] / coef(regression_model)[2] # evtl. 2 und 3 vertauschen; ich glaube aber es stimmt so
# Plot der MDS-Koordinaten
plot(mds_result$points, main = "MDS-Lösung mit Regressionsgerade", xlab = "Dimension 1", ylab = "Dimension 2", xlim = xlim, ylim = ylim, asp=1)
text(mds_result$points, labels = rownames(data), pos = 3)
# Hinzufügen der Regressionsgerade
abline(a = b0, b = b1, col = "red", lwd = 2)
steigung <- b1
for (i in 1:nrow(data)) {
# Koordinaten des Datenpunkts
x0 <- data$MDS1[i]
y0 <- data$MDS2[i]
# Berechnung des Lotfußpunkts (x1, y1) auf die Linie y = steigung * x
x1 <- (x0 + steigung * y0) / (1 + steigung^2)
y1 <- steigung * x1
# Zeichnen des Lots
segments(x0, y0, x1, y1, col = "blue", lwd = 2)
# Zeichnen des Lotfußpunkts
points(x1, y1, col = "blue", pch = 19)
}