Eine typische Frage von Studierenden

Vor kurzem fand ich mal wieder eine Anfrage einer Studierenden in meinem Email Postfach. Die Frage lautete in etwa wie folgt:

Guten Tag Herr Markgraf,

ich würde gerne die Hypothese untersuchen: Die reduzierte Abhängigkeit des Iphones tagsüber liegt am schönen Wetter. Dazu habe ich eine Variable “iphones.tagsüber.unbeachtet” mit 1x, 2x und 3x täglich als Ausprägungen und eine andere Variable “wetter.ist.gut”, die als Ausprägung “Ja” und “Nein” hat. Welchen Test kann ich dazu zur Überprüfung einer Abhängigkeit nehmen?

Vielen Dank im Voraus.

MfG Monika Mustermann

Natürlich ist diese Frage im Prinzip einfach zu beantworten, sogar von Leuten, die Statistik an einer Hochschule gehört haben. – Aber da ich ja auch sonst nichts zu tun habe, gebe ich gerne statistische Hilfestellung für Studierende. Sicher, ich verdiene damit eigentlich mein Geld. Also ist es nur natürlich, dass ich so etwas vollkommen unentgeldlich mache. Und wieso sollten Studierende einfach mal ein Buch in die Hand nehmen und selber nachdenken? Es gibt vermutlich keine Bücher zu diesem Thema, denn es ist ganz sicher eine Geheimwissenschaft. Und wieso sollte man dann also seine Betreuungsperson zu diesem Probem fragen? Die hat ja auch so viel zu tun… – Egal.

Was haben wir hier vorliegen? – Im einfachsten Fall sind es zwei kategoriale Variablen, und wir wollen sehen ob diese von einander (un-)abhängig sind.

Mangels tatsächlicher Daten basteln wir uns einfach mal ein Beispiel:

Wir bastlen uns ein Beispiel

# Wie immer zuerst das Paket 'mosaic' laden
library(mosaic)

# Einen beliebigen Startwert für den Zufallszahlengenerator
# für die Reproduzierbarkeit
set.seed(123)

# Anzahl der Vorfälle insgesamt
n <- 176

# Anzahl der Wiederholungen für die SBI-Methoden
loops <- 10000

# Erfinden eines Beispieldatensatzes
daten <- data.frame(
  iphones.tagsüber.unbeachtet = sample(rep(c("1xtäglich","2xtäglich","3xtäglich"),n),n),
  wetter.ist.gut = sample(rep(c("Ja","Nein"),n),n)
)

# Ausgabe der ersten Zeilen des Datensatzes
head(daten)
##   iphones.tagsüber.unbeachtet wetter.ist.gut
## 1                   1xtäglich             Ja
## 2                   1xtäglich           Nein
## 3                   2xtäglich             Ja
## 4                   3xtäglich           Nein
## 5                   1xtäglich             Ja
## 6                   2xtäglich             Ja

Ein Blick auf Kennzahlen und Visualisierungsmöglichkeiten

Man kann diese Daten als Kreuztabelle zusammenfassen und diese dann mit Hilfe eines Mosaikplots darstellen:

tally(iphones.tagsüber.unbeachtet ~ wetter.ist.gut, data = daten)
##                            wetter.ist.gut
## iphones.tagsüber.unbeachtet Ja Nein
##                   1xtäglich 29   33
##                   2xtäglich 34   26
##                   3xtäglich 27   27
mosaicplot(wetter.ist.gut ~ iphones.tagsüber.unbeachtet, data = daten)

# Für später speichern wir die Kreuztabelle in obs.tab
obs.tab <- tally(iphones.tagsüber.unbeachtet ~ wetter.ist.gut, data = daten)

Von der Forschungsthese zur Hypothese

Um nun zwischen abhängig und unabhängig statistisch zu unterscheiden, sollte man sich die Null- und Alternativhypothese genau überlegen und operationalisieren.

