Korrelation

Korrelation
Deskriptive Statistik
Interpretation
R
Python
Pearson, Spearman und Kendall als Masse, ihre Grenzen und Fallstricke.

Kernideen

  • Das Streudiagramm kommt vor jeder Kennzahl, nicht danach.
  • Die Kovarianz hängt an den Einheiten, die Korrelation nicht.
  • Pearson misst linearen Zusammenhang, Spearman und Kendall messen monotonen.
  • Ein Wert nahe null schliesst einen starken, aber krummen Zusammenhang nicht aus.
  • Ein einzelner Ausreisser kann das Vorzeichen von Pearson umkehren.
  • \(r^2\) ist der Anteil gemeinsamer Streuung und schon deshalb ist \(r = 0.5\) nicht “halb so stark” wie \(r = 1\).
  • Korrelation ist keine Kausalität, und das ist keine Floskel, sondern ein nachrechenbarer Sachverhalt.

Erklärung

Vorwissen: Lage- und Streuungsmasse für Varianz und Standardabweichung, Skalenniveaus für die Frage, welches Mass zulässig ist. Ob ein beobachteter Zusammenhang mehr ist als Zufall, beantwortet der Korrelationstest; die gerichtete Fassung steht unter einfache lineare Regression.

Von einem Merkmal zu zweien

Bisher ging es um die Verteilung eines Merkmals. Die interessanteren Fragen betreffen zwei: Steigt der Verbrauch mit der Laufzeit? Hängt der Blutdruck vom Alter ab? Für solche Fragen braucht es ein Mass für den gemeinsamen Verlauf.

Vor der Kennzahl steht die Grafik. Ein Zusammenhang lässt sich sehen, bevor er gerechnet wird, und was man sieht, entscheidet darüber, welche Kennzahl überhaupt passt.

Kovarianz und Korrelation

Die Kovarianz misst, ob zwei Merkmale gemeinsam von ihrem jeweiligen Mittel abweichen. Liegen beide gleichzeitig über oder unter ihrem Mittel, ist der Beitrag positiv.

\[\text{cov}(x,y) = \frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})(y_i - \bar{y})\]

Ihr Nachteil ist, dass sie an den Einheiten hängt. Die Korrelation nach Pearson behebt das, indem sie durch die beiden Standardabweichungen teilt. Das Ergebnis liegt immer zwischen minus eins und eins und ist einheitenfrei:

\[r = \frac{\text{cov}(x,y)}{s_x \cdot s_y}\]

Die drei gebräuchlichen Masse

Mass Was es misst Rechnet auf Ab Skalenniveau Robust
Pearson \(r\) linearer Zusammenhang den Werten metrisch nein
Spearman \(\rho\) monotoner Zusammenhang den Rängen ordinal ja
Kendall \(\tau\) monotoner Zusammenhang, über Paarvergleiche den Rängen ordinal ja

Spearman ist nichts anderes als Pearson, angewendet auf die Ränge. Kendall geht anders vor: Er zählt für alle Paare von Beobachtungen, ob sie gleichgerichtet (konkordant) oder gegenläufig (diskordant) sind, und bildet daraus \(\tau = \frac{\text{konkordant} - \text{diskordant}}{\text{Anzahl Paare}}\).

Daraus folgen die praktischen Unterschiede:

Spearman Kendall
Werte bei mittleren Zusammenhängen grösser kleiner (typisch rund zwei Drittel des Spearman-Werts)
Deutung “wie gut passen die Ränge zueinander” direkt als Wahrscheinlichkeitsdifferenz: \((\tau + 1)/2\) ist der Anteil gleichgerichteter Paare
Bei vielen Bindungen weniger zuverlässig besser geeignet (Varianten \(\tau_b\), \(\tau_c\))
Rechenaufwand gering quadratisch in \(n\)

Was \(r\) bedeutet und was nicht

\(r^2\) ist der Anteil der Streuung, den die beiden Merkmale teilen. Daraus folgt eine Skala, die dem ersten Eindruck widerspricht:

\(r\) \(r^2\) gemeinsame Streuung
0.9 0.81 81 %
0.7 0.49 49 %
0.5 0.25 25 %
0.3 0.09 9 %

Ein \(r\) von 0.5 ist also nicht “halb so stark” wie ein \(r\) von 1, sondern beschreibt einen Zusammenhang, bei dem drei Viertel der Streuung anderswo herkommen.

Faustregeln für die Stärke sind fachabhängig. In der Physik gilt \(r = 0.9\) als schwach, in der Sozialforschung als aussergewöhnlich hoch. Wer Schwellen nennt, sollte die Quelle dazu nennen. Aussagekräftiger als jede Schwelle ist das Streudiagramm plus die Angabe von \(n\).

Der wichtigste Vorbehalt

