Schil · Kruistabel en χ²

Samenhang tussen twee categorische variabelen · contingency table & chi-square

De prikkel

In de nacht van 14 op 15 april 1912 vaart het grootste schip ter wereld tegen een ijsberg. Het water is twee graden koud. Er zijn 2201 mensen aan boord; als de ochtend komt, leven er nog 711.1 Van elke opvarende zijn later twee dingen genoteerd, meer niet: in welke klasse hij of zij reisde — eerste, tweede, derde, of bemanning — en of hij of zij het overleefde. Twee kolommetjes tekst. Elke rij was iemand.

En nu wij. Want tel je die twee kolommetjes tegen elkaar af, dan rolt er iets uit dat je even stil maakt. In de eerste klasse overleefde 62%. In de derde klasse 25%. Bij de bemanning 24%. Dezelfde ijsberg, hetzelfde water — en toch zulke andere kansen. De vraag jeukt meteen: had je plek op dat schip iets te maken met je plek in die reddingsboot? Of kan zo’n verschil ook gewoon… toeval zijn, het soort scheefheid dat elke telling nu eenmaal heeft?

Trek even mee. We gaan het zelf natellen — en onderweg leer je het gereedschap dat precies voor deze vraag is gemaakt.

Speel het

⬇ Download de data — titanic.csv

Geen stippenwolk deze keer: beide variabelen zijn categorieën, dus we tellen. Het huis waar getelde categorieën wonen heet de kruistabel (contingency table): klassen als rijen, overleefd ja/nee als kolommen, en in elke cel hoeveel mensen daar zitten.

OpmerkingIn R · trek eraan
tit <- read.csv("titanic.csv")

t <- table(tit$klasse, tit$overleefd)    # de kruistabel: 4 rijen x 2 kolommen
t
round(prop.table(t, 1) * 100)            # rijpercentages: wie overleefde, per klasse

chisq.test(t)                            # → X-squared = 190.4, df = 3, p < .001

Daar staat de tabel: 203 van de 325 eersteklassers overleefden, 212 van de 885 bemanningsleden. En daaronder één getal voor de héle tabel: χ² = 190.4 (spreek uit: chi-kwadraat, chi-square). Wat dat getal doet: het vergelijkt elke cel met de saaiste tabel denkbaar — de tabel die je zou krijgen als klasse en overleven níéts met elkaar te maken hadden en elke klasse gewoon het scheepsbrede 32% zou volgen. Onder die saaie tabel zouden er in de eerste klasse zo’n 105 overlevenden “horen” te zitten (de verwachte aantallen, expected counts); het waren er 203. χ² telt al die verschillen tussen geteld en verwacht op tot één maat voor “hoe scheef is deze tabel?”. Nul betekent: precies zo saai als verwacht. En 190.4 — is dat veel? Geen idee, nog. Daarvoor moeten we eerst weten hoe scheef púúr toeval kan zijn.

Schud het

Dus dat gaan we maken: toeval, met onze eigen handen. We knippen de kolom overleefd los van de kolom klasse en delen ’m lukraak opnieuw uit. Iedereen houdt z’n klasse, de 711 “ja”s blijven 711 “ja”s — maar wíé overleeft, is nu puur lot. Doe dat duizend keer, en je hebt duizend werelden gebouwd waarin er écht geen samenhang is tussen klasse en overleven. In elk van die werelden rekenen we χ² uit.

OpmerkingIn R · schud de boel door elkaar
# één keer schudden: 'overleefd' lukraak herverdelen over de opvarenden
chisq.test(table(tit$klasse, sample(tit$overleefd)))$statistic   # → iets kleins

# doe het 1000 keer en kijk waar χ² dan landt
set.seed(42)
nep <- replicate(1000,
  chisq.test(table(tit$klasse, sample(tit$overleefd)))$statistic)

hist(nep, xlim = c(0, 200))              # het toeval-bergje, links in beeld
max(nep)                                  # → 22.3: verder komt puur geluk niet
abline(v = 190.4, col = "red", lwd = 2)   # en dáár staat de echte

Kijk eerst naar het bergje zelf, want daar zit al een les in. In duizend werelden waarin de waarheid “geen verband” is, is de gemeten scheefheid nooit precies nul — de kleinste geschudde χ² was 0.02, en de meeste liggen er ruim boven. Toeval deelt nooit perfect eerlijk uit; een beetje scheefheid krijg je altijd cadeau. Dát is wat het toeval-bergje je laat zien: zó ver komt puur geluk — tot een keer of 22, en dan houdt het op.