Ein Blick auf die (orginale) Forschungsthese: “Die reduzierte Abhängigkeit des Iphones tagsüber liegt am schönen Wetter.”

Oh je, eine kausale Forschungsthese. Ein dezenter Hinweis auf das Werk von Judea Pearl und Dana Mackenzie “The Book of Why!” muss an dieser Stelle sein. – Aber da wir keine kausale Modellierung machen wollen, müssen wir das Problem sinngetreu umformulieren:

“Es besteht ein Zusammenhang zwischen ‘schönem Wetter’ und dem ‘Iphone tagsüber unbeachtet’ lassen.”

Warum diese neue Formulierung? – Nun, in der orginal Forschungsthese wird ein kausal Zusammenhang geprüft. Da es sich vermutlich um eine Beobachtungstudie handelt können wir einen solchen Ursache-Wirkungs-Zusammenhang aber hier nicht so einfach prüfen. Wie das gehen könnte, dazu schaut man mal bei J.Pearl und D.Mackenzie (s.o.) nach. Zwar kann man von außen sagen: “Wenn es einen Zusammenhang gibt, dann führt das schöne Wetter zur Nichtbeachtung.” mit klassischer Statistik können wir hier aber nur den Zusammenhang (und zwar ungerichtet!) testen. Liegt dieser nicht vor, so spricht erstmal auch nichts für einen kausalen Zusammenhang, aber ein Zusammenhang an sich spricht noch nicht für einen kausalen Zusammenhang! (Korrelation ist ebeb nicht Kausalität!)

Aus der umformulierten Forschungsfrage können wir die Alternativ- und auch die Nullhypothese ableiten:

Alternativhypothese: Es besteht ein Zusammenhang zwischen ‘schönem Wetter’ und dem ‘Iphone tagsüber unbeachtet’ lassen.

Nullhypothese: Es besteht kein Zusammenhang zwischen ‘schönem Wetter’ und dem ‘Iphone tagsüber unbeachtet’ lassen.

Wie kann man nun den Zusammenhang messen und wie sieht kein Zusammenhang dabei aus?

Um zu sehen ob unsere Werte keinen Zusammenhang haben, also rein zufällig sind, oder es einen inneren Zusammenhang gibt müssen wir die äußeren von den inneren Häufigkeiten trennen.

Konkret heißt das, wir schauen uns an wie die Häufigkeiten oder auch Verteilung der einzelnen Variabeln ausssehen:

tally(~ wetter.ist.gut, data = daten)
## wetter.ist.gut
##   Ja Nein 
##   90   86
tally(~ iphones.tagsüber.unbeachtet, data = daten)
## iphones.tagsüber.unbeachtet
## 1xtäglich 2xtäglich 3xtäglich 
##        62        60        54

Freiheitsgrade

Die Werte innerhalb der Kreuztabelle oben werden im wesendlichen durch diese Werte bestimmt. Die außeren Werte sind also unsere Rahmenbedingungen. Dabei ist der Einfluss der sogenannten Randhäufigkeiten (Marginale Häufigkeit) nicht zu unterschätzen. Denn wenn wir diese als fix/gegeben ansehen, können wir nur mit den sechs Werten in der Mitte unserer Kreuztabelle spielen.

Doch sind nicht alle sechs Werte wirklich frei wählbar. Denn um zum Beispiel die Summe 62 in der ersten Zeile zu erhalten haben wir ja die Summe von 29 und 33 gebildet.

Ist nun der Rand, also 62, fest, so kann ich nicht beide Summanden frei wählen, denn

\[62 = 29 + 33\]

impliziert ja, dass allgemein

\[62 = x + y\] gelten muss und somit durch

\[x = 62 - y \qquad\text{ bzw. }\qquad y = 62 - x\] immer maximal eine der Variabeln – \(x\) oder \(y\) – wirklich frei wählen kann.