Ein statistischer Zusammenhang belegt keine Ursache. Drei Erklärungen sind immer möglich, und die Daten allein unterscheiden nicht zwischen ihnen: \(x\) wirkt auf \(y\), \(y\) wirkt auf \(x\), oder eine dritte, nicht beobachtete Grösse treibt beide. Beispiel 5 rechnet den dritten Fall durch.

Beispiele

Frage und Datenlage

Vier Datensätze zu je elf Punkten mit praktisch identischen Kennzahlen. Das Beispiel stammt von Anscombe und ist in R eingebaut.

Rechnung

lang <- data.frame(
  satz = rep(1:4, each = 11),
  x = c(anscombe$x1, anscombe$x2, anscombe$x3, anscombe$x4),
  y = c(anscombe$y1, anscombe$y2, anscombe$y3, anscombe$y4)
)

ggplot(lang, aes(x, y)) +
  geom_point(size = 1.8) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE,
              colour = "black", linewidth = 0.5) +
  facet_wrap(~ satz, nrow = 1) +
  labs(x = NULL, y = NULL)

lang |>
  group_by(satz) |>
  summarise(mittel_x = mean(x), sd_x = sd(x),
            mittel_y = round(mean(y), 2), sd_y = round(sd(y), 2),
            pearson = round(cor(x, y), 3),
            spearman = round(cor(x, y, method = "spearman"), 3),
            .groups = "drop")
# A tibble: 4 × 7
   satz mittel_x  sd_x mittel_y  sd_y pearson spearman
  <int>    <dbl> <dbl>    <dbl> <dbl>   <dbl>    <dbl>
1     1        9  3.32      7.5  2.03   0.816    0.818
2     2        9  3.32      7.5  2.03   0.816    0.691
3     3        9  3.32      7.5  2.03   0.816    0.991
4     4        9  3.32      7.5  2.03   0.817    0.5  
Abbildung 1: Beispiel 1: vier Datensätze mit gleichem Mittelwert, gleicher Varianz und gleicher Korrelation.
x123 = np.array([10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5], dtype=float)
saetze = {
    1: (x123, np.array([8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26,
                        10.84, 4.82, 5.68])),
    2: (x123, np.array([9.14, 8.14, 8.74, 8.77, 9.26, 8.10, 6.13, 3.10,
                        9.13, 7.26, 4.74])),
    3: (x123, np.array([7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39,
                        8.15, 6.42, 5.73])),
    4: (np.array([8, 8, 8, 8, 8, 8, 8, 19, 8, 8, 8], dtype=float),
        np.array([6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.50, 5.56,
                  7.91, 6.89])),
}

fig, achsen = plt.subplots(1, 4, figsize=(7, 2.8), sharey=True)
zeilen = []
for achse, (nummer, (x, y)) in zip(achsen, saetze.items()):
    achse.scatter(x, y, s=14, color="black")
    steigung, achsenabschnitt = np.polyfit(x, y, 1)
    gitter = np.linspace(x.min(), x.max(), 2)
    achse.plot(gitter, achsenabschnitt + steigung * gitter,
               color="black", lw=0.6)
    achse.set_title(f"Satz {nummer}", fontsize=9)
    zeilen.append({"satz": nummer, "mittel_x": x.mean(), "sd_x": x.std(ddof=1),
                   "mittel_y": y.mean(), "sd_y": y.std(ddof=1),
                   "pearson": np.corrcoef(x, y)[0, 1],
                   "spearman": stats.spearmanr(x, y).statistic})
plt.tight_layout()
plt.show()
Abbildung 2: Beispiel 1: dieselben vier Datensätze in Python.
print(pd.DataFrame(zeilen).round(3).to_string(index=False))
 satz  mittel_x  sd_x  mittel_y  sd_y  pearson  spearman
    1       9.0 3.317     7.501 2.032    0.816     0.818
    2       9.0 3.317     7.501 2.032    0.816     0.691
    3       9.0 3.317     7.500 2.030    0.816     0.991
    4       9.0 3.317     7.501 2.031    0.817     0.500

Output Zeile für Zeile

Satz Mittel x SD x Mittel y SD y Pearson Spearman
1 9.0 3.32 7.50 2.03 0.816 0.818
2 9.0 3.32 7.50 2.03 0.816 0.691
3 9.0 3.32 7.50 2.03 0.816 0.991
4 9.0 3.32 7.50 2.03 0.817 0.500
Satz Was das Bild zeigt Was die Kennzahl verschweigt
1 eine gleichmässig streuende Punktwolke um eine Gerade nichts, nur hier beschreibt \(r\), was man sieht
2 eine exakte Parabel Der Zusammenhang ist perfekt und nicht linear. Pearson misst nur den geraden Anteil.
3 eine perfekte Gerade plus ein Ausreisser Ohne den einen Punkt wäre \(r = 1\). Der Ausreisser drückt ihn auf 0.816.
4 zehn Punkte auf einer Senkrechten plus einer weit rechts Die Korrelation wird von einem einzigen Punkt erzeugt. Ohne ihn ist sie nicht definiert.