En dan die rode streep op 190.4. Niet aan de rand van het bergje — er mijlenver voorbij, bijna tien keer zo ver als het wildste toeval in duizend pogingen. Geen p-waarde die je moet geloven, maar een afstand die je zíét. De echte nacht van 1912 ligt niet in de wereld van het lot. De samenhang tussen klasse en overleven is echt.

Snap het

Echt — maar wat wéét je daarmee precies? Minder dan je denkt, en dat is de kern van dit blok. χ² beantwoordt maar één vraag, met veel gezag en weinig woorden: hangen deze twee samen, of is dit toeval-scheefheid? Antwoord: ze hangen samen. Punt. Het is een kaal ja — het zegt niet hoe stérk, niet wáár in de tabel, en al helemaal niet waaróm. Voor die drie vragen heb je drie andere dingen nodig, en die heb je eigenlijk al in handen.

Hoe sterk? Daar is een apart getal voor: Cramérs V, dat χ² terugschaalt naar een bandbreedte van 0 (geen samenhang) tot 1 (perfect voorspelbaar). Hier: V = .29 — een stevige, duidelijk zichtbare samenhang, maar geen lotsbestemming; ook in de derde klasse overleefde één op de vier.

Wáár zit het? Vraag de tabel welke cellen het hardst afwijken van verwacht — de residuen (residuals):

OpmerkingIn R · waar zit de scheefheid?
ct <- chisq.test(t)
round(ct$residuals, 1)        # per cel: hoe ver van 'verwacht' af?
sqrt(ct$statistic / sum(t))   # Cramérs V → 0.29

De uitschieters vertellen het verhaal: eerste klasse zit ver bóven verwacht bij de overlevenden (+9.6), bemanning en derde klasse ver erónder (−4.4 en −3.3). De scheefheid is geen gelijkmatig waas over de tabel — het is een trap, van boven naar beneden door het schip.

En waaróm? Hier houdt de statistiek haar mond, en terecht. De kruistabel zegt dat klasse en overleven samenhangen; ze zegt niet dat je ticket je redde. De verklaring is historisch, geen getal: de eersteklashutten lagen dekken dichter bij de reddingsboten, de bemanning bleef werken terwijl anderen instapten, hekken en gangen en taal zaten ertussen. Dat verhaal is waarschijnlijk wáár — maar het komt uit de geschiedenisboeken, niet uit χ². Wie alleen de toets rapporteert (“χ²(3) = 190.4, p < .001, dus er is een verband”) heeft het minst interessante deel te pakken. De percentages — 62, 41, 25, 24 — vertellen wat er die nacht gebeurde; de residuen wijzen aan waar; χ² zegt alleen dat het geen toeval was. Je hebt ze alle drie nodig, in die volgorde. En één ding nog, omdat het makkelijk wegzakt achter de getallen: dit waren tellingen van mensen. Wat de saaie verwachte tabel “gladstrijkt”, waren er die nacht honderden.

(Dat kleine getal df = 3 dat R erbij zet — de vrijheidsgraden — is boekhouding over de maat van de tabel: (4−1)×(2−1) = 3. Het vertelt de toets hoe groot het toeval-bergje voor een tabel van dit formaat hoort te zijn. Precies wat jij net zelf hebt gebouwd door te schudden.)

Zelfde vorm in het boek

Hier: hangen twee categorische variabelen samen — tellen, verwachten, en zien hoe ver de echte telling van saai afligt.

In het boek: nog niet — dit hoort bij de schil S2 · Tellen en kruistabellen.

Als die schil er komt, begint ze waar dit blok begon: bij de tabel en de percentages, niet bij de toets.

TODO (broertje, geschreven 24-7 naar het charter): S2-anker is de schil-variant — er is (nog) geen boek-hoofdstuk voor tellen/kruistabellen; anker updaten als dat verandert. Verhaal-stem-opening is een eerste stem-pas. De JASP-tweeling deelt deze tekst; alleen “Speel het / Schud het” verschilt (JASP kan de shuffle niet zelf — speeltje + hop, zie het JASP-blok). Alle getallen nagerekend op titanic.csv (seed 42 voor het schud-bergje: max 22.3, min 0.02).

Voetnoten

  1. De échte passagierslijst van de Titanic, zoals samengevat in het onderzoek van de British Board of Trade (1912); via de R-dataset Titanic (zie ook Dawson, 1995, Journal of Statistics Education). Alle getallen in dit blok zijn op die échte data nagerekend.↩︎