Da dies für jede Zeile, aber auch für jede Spalte gilt, denn z.B. ist die Summe der ersten Spalte gegeben durch

\[90 = 29 + 34 + 27,\] sind von den sechs Werten in der Kreuztabelle in der Tat nur 2 Werte wirklich frei zu wählen. Wir haben also ein Problem mit 2 Freiheitsgraden, man schreibt das kurz mit \(df=2\) (df steht dabei für degree of freedom).

Unabhängigkeit in der Statistik

Wir sagen, in der Statistik, dass ein gemeinsames Ereignis unabhängig ist wenn sich das Ereignis als Produkt der beiden Einzelereignisse berechnen lässt. Seien \(A\) und \(B\) also zwei Ereignisse, dann gilt im Falle der Unabhängigkeit:

\[P(A \cap B) = P(A) \cdot P(B)\] Oder etwas informeller: Die Wahrscheinlichkeit das beide Ereignisse eintreffen ist das Produkt der Wahrscheinlichkeiten, dass jeweils eines der beiden Ereignisse eintrifft.

Wir können diese Definition aus der Wahrscheinlichkeitstheorie an unser Problem adaptieren, in dem wir die Wahrscheinlichkeiten durch die relativen Häufigkeiten ersetzen.

Der Wert für das gemeinsame Ereignis iphone.tagsüber.unbeachtet = 1xtäglich und das wetter.ist.gut=ja wird im Falle der Unabhägigkeit durch die beiden Randhäufigkeiten bestimmt:

\[62 \cdot 90 = 31.7045455\]

Wir können nun mit eine Kreuztabelle erstellen, wie sie seien müsste, falls wir tatsächlich statitische Unabhängigkeit hätten. Wir nutzen dafür eine sehr allgemein gehaltene, aber selbst programmierte, Funktion expectation.tab(), der wir eine Tabelle mit den Häufigkeiten der Beobachtungen geben und die uns dann die Tabelle liefert, wie sie aussehen würde, falls tatsächlich statitische Unabhängigkeit herrschen würde.

Die Tabelle mit den beobchteten Werten speichern wir in obs.tab, die der erwarteten Werte in exp.tab:

expectation.tab <- function(tab.obs) {
  ret <- tab.obs
  max.i <- dim(tab.obs)[1]
  max.j <- dim(tab.obs)[2]
  
  # Randhäufigkeiten 
  x <- rep(0, max.i)
  for (i in 0:max.i) x[i] = sum(tab.obs[i,])

  y <- rep(0, max.j)
  for (j in 0:max.j) y[j] = sum(tab.obs[,j])

  # Anzahl aller Beobachtungen
  n = sum(tab.obs)
  
  for (i in 0:max.i) {
    for (j in 0:max.j) {
       ret[i,j] <- (x[i] * y[j] / n)
    }
  }

  ret
}

# Kreuztabelle der beobachtete Werte
obs.tab <- tally(iphones.tagsüber.unbeachtet ~ wetter.ist.gut, data = daten)

# Kreuztabelle der erwarteten Werte auf Grundlage der beobachteten Werte
exp.tab <- expectation.tab(obs.tab)

Schauen wir uns die beiden Tabellen kurz an. Zuerst die der beobachteten Werte:

obs.tab
##                            wetter.ist.gut
## iphones.tagsüber.unbeachtet Ja Nein
##                   1xtäglich 29   33
##                   2xtäglich 34   26
##                   3xtäglich 27   27

Dann die der erwarteten Werte:

exp.tab
##                            wetter.ist.gut
## iphones.tagsüber.unbeachtet       Ja     Nein
##                   1xtäglich 31.70455 30.29545
##                   2xtäglich 30.68182 29.31818
##                   3xtäglich 27.61364 26.38636

Was können wir nun messen?