Die Spearman-Spalte ist die interessantere: Anders als Pearson unterscheidet sie die vier Sätze deutlich (0.82, 0.69, 0.99, 0.50). Das ist kein Zufall, die Ränge reagieren anders auf Krümmung und Ausreisser als die Werte selbst.

Trotzdem ersetzt auch sie das Bild nicht: Bei Satz 4 liefert sie 0.50 und sagt damit nicht, dass zehn der elf Punkte denselben x-Wert haben.

Interpretation

Jede Kennzahl fasst zusammen und wirft dabei etwas weg. Das Streudiagramm zeigt, was weggeworfen wurde und ist deshalb der erste Schritt, nicht der letzte.

Frage und Datenlage

120 Anlagen mit Laufzeit in Stunden und Verbrauch in Litern. Was passiert mit Kovarianz und Korrelation, wenn man Liter in Milliliter umrechnet?

Rechnung

ggplot(anlagen, aes(laufzeit, verbrauch)) +
  geom_point(alpha = 0.6) +
  labs(x = "Laufzeit (h)", y = "Verbrauch (l)")

round(c(
  cov_liter = cov(anlagen$laufzeit, anlagen$verbrauch),
  cov_milliliter = cov(anlagen$laufzeit, anlagen$verbrauch * 1000),
  r_liter = cor(anlagen$laufzeit, anlagen$verbrauch),
  r_milliliter = cor(anlagen$laufzeit, anlagen$verbrauch * 1000)
), 4)
     cov_liter cov_milliliter        r_liter   r_milliliter 
       70.7551     70755.1254         0.9333         0.9333 
# Die Korrelation von Hand, zur Kontrolle
round(cov(anlagen$laufzeit, anlagen$verbrauch) /
        (sd(anlagen$laufzeit) * sd(anlagen$verbrauch)), 4)
[1] 0.9333
round(c(sd_laufzeit = sd(anlagen$laufzeit), sd_verbrauch = sd(anlagen$verbrauch),
        r_quadrat = cor(anlagen$laufzeit, anlagen$verbrauch)^2), 4)
 sd_laufzeit sd_verbrauch    r_quadrat 
      4.9271      15.3864       0.8711 
Abbildung 3: Beispiel 2: erster Blick auf zwei Merkmale. Die Punktwolke steigt und wirkt geradlinig.
fig, achse = plt.subplots(figsize=(7, 3.2))
achse.scatter(anlagen["laufzeit"], anlagen["verbrauch"], s=14, alpha=0.6,
              color="black")
achse.set_xlabel("Laufzeit (h)")
achse.set_ylabel("Verbrauch (l)")
plt.tight_layout()
plt.show()
Abbildung 4: Beispiel 2: dasselbe Streudiagramm in Python.
kov = np.cov(anlagen["laufzeit"], anlagen["verbrauch"])[0, 1]
r = np.corrcoef(anlagen["laufzeit"], anlagen["verbrauch"])[0, 1]
print({"cov_liter": round(float(kov), 4),
       "cov_milliliter": round(float(np.cov(anlagen["laufzeit"],
                                            anlagen["verbrauch"] * 1000)[0, 1]), 1),
       "r_liter": round(float(r), 4),
       "r_milliliter": round(float(np.corrcoef(anlagen["laufzeit"],
                                               anlagen["verbrauch"] * 1000)[0, 1]), 4)})
{'cov_liter': 70.7551, 'cov_milliliter': 70755.1, 'r_liter': 0.9333, 'r_milliliter': 0.9333}
sx = anlagen["laufzeit"].std(ddof=1)
sy = anlagen["verbrauch"].std(ddof=1)
print("von Hand:", round(float(kov / (sx * sy)), 4))
von Hand: 0.9333
print({"sd_laufzeit": round(float(sx), 4), "sd_verbrauch": round(float(sy), 4),
       "r_quadrat": round(float(r ** 2), 4)})
{'sd_laufzeit': 4.9271, 'sd_verbrauch': 15.3864, 'r_quadrat': 0.8711}

Output Zeile für Zeile

Grösse in Litern in Millilitern Faktor
Kovarianz 70.755 70 755 1000
Korrelation 0.9333 0.9333 1
Ausgabe Wert hier Wie er zu lesen ist
Kovarianz 70.755 Einheit: Stunden mal Liter Die Zahl ist für sich genommen nicht deutbar. Ist 70 viel? Das hängt daran, in welchen Einheiten gemessen wurde.
Kovarianz mal 1000 genau der Umrechnungsfaktor Am Zusammenhang hat sich nichts geändert, an der Zahl alles.
Korrelation unverändert 0.9333 in beiden Fällen Im Nenner stehen die Standardabweichungen, und \(s_y\) wächst um denselben Faktor 1000. Er kürzt sich heraus. Genau das ist der Zweck der Normierung.
von Hand nachgerechnet \(70.755 / (4.927 \cdot 15.386) = 0.9333\) Die Korrelation ist nichts anderes als eine auf die Streuungen bezogene Kovarianz.
\(r^2\) 0.871 87 Prozent der Streuung im Verbrauch gehen mit der Laufzeit einher.