Unsicherheit und Zufall spielen eine große Rolle. Wir können also nicht erwarten, dass die Werte für die Kreuztabelle in der Realität genau getroffen werden. (Vorallem, weil wir hier ja mit Nachkommastellen arbeiten!) Aber wir können versuchen den Abstand zu diesen Werten zu messen. Je weiter weg die Werte in der Kreuztabelle von den theoretischen Werten liegen, um so unwarscheinlicher ist es, dass die Werte zufällig aus einer unabhängigen Population gezogen wurden. D.h. wir könnten uns für eine Abhägigkeit aussprechen.

Messen mit dem Absolutabstand?

Man könnte nun auf die Idee kommen die Abstände an jeder Stelle zu messen und den absoluten Abstand zu summieren:

sum(abs(obs.tab - exp.tab))
## [1] 13.27273

Nur was sagt dieser Wert aus? – Ist das ein kleiner Abstand oder ein großer?

Wir brauchen Referenzwerte zur Orientierung. Eine Idee lautet: Permutationstest

Sind die Werte unabhängig von einander, dann spielt die konkrete Zuordnung keine Rolle, sondern nur die Anzahl der Ereignisse an sich. Ordnen wir nun zufällig einem iphones.tagsüber.unbeachtet-Wert einen beliebigen wetter.ist.gut-Wert zu, dann besteht kein Zusammenhang mehr zwischen den Werten. Dies machen wir mittels iphones.tagsüber.unbeachtet ~ shuffle(wetter.ist.gut).

Wir simulieren so den Zustand, dass es keine Abhängigkeit zwischen den Werten gibt.

Dabei messen wir den Abstand zwischen den Abstand zwischen den beobachteten Werten und den Werten, die wir erwarten würden, falls Unabhägigkeit vorliegen würde. Dafür nutzen wir die selbsterstellte Funktioen diffabsobsexp, welche die Summe der absoluten Abweichungen berechnet:

\[\text{diffabsobsexp}(obs, exp) = \sum\limits_i \left|obs_i - exp_i\right|\]

Wir Wiederholen das ganze mit Hilfe von do(loops) genau loops\(=10^{4}\) mal, geben dann das Histogramm aus und tragen als rote Linie den Wert ein, die wir bei unseren beobachteten Daten tatsächliche gemessen haben:

# Funktion zur Berechnung der absoluten Differenz zwischen
# beobachteten und erwarteten Werte
diffabsobsexp <- function(obs, exp) {
  sum(abs(obs - exp))
}

# Absolute Abweichung der gemessenen Werte
obs.abs <- diffabsobsexp(obs.tab, exp.tab)

# Erzeugen der Nullverteilung
NullVert  <- do(loops) * diffabsobsexp(tally(iphones.tagsüber.unbeachtet ~ shuffle(wetter.ist.gut), data = daten), exp.tab)
gf_histogram(~ diffabsobsexp, data = NullVert) %>%
  gf_vline(xintercept = ~ obs.abs, color = "red")

Wir können nun den p-Wert, also die relative Fläche rechts von der roten Linie in unseren Histogramm, abschätzen mit:

prop( ~ diffabsobsexp >= obs.abs, data = NullVert)
## prop_TRUE 
##    0.5714

Absolute Abweichungen (oder auch absolute Fehler) haben die Tendenz bei großen Zahlen auch große Abweichungswerte zu liefern und bei kleinen Werten eher kleine Abweichungswerte. Das kann man als Markel ansehen. Daher arbeitet man vielleicht lieber mit relativen Abweichungen (oder auch relativen Fehlern). Dabei setzt man die absolute Abweichung jedesmal in Bezug auf den erwarteten Wert. Die dazu passenden Funktion haben wir unten mit diffabsobsexprel implementiert. Dabei ist:

\[\text{diffabsobsexprel}(obs, exp) = \sum\limits_i \frac{\left|obs_i - exp_i\right|}{exp_i}\]

Wir Wiederholen das ganze mit Hilfe von do(loops) genau loops\(=10^{4}\) mal, geben dann das Histogramm aus und tragen als rote Linie den Wert ein, den wir bei unseren beobachteten Daten tatsächliche gemessen haben:

# Funktion zur Berechnung der korrigierten absoluten 
# Differenz zwischen beobachteten und erwarteten Werten
diffabsobsexprel <- function(obs, exp) {
  sum((abs(obs - exp))/exp)
}

# Absolute Abweichung der gemessenen Werte -- korrigiert
obs.abs <- diffabsobsexprel(obs.tab, exp.tab)

# Erzeugen der Nullverteilung
NullVert  <- do(loops) * diffabsobsexprel(tally(iphones.tagsüber.unbeachtet ~ shuffle(wetter.ist.gut), data = daten), exp.tab)
gf_dhistogram(~ diffabsobsexprel, data = NullVert) %>%
  gf_vline(xintercept = ~ obs.abs, color = "red")

Auch hier können wir den p-Wert abschätzen:

prop( ~ diffabsobsexprel >= obs.abs, data = NullVert)
## prop_TRUE 
##    0.5983

Ist der absolute Abstand überhaupt gut gewählt? – Wäre nicht eher der quadratische Abstand angebracht?

Ein Vorteil des quadratischen Abstand ist es, dass er kleine Abstände kleiner und große Abstände größer bewertet, als der absolute Abstand. Außerdem hat er mathematisch einige Vorteile. Wir messen nun den quadratischen Abstande mit der Funktion diffquad, die wie folgt arbeitet:

\[\text{diffquad}(obs, exp) = \sum\limits_i \left(obs_i - exp_i\right)^2\]

Wir Wiederholen dies nun mit Hilfe von do(loops) genau loops\(=10^{4}\) mal, geben dann das Histogramm aus und tragen als rote Linie den Wert ein, den wir bei unseren beobachteten Daten tatsächliche gemessen haben:

# Funktion zur Berechnung der quadratischen 
# Differenz zwischen beobachteten und erwarteten Werten
diffquad <- function(obs, exp) {
  sum((obs - exp)^2)
}

# Quadratische Abweichung der gemessenen Werte
obs.abs <- diffquad(obs.tab, exp.tab)

# Erzeugen der Nullverteilung
NullVert  <- do(loops) * diffquad(tally(iphones.tagsüber.unbeachtet ~ shuffle(wetter.ist.gut), data = daten), exp.tab)
gf_dhistogram(~ diffquad, data = NullVert) %>%
  gf_vline(xintercept = ~ obs.abs, color = "red")

Wir können nun den p-Wert abschätzen mit:

prop( ~ diffquad >= obs.abs, data = NullVert)
## prop_TRUE 
##    0.5389

Wie beim absoluten Abstand werden hier die Größe der Werte ausser acht gelassen und vielleicht fühlen wir uns etwas wohler, wenn wir statt des quadratischen Abstands den relativen quadratischen Abstand benutzen:

\[\text{diffquadrel}(obs, exp) = \sum\limits_i \frac{\left(obs_i - exp_i\right)^2}{exp_i}\]

Dies wiederholen wir nun mit Hilfe von do(loops) genau loops\(=10^{4}\) mal, geben dann das Histogramm aus und tragen als rote Linie den Wert ein, den wir bei unseren beobachteten Daten tatsächliche gemessen haben:

# Funktion zur Berechnung der korrigierten quadratischen 
# Differenz zwischen beobachteten und erwarteten Werten
diffquadrel <- function(obs, exp) {
  sum(((obs - exp)^2)/exp)
}

# Quadratische Abweichung der gemessenen Werte -- korrigiert
obs.abs <- diffquadrel(obs.tab, exp.tab)

# Erzeugen der Nullverteilung
NullVert  <- do(loops) * diffquadrel(tally(iphones.tagsüber.unbeachtet ~ shuffle(wetter.ist.gut), data = daten), exp.tab)
gf_histogram(~ diffquadrel, binwidth = 0.5, center = 0.25, data = NullVert) %>%
  gf_vline(xintercept = ~ obs.abs, color = "red")