Was die Normierung kostet: Die Kovarianz enthält die Grössenordnung des Zusammenhangs, die Korrelation nicht. Ein \(r\) von 0.93 sagt nichts darüber, um wie viel der Verbrauch je Stunde steigt, das sagt die Steigung einer Regression, hier rund 2.8 Liter je Stunde.

Für die Frage “wie eng” ist die Korrelation richtig, für “wie viel” die Regression. Beide werden regelmässig verwechselt.

Interpretation und Ergebnissatz

Laufzeit und Verbrauch hängen stark linear zusammen (Pearson \(r\) = 0.93, \(r^2\) = 0.87, n = 120). Die Korrelation ist einheitenfrei und ändert sich nicht, wenn der Verbrauch in Millilitern statt Litern gemessen wird.

Frage und Datenlage

Drei Situationen, in denen die drei Masse auseinanderlaufen:

  1. ein monotoner, aber gekrümmter Zusammenhang: \(y = e^{x/10}\)
  2. ein U-förmiger Zusammenhang: \(y = x^2\) plus Rauschen
  3. eine saubere Gerade plus einen einzigen Ausreisser

Rechnung

x_exp <- 1:50
y_exp <- exp(x_exp / 10)

x_u <- seq(-3, 3, length.out = 80)
y_u <- x_u^2 + normalwerte(6613, 80, 0, 0.5)

x_rein <- 1:20
y_rein <- x_rein + normalwerte(6614, 20, 0, 1)
x_aus <- c(x_rein, 40)
y_aus <- c(y_rein, -20)

par(mfrow = c(1, 3), mar = c(4, 4, 2.5, 1))
plot(x_exp, y_exp, pch = 16, cex = 0.7, main = "monoton, gekrümmt")
plot(x_u, y_u, pch = 16, cex = 0.7, main = "U-förmig")
plot(x_aus, y_aus, pch = 16, cex = 0.7, main = "mit Ausreisser")
par(mfrow = c(1, 1))

masse <- function(x, y) {
  c(pearson = cor(x, y),
    spearman = cor(x, y, method = "spearman"),
    kendall = cor(x, y, method = "kendall"))
}

round(rbind(gekruemmt = masse(x_exp, y_exp),
            u_foermig = masse(x_u, y_u),
            ohne_ausreisser = masse(x_rein, y_rein),
            mit_ausreisser = masse(x_aus, y_aus)), 3)
                pearson spearman kendall
gekruemmt         0.858    1.000   1.000
u_foermig        -0.015   -0.015  -0.008
ohne_ausreisser   0.976    0.977   0.895
mit_ausreisser   -0.108    0.708   0.714
# Beim U-Fall hilft die Transformation
round(cor(abs(x_u), y_u), 3)
[1] 0.94
Abbildung 5: Beispiel 3: gekrümmt, U-förmig und mit Ausreisser.
x_exp = np.arange(1, 51, dtype=float)
y_exp = np.exp(x_exp / 10)

x_u = np.linspace(-3, 3, 80)
y_u = x_u ** 2 + normalwerte(6613, 80, 0, 0.5)

x_rein = np.arange(1, 21, dtype=float)
y_rein = x_rein + normalwerte(6614, 20, 0, 1)
x_aus = np.append(x_rein, 40)
y_aus = np.append(y_rein, -20)

fig, achsen = plt.subplots(1, 3, figsize=(7, 2.8))
for achse, (x, y, titel) in zip(achsen, [
        (x_exp, y_exp, "monoton, gekrümmt"),
        (x_u, y_u, "U-förmig"),
        (x_aus, y_aus, "mit Ausreisser")]):
    achse.scatter(x, y, s=12, color="black")
    achse.set_title(titel, fontsize=9)
plt.tight_layout()
plt.show()
Abbildung 6: Beispiel 3: dieselben drei Fälle in Python.
def masse(x, y):
    return {"pearson": np.corrcoef(x, y)[0, 1],
            "spearman": stats.spearmanr(x, y).statistic,
            "kendall": stats.kendalltau(x, y).statistic}


print(pd.DataFrame({
    "gekruemmt": masse(x_exp, y_exp),
    "u_foermig": masse(x_u, y_u),
    "ohne_ausreisser": masse(x_rein, y_rein),
    "mit_ausreisser": masse(x_aus, y_aus),
}).T.round(3))
                 pearson  spearman  kendall