Den Wert 1.2344597, den wir mit Hilfe der relativen quadratischen Abweichung berechnet haben, nennen wir auch \(\chi^2\) Wert.

Wir können nun den p-Wert abschätzen mit:

prop( ~ diffquadrel >= obs.abs, data = NullVert)
## prop_TRUE 
##    0.5599

An Hand der p-Werte können wir nun über die Nullhypothese entscheiden:

Was sagt die klassische Statistik?

In der klassischen Statistik könnte man hier den \(\chi^2\)-Unabhängigkeitstest anwenden:

xchisq.test(iphones.tagsüber.unbeachtet ~ wetter.ist.gut, data = daten)
## 
##  Pearson's Chi-squared test
## 
## data:  x
## X-squared = 1.2345, df = 2, p-value = 0.5394
## 
##    29       33   
## (31.70)  (30.30) 
## [0.231]  [0.241] 
## <-0.48>  < 0.49> 
##    
##    34       26   
## (30.68)  (29.32) 
## [0.359]  [0.376] 
## < 0.60>  <-0.61> 
##    
##    27       27   
## (27.61)  (26.39) 
## [0.014]  [0.014] 
## <-0.12>  < 0.12> 
##    
## key:
##  observed
##  (expected)
##  [contribution to X-squared]
##  <Pearson residual>

Vergleichen wir nun die beiden Ansätze, SBI auf der einen und der klassische Ansatz auf der anderern Seite, einmal in einem Diagramm. Das (Dichte-)Histogramm sind die Daten aus der Nullverteilung für die quadratische, korrigierte Differenz. Die rote Linie ist der gemessene Abweichungswert. Die schwarze Linie ist der Graph der \(\chi^2\)-Verteilung mit zwei Freiheitsgraden:

gf_dhistogram(~ diffquadrel, binwidth = 0.5, center = 0.25, data = NullVert) %>%
  gf_fun(dchisq(x, df=2) ~ x, xlim = c(0:20), color = "blue") %>% 
  gf_vline(xintercept = ~ obs.abs, color = "red")

Aber es gibt auch den (exakten) Fisher-Test:

fisher.test(obs.tab, alternative = "greater")
## 
##  Fisher's Exact Test for Count Data
## 
## data:  obs.tab
## p-value = 0.5609
## alternative hypothesis: greater

Fazit

Wir können die p-Werte der einzelnen Tests nun gegenüber stellen:

## Scale for 'y' is already present. Adding another scale for 'y', which will
## replace the existing scale.

Gewöhnlich haben wir ein Signifikanznivau von \(5\% = 0{,}05\) angenommen. Die rote Linie zeigt diese Grenze. Liegt der Balken links vor dieser Linie, so sprechen wir davon, dass der gemessene Wert selten bei unabhänigen Daten vorliegt und würden uns gegen die Nullhypothese und damit quasi für die Alternativhypothese entscheiden. Liegt der Balken recht der roten Linie, so haben wir übliche Werte für unabhängige Daten und keinen Grund gefunden, der gegen die Nullhypothese spricht. Warum wir sie dann, auf Grundlage unserer Daten, auch nicht ablehnen können.

Bleibt Sie Frage, gibt es Situationen in denen die Entscheidung über die Nullhypothese bei den einzelen betrachteten Verfahren unterschiedlichen ist? Und wenn ja, wann und wieoft?

Diese Fragen sind nicht Thema dieses Beitrags, aber vielleicht habe ich Zeit und betrachte das später einmal.

Norman Markgraf
Norman Markgraf
Diplom-Mathematiker

Norman Markgraf ist freiberuflicher Dozent für Mathematik, Statistik, Data Science und Informatik, sowie freiberuflicher Programmierer.

Ähnliches