gekruemmt          0.858     1.000    1.000
u_foermig         -0.015    -0.015   -0.008
ohne_ausreisser    0.976     0.977    0.895
mit_ausreisser    -0.108     0.708    0.714
print("Nach Transformation |x| im U-Fall:",
      round(float(np.corrcoef(np.abs(x_u), y_u)[0, 1]), 3))
Nach Transformation |x| im U-Fall: 0.94

Output Zeile für Zeile

Situation Pearson Spearman Kendall
monoton, gekrümmt 0.858 1.000 1.000
U-förmig -0.015 -0.015 -0.008
Gerade ohne Ausreisser 0.976 0.977 0.895
Gerade mit einem Ausreisser -0.108 0.708 0.714
Fall Was passiert
Gekrümmt Spearman und Kendall liefern exakt eins, weil die Reihenfolge perfekt übereinstimmt, mehr misst eine Rangkorrelation nicht. Pearson bleibt bei 0.858, weil die Beziehung nicht geradlinig ist. Wer 0.858 als “etwas Streuung” liest, liegt falsch: Es gibt keine Streuung, nur Krümmung.
U-förmig Alle drei liefern praktisch null und der Zusammenhang ist trotzdem perfekt deterministisch. Auch die Rangkorrelation versagt hier, denn der Zusammenhang ist nicht monoton: y fällt erst, dann steigt es.
Ausreisser Der spektakulärste Fall: Ein einziger von 21 Punkten dreht Pearson von +0.976 auf -0.108 um. Spearman fällt nur auf 0.708, weil der Ausreisser rangmässig nur ein Punkt unter vielen ist.

Was im U-Fall hilft: Die Korrelation zwischen \(\lvert x \rvert\) und \(y\) beträgt 0.94. Der Zusammenhang war also die ganze Zeit da, nur nicht in der Form, die eine Korrelation messen kann.

Das ist das allgemeine Rezept: Wenn das Bild eine Struktur zeigt, die die Kennzahl nicht findet, transformiert man die Variablen, statt die Kennzahl zu verwerfen. Übliche Kandidaten sind Logarithmus (bei multiplikativen Zusammenhängen), Wurzel und Betrag.

Und der Grund, warum Kendall bei “mit Ausreisser” fast gleichauf mit Spearman liegt (0.714 gegen 0.708), obwohl es sonst kleinere Werte liefert: Beide zählen denselben einen Punkt als eine Beobachtung.

Interpretation und Ergebnissatz

Zwischen den Merkmalen besteht ein monotoner Zusammenhang (Spearman \(\rho\) = 1.00, Kendall \(\tau\) = 1.00, n = 50). Die Pearson-Korrelation von 0.86 unterschätzt ihn, weil der Verlauf exponentiell und nicht linear ist.

Frage und Datenlage

Die Wahl zwischen den drei Massen ist keine Geschmacksfrage. Sie folgt aus dem Skalenniveau und aus dem, was das Streudiagramm zeigt.

Rechnung

# Ordinale Daten: Zufriedenheit und Weiterempfehlung, je 1 bis 5
zufrieden <- c(5, 4, 4, 5, 3, 2, 1, 3, 4, 5, 2, 3, 5, 4, 1, 2, 3, 4, 5, 3)
empfehlen <- c(5, 5, 4, 4, 3, 2, 1, 4, 4, 5, 1, 3, 5, 3, 2, 2, 4, 5, 4, 3)

table(zufrieden, empfehlen)
         empfehlen
zufrieden 1 2 3 4 5
        1 1 1 0 0 0
        2 1 2 0 0 0
        3 0 0 3 2 0
        4 0 0 1 2 2
        5 0 0 0 2 3
round(c(pearson = cor(zufrieden, empfehlen),
        spearman = cor(zufrieden, empfehlen, method = "spearman"),
        kendall = cor(zufrieden, empfehlen, method = "kendall")), 3)
 pearson spearman  kendall 
   0.864    0.846    0.759 
# Kendall von Hand: konkordante gegen diskordante Paare
paare <- expand.grid(i = seq_along(zufrieden), j = seq_along(zufrieden))
paare <- paare[paare$i < paare$j, ]
richtung <- sign(zufrieden[paare$i] - zufrieden[paare$j]) *
  sign(empfehlen[paare$i] - empfehlen[paare$j])
c(konkordant = sum(richtung > 0), diskordant = sum(richtung < 0),
  bindungen = sum(richtung == 0), paare = nrow(paare))
konkordant diskordant  bindungen      paare 
       125          7         58        190 
zufrieden = np.array([5, 4, 4, 5, 3, 2, 1, 3, 4, 5, 2, 3, 5, 4, 1, 2, 3, 4, 5, 3])
empfehlen = np.array([5, 5, 4, 4, 3, 2, 1, 4, 4, 5, 1, 3, 5, 3, 2, 2, 4, 5, 4, 3])

print(pd.crosstab(zufrieden, empfehlen))
col_0  1  2  3  4  5
row_0               
1      1  1  0  0  0
2      1  2  0  0  0
3      0  0  3  2  0
4      0  0  1  2  2
5      0  0  0  2  3
print({"pearson": round(float(np.corrcoef(zufrieden, empfehlen)[0, 1]), 3),
       "spearman": round(float(stats.spearmanr(zufrieden, empfehlen).statistic), 3),
       "kendall": round(float(stats.kendalltau(zufrieden, empfehlen).statistic), 3)})
{'pearson': 0.864, 'spearman': 0.846, 'kendall': 0.759}
konkordant = diskordant = bindungen = 0
for i in range(len(zufrieden)):
    for j in range(i + 1, len(zufrieden)):
        richtung = (np.sign(zufrieden[i] - zufrieden[j])
                    * np.sign(empfehlen[i] - empfehlen[j]))
        if richtung > 0:
            konkordant += 1
        elif richtung < 0:
            diskordant += 1
        else:
            bindungen += 1

print({"konkordant": konkordant, "diskordant": diskordant,
       "bindungen": bindungen,
       "paare": len(zufrieden) * (len(zufrieden) - 1) // 2})
{'konkordant': 125, 'diskordant': 7, 'bindungen': 58, 'paare': 190}

Output Zeile für Zeile

Zwanzig Befragte, beide Merkmale auf einer Skala von 1 bis 5.

Mass Wert Zulässig?
Pearson 0.864 nein, er setzt voraus, dass der Abstand von 1 zu 2 dasselbe bedeutet wie der von 4 zu 5
Spearman 0.846 ja
Kendall 0.759 ja, und hier die bessere Wahl

Die Aufteilung der 190 Paare in konkordante, diskordante und Bindungen zeigt, warum:

Kategorie Anzahl Bedeutung
konkordant 125 Beide Merkmale zeigen in dieselbe Richtung: Wer zufriedener ist, empfiehlt auch eher.
diskordant 7 Gegenläufig.
Bindungen 58 Mindestens eines der beiden Merkmale ist bei beiden Befragten gleich.
Summe 190 alle Paare aus 20 Befragten

Ohne Bindungen wäre der Wert (125 - 7) / 190 = 0.621. Die Voreinstellung \(\tau_b\) rechnet die Bindungen aus dem Nenner heraus und kommt deshalb auf 0.759.

Beobachtung Deutung
Es gibt 58 Bindungen von 190 Paaren Also fast ein Drittel. Bei einer Skala mit fünf Stufen und zwanzig Befragten ist das unvermeidlich: Jeder Wert kommt mehrfach vor.
Genau deshalb ist Kendall besser geeignet Seine Varianten \(\tau_b\) und \(\tau_c\) behandeln Bindungen ausdrücklich; Spearman rechnet mit gemittelten Rängen und wird bei vielen Bindungen unzuverlässig. R und scipy verwenden voreingestellt \(\tau_b\).
Kendall liegt mit 0.759 unter Spearman mit 0.846 Der übliche Fall. Die beiden messen nicht dasselbe auf verschiedenen Skalen, sondern verschiedene Dinge, ein direkter Vergleich der Zahlen ist nicht sinnvoll.
\((\tau + 1)/2\) Hier 0.88: der Anteil gleichgerichteter Paare. Das ist die einzige der drei Kennzahlen mit einer unmittelbaren Wahrscheinlichkeitsdeutung.

Die Entscheidungsregel in vier Zeilen:

Situation Mass
beide metrisch, Streudiagramm zeigt eine Gerade Pearson
beide metrisch, Zusammenhang monoton aber krumm Spearman
mindestens eines ordinal, wenige Stufen, viele Bindungen Kendall
Zusammenhang nicht monoton (U-Form) keines, transformieren oder ein Modell

Interpretation

Die Reihenfolge ist immer dieselbe: erst Skalenniveau, dann Streudiagramm, dann Kennzahl. Wer mit der Kennzahl anfängt, wählt sie nach Gewohnheit statt nach Passung.

Frage und Datenlage

Der klassische Fall: Glaceverkauf und Badeunfälle. Beide werden von der Temperatur getrieben, haben aber miteinander nichts zu tun. Was zeigt die Korrelation, und wie macht man den Schein sichtbar?

Rechnung

temperatur <- 5 + 25 * lehmer(6615, 200)
glace <- 20 + 3 * temperatur + normalwerte(6616, 200, 0, 10)
badeunfaelle <- 2 + 0.4 * temperatur + normalwerte(6617, 200, 0, 2)

rest_glace <- resid(lm(glace ~ temperatur))
rest_unfaelle <- resid(lm(badeunfaelle ~ temperatur))

par(mfrow = c(1, 2), mar = c(4, 4, 2.5, 1))
plot(glace, badeunfaelle, pch = 16, cex = 0.6, col = "grey30",
     xlab = "Glaceverkauf", ylab = "Badeunfälle", main = "roh")
plot(rest_glace, rest_unfaelle, pch = 16, cex = 0.6, col = "grey30",
     xlab = "Glace, Rest", ylab = "Unfälle, Rest",
     main = "Temperatur herausgerechnet")
par(mfrow = c(1, 1))

round(c(
  glace_unfaelle = cor(glace, badeunfaelle),
  glace_temperatur = cor(glace, temperatur),
  unfaelle_temperatur = cor(badeunfaelle, temperatur),
  partiell = cor(rest_glace, rest_unfaelle)
), 3)
     glace_unfaelle    glace_temperatur unfaelle_temperatur            partiell 
              0.767               0.900               0.829               0.085 
Abbildung 7: Beispiel 5: links der scheinbare Zusammenhang, rechts derselbe nach Herausrechnen der Temperatur.
temperatur = 5 + 25 * lehmer(6615, 200)
glace = 20 + 3 * temperatur + normalwerte(6616, 200, 0, 10)
badeunfaelle = 2 + 0.4 * temperatur + normalwerte(6617, 200, 0, 2)

X = sm.add_constant(temperatur)
rest_glace = sm.OLS(glace, X).fit().resid
rest_unfaelle = sm.OLS(badeunfaelle, X).fit().resid

fig, achsen = plt.subplots(1, 2, figsize=(7, 3.2))
achsen[0].scatter(glace, badeunfaelle, s=10, color="0.3")
achsen[0].set_xlabel("Glaceverkauf")
achsen[0].set_ylabel("Badeunfälle")
achsen[0].set_title("roh")
achsen[1].scatter(rest_glace, rest_unfaelle, s=10, color="0.3")
achsen[1].set_xlabel("Glace, Rest")
achsen[1].set_ylabel("Unfälle, Rest")
achsen[1].set_title("Temperatur herausgerechnet")
plt.tight_layout()
plt.show()
Abbildung 8: Beispiel 5: dieselbe Gegenüberstellung in Python.
print({
    "glace_unfaelle": round(float(np.corrcoef(glace, badeunfaelle)[0, 1]), 3),
    "glace_temperatur": round(float(np.corrcoef(glace, temperatur)[0, 1]), 3),
    "unfaelle_temperatur": round(float(np.corrcoef(badeunfaelle,
                                                   temperatur)[0, 1]), 3),
    "partiell": round(float(np.corrcoef(rest_glace, rest_unfaelle)[0, 1]), 3),
})
{'glace_unfaelle': 0.767, 'glace_temperatur': 0.9, 'unfaelle_temperatur': 0.829, 'partiell': 0.085}

Output Zeile für Zeile

Paar \(r\) Deutung
Glace, Badeunfälle 0.767 Ein starker Zusammenhang, der jede Schwelle überschreitet.
Glace, Temperatur 0.900 Die gemeinsame Ursache, erste Hälfte.
Badeunfälle, Temperatur 0.829 Die gemeinsame Ursache, zweite Hälfte.
partiell, Temperatur herausgerechnet 0.085 Nichts bleibt übrig.
Beobachtung Erklärung
0.767 ist keine Fehlrechnung Der Zusammenhang existiert in den Daten. Was nicht existiert, ist eine Wirkung des einen auf das andere.
Warum 0.767 herauskommt Ungefähr das Produkt der beiden Einzelkorrelationen: \(0.900 \cdot 0.829 = 0.746\). Bei einer reinen gemeinsamen Ursache ist das genau die Erwartung.
Die partielle Korrelation Man rechnet die Temperatur aus beiden Merkmalen heraus (über eine Regression) und korreliert die Reste. Bleibt dort nichts übrig, war der Zusammenhang vollständig durch die dritte Grösse erklärt.
0.085 statt exakt 0 Stichprobenzufall bei n = 200.
Das rechte Streudiagramm zeigt eine strukturlose Wolke gegenüber der klaren Steigung links.

Was dieses Beispiel nicht zeigt: wie man die dritte Grösse findet. Hier war sie bekannt, weil die Daten so konstruiert wurden. In echten Daten ist genau das die Schwierigkeit, eine nicht erhobene gemeinsame Ursache bleibt unsichtbar, und keine Rechnung kann sie aufdecken.

Was hilft, ist Fachwissen und ein Erhebungsdesign, das die Kandidaten mitmisst. Systematisch behandelt wird das unter multipler Regression, technisch ist die partielle Korrelation oben genau ein Schritt davon.

Die drei möglichen Erklärungen für jede beobachtete Korrelation bleiben:

Erklärung Beispiel hier
\(x\) wirkt auf \(y\) Glace verursacht Unfälle, inhaltlich absurd
\(y\) wirkt auf \(x\) Unfälle treiben den Glacekonsum, ebenso
dritte Grösse treibt beide Temperatur, das ist es

Die Daten allein unterscheiden nicht zwischen ihnen.

Interpretation und Ergebnissatz

Glaceverkauf und Badeunfälle korrelieren mit \(r\) = 0.77 (n = 200). Der Zusammenhang geht vollständig auf die Aussentemperatur zurück: Wird sie aus beiden Merkmalen herausgerechnet, bleibt eine partielle Korrelation von 0.09.

Verständnisfragen

Die Korrelation zwischen zwei Merkmalen beträgt 0.02. Haben sie nichts miteinander zu tun?

Ja, der Wert liegt praktisch bei null
Ausgeschlossen ist damit nur ein linearer Zusammenhang.
Nicht unbedingt, ein U-förmiger Zusammenhang ergibt ebenfalls fast null
Richtig. Pearson misst nur den linearen Anteil. In Beispiel 3 liefert ein deterministischer U-Zusammenhang r = -0.015, während die Korrelation mit dem Betrag von x bei 0.94 liegt.
Der Wert ist zu klein zum Interpretieren
Interpretieren lässt er sich gut, man muss nur wissen, was er misst.

Warum ändert sich die Korrelation nicht, wenn eine Variable von Liter auf Milliliter umgerechnet wird, die Kovarianz aber schon?

Weil im Nenner die Standardabweichungen stehen, die um denselben Faktor wachsen
Richtig. Der Faktor 1000 kürzt sich heraus. Genau das ist der Zweck der Normierung.
Weil die Korrelation gerundet wird
Mit Rundung hat es nichts zu tun.
Weil Milliliter und Liter dieselbe Einheit sind
Sie unterscheiden sich um den Faktor 1000, und die Kovarianz zeigt das auch.

Ein einzelner Punkt kommt zu zwanzig anderen dazu, und die Pearson-Korrelation springt von +0.98 auf -0.11. Was folgt daraus?

Pearson ist nicht robust; ein Hebelpunkt kann das Vorzeichen umkehren
Richtig. Der Punkt liegt weit ausserhalb des x-Bereichs und zieht die gedachte Gerade mit sich. Die Rangkorrelation fällt im selben Beispiel nur auf 0.71, weil sie den Punkt als eine Beobachtung unter vielen zählt.
Die Daten wurden falsch erhoben
Möglich, folgt aber nicht daraus. Ein extremer Wert kann echt sein.
Die Stichprobe ist zu klein
Bei grösserem n wäre die Wirkung kleiner, aber das Problem bleibt dasselbe.

Zwei ordinale Merkmale mit je fünf Stufen sollen verglichen werden, n = 20. Was spricht für Kendall statt Spearman?

Bei wenigen Stufen und vielen Bindungen ist Kendall zuverlässiger
Richtig. Seine Varianten behandeln Bindungen ausdrücklich, während Spearman mit gemittelten Rängen rechnet. Zusätzlich hat Kendall eine unmittelbare Deutung als Anteil gleichgerichteter Paare.
Kendall liefert grössere Werte
Er liefert typisch kleinere, weil er etwas anderes misst.
Spearman ist für ordinale Daten nicht zulässig
Er ist zulässig, nur bei vielen Bindungen weniger geeignet.

Glaceverkauf und Badeunfälle korrelieren mit 0.77. Nach Herausrechnen der Temperatur bleibt 0.09. Was ist damit gezeigt?

Der Zusammenhang lässt sich vollständig durch die gemeinsame Ursache erklären
Richtig. Das ist die partielle Korrelation: Die Temperatur wird aus beiden Merkmalen herausgerechnet, und aus den Resten bleibt nichts.
Glace verursacht keine Badeunfälle
Das ist die richtige inhaltliche Schlussfolgerung, aber sie folgt aus dem Sachverstand, nicht aus der Rechnung. Die Rechnung zeigt nur, dass die Temperatur genügt.
Die ursprüngliche Korrelation war falsch berechnet
Sie war korrekt. Der Zusammenhang existiert in den Daten, nur nicht als Wirkung.

Ein Bericht nennt \(r\) = 0.5 und beschreibt den Zusammenhang als “halb so stark wie ein perfekter”. Was ist daran falsch?

Geteilt wird die Streuung, und \(r^2\) = 0.25 heisst 25 Prozent gemeinsame Streuung
Richtig. Drei Viertel der Streuung kommen anderswo her. Die Skala von r ist nicht linear in dem, was man umgangssprachlich unter “Stärke” versteht.
Nichts, 0.5 ist die Hälfte von 1
Rechnerisch ja, inhaltlich führt es in die Irre.
r kann nicht als Stärke gedeutet werden
Es kann, nur nicht linear.

Verlinkte Ressourcen