2. Reliability — Cronbach’s α, split-half en wat er overblijft

Het verhaal van dit thema

De wezel was nuchter, zoals altijd.

“Tien items,” zei hij, “en jij noemt dat een schaal.”

“Bos-Piekeren-Schaal,” zei de kraai. “Tien vragen. Eén score per dier.”

“Cronbach?”

“Komt eraan. Daarom zijn we hier.”

De wezel kruiste twee voorpoten. Hij was niet onder de indruk, maar hij was ook niet ongeïnteresseerd. Dat was zijn ding. “Eerst zien.”

“Als alpha onder de zeventig is,” zei hij, “ga ik weg.”

Tweehonderd bosdieren in dit thema. Tien items op een \(5\)-puntsschaal, samen de Bos-Piekeren-Schaal (BPS). Daarnaast twee kleine datasets: 70 pissebedden op een zes-item emotie-regulatie-schaal voor een mini-practical, en 143 egels op een zes-item doorzet-schaal, die bij de item-deletie naast de bosdieren komt te liggen.

In thema 1 leerde je wat scores betekenen (norm-scoren, T-scores, percentielen). Nu de vraag eronder: meet die schaal überhaupt iets consistents?

Drie hoofdvragen:

  1. Hangen de items samen? — Cronbach’s \(\alpha\), item-totaal-correlaties.
  2. Welke twee helften van de schaal zeggen hetzelfde? — split-half + Spearman-Brown.
  3. Welke items kunnen weg? — item-deletie-analyse, en wanneer het antwoord nee is.
NoteA. Wat is reliability?

Betrouwbaarheid reliability = de mate waarin een meting consistent is. Meet je hetzelfde nog een keer, onder dezelfde omstandigheden — krijg je dan hetzelfde getal?

Om dat na te gaan heb je twee metingen nodig die je eerlijk naast elkaar mag leggen. Zulke metingen heten parallel: ze meten allebei even goed hetzelfde onderliggende ding. Dat onderliggende ding heet de ware score — wat je zou meten als je instrument geen enkele ruis had. Het addertje: die ware score kun je niet zien, want je hebt alleen je meting. Of twee metingen écht parallel zijn weet je dus nooit zeker — je schat het. Vandaar drie manieren om aan die twee metingen te komen, elk met een eigen zwakke plek:

  • Parallelle vormen alternate forms — twee losse testen die hetzelfde meten, allebei afgenomen. Correleren de scores? Zwakke plek: dát ze parallel zijn is een aanname, geen meting.
  • Test-hertest test-retest — één test, twee momenten, dezelfde personen. Pearson-\(r\) tussen meting 1 en 2. Zwakke plek: de tweede keer is de eerste keer nog niet vergeten. Wie zich zijn antwoord herinnert, herhaalt het — inclusief de vergissing die hij de eerste keer maakte. De test lijkt daardoor stabieler dan hij is, en je schat de betrouwbaarheid te hoog.
  • Split-half — één test, één moment, in twee helften geknipt. Zwakke plek: je meet zo de betrouwbaarheid van een hálve test, en een kortere test is altijd minder betrouwbaar: minder items betekent minder gelegenheid om toevallige missers tegen elkaar weg te middelen. Spearman-Brown rekent daarom terug naar de volle lengte.

En als je verder telt dan twee metingen? Dan kom je bij interne consistentie internal consistency: behandel elk item als een aparte test. De maat daarvoor is Cronbach’s \(\alpha\). Dat is dit thema — je komt er drie varianten van tegen: de ruwe alfa, de gestandaardiseerde alfa, en KR-20 voor vragen met goed-fout-antwoorden.

Reliability \(\neq\) validity. Een onbetrouwbare schaal kan onmogelijk valide zijn (te veel ruis), maar een betrouwbare schaal hoeft nog niet valide te zijn (kan consistent het verkeerde meten). Validity volgt in thema 3.

En let op wát je schat. Betrouwbaarheid is geen eigenschap van een schaal, maar van deze schaal in deze populatie. Dezelfde tien items kunnen bij bosdieren keurig samenhangen en bij pissebedden uit elkaar vallen.

Eén vorm die je elders wél tegenkomt maar hier niet: inter-rater — stemmen twee beoordelaars overeen die hetzelfde object scoren? Dat is een volwaardige vorm van betrouwbaarheid, maar je meet hem niet met \(\alpha\): daarvoor gebruik je Cohen’s \(\kappa\) bij een categorisch oordeel, en de ICC bij continue scores. Meer erover achterin, bij Wat blijft liggen.

NoteB. Cronbach’s α — de standaardmaat voor internal consistency

Cronbach’s \(\alpha\) kwantificeert hoe sterk de items binnen een schaal samenhangen. Formules:

\[ \alpha = \frac{k}{k - 1} \left( 1 - \frac{\sum_{i=1}^k s_i^2}{s_{\text{som}}^2} \right) \]

Met \(k\) = aantal items, \(s_i^2\) = variantie van item \(i\), \(s_{\text{som}}^2\) = variantie van de som-score.

Of equivalent (gebaseerd op gemiddelde inter-item-correlatie \(\bar{r}\)):

\[ \alpha_{\text{std}} = \frac{k \cdot \bar{r}}{1 + (k - 1) \cdot \bar{r}} \]

Twee belangrijke eigenschappen:

  1. \(\alpha\) stijgt met \(k\) — meer items = hogere \(\alpha\), ook bij gelijke inter-item-correlatie. Dat verklaart waarom kortere schalen het lastiger hebben.
  2. \(\alpha\) stijgt met \(\bar{r}\) — sterker samenhangende items = hogere \(\alpha\).

Vuistregels (gangbaar, niet wettelijk):

\(\alpha\)-niveau Interpretatie
\(\geq .90\) Uitstekend (soms te hoog — items kunnen redundant zijn)
\(.80\)-\(.89\) Goed
\(.70\)-\(.79\) Acceptabel voor onderzoek
\(.60\)-\(.69\) Twijfelachtig — zeker geen klinische beslissing op baseren
\(< .60\) Schaal werkt niet
NoteC. Wezel-frame — wat onderzoeken we?

De wezel — sluw, kritisch — kijkt naar de Bos-Piekeren-Schaal (BPS) en wil weten:

  • Hangen de tien items voldoende samen om er één score uit te halen?
  • Zijn er items die er niet bij horen (te zwak gerelateerd, andere structuur)?
  • Hoe stevig is de geschatte \(\alpha\) — bouwt hij door als ik items wegsnijd?

De wezel werkt door. Hij is niet snel tevreden. Niemand mag \(\alpha = .85\), klaar” zeggen zonder dat de wezel naar de items kijkt en vraagt: “Welke item is de zwakkere broer?”

NoteHoe dit hoofdstuk leest

Drie-laagse structuur als de andere thema’s:

  1. Verhaal-frame — wezel en consorten in het bos.
  2. Algemene vorm — abstract met mijn_data.
  3. Voor onze dieren — uitvoerend, concrete namen.

Daarnaast vier soorten blokken, elk met zijn eigen kop: vragen die je zelf maakt, antwoorden die je pas openklapt ná je eigen poging, vuistregels om vast te houden, en alarmen bij wat er in de praktijk vaak misgaat.

  • Scale-score als gemiddelde over \(k\) items (rowMeans).
  • NA-discipline bij scale-scoren: bij hoogstens één ontbrekende waarde mag je middelen, vanaf twee ontbrekend zet je de scale-score op NA — op de 5 items van thema 1 dus minstens 4 ingevuld. Waaróm die grens zo streng staat zie je pas in dít thema: Spearman-Brown laat die schaal zakken van \(\alpha = .85\) over 5 items naar \(.81\) over 4 en \(.77\) over 3.
  • Norm-scoren via z, T, percentiel — nu pas zinvol als de schaal meet. Vandaar dit thema vóór je veel norm-tabellen bouwt.

Plus Bens slogan uit thema 1: Ruw is Ruk. Geldt hier dubbel — een ruwe item-totaal-correlatie zegt niets als de items op verschillende schalen staan. Standaardiseren of rekening houden met item-variantie.

Werkmaterialen — R-pakketten en functies

De wezel pakt zijn gereedschap

Gereedschap Waar het voor is Pakket
psych::alpha() Cronbach’s \(\alpha\) + item-statistieken in één output psych
psych::splitHalf() Alle mogelijke split-halfs en gemiddelde psych
cor() Item-correlatiematrix base
rowMeans(), rowSums() Som-score / scale-score base
cor(meting1, meting2) Test-retest betrouwbaarheid (zelden in dit thema) base
var() Variantie van items en som-score base

Let op de laatste regel maar één: test-retest is een correlatie tussen meting 1 en meting 2, niet een t.test(..., paired = TRUE). Die gepaarde toets vraagt of het gemiddelde van de groep verschuift tussen de twee momenten — een heel andere vraag. Een schaal kan perfect betrouwbaar zijn en tóch een verschuiving in het gemiddelde laten zien (iedereen scoort de tweede keer twee punten hoger), en een schaal kan volstrekt onbetrouwbaar zijn terwijl het gemiddelde precies gelijk blijft.

Je kunt \(\alpha\) zelf uitrekenen — formule kennen is examenstof. Maar in praktijk is psych::alpha() éé́n commando dat je alles geeft: \(\alpha\) raw + standardized, item-statistieken (raw.r, r.drop), \(\alpha\)-als-item-deleted, gemiddelden + SDs per item. Voor onderzoek + rapportage de werkelijke route. Voor het tentamen: weet de formule én weet wat de output betekent.

Notatie — symbolen voor reliability

NoteSleutelsymbolen
  • \(\alpha\) — Cronbach’s alpha. Niet te verwarren met het Type-I-foutniveau (ook \(\alpha\)). Context maakt duidelijk welke.
  • \(k\) — aantal items in de schaal.
  • \(\bar{r}\) — gemiddelde inter-item-correlatie.
  • \(s_i^2\) — variantie van item \(i\).
  • \(s_{\text{som}}^2\) — variantie van de som-score.
  • \(r_{\text{half}}\) — correlatie tussen twee schaal-helften (split-half-correlatie).
  • \(r_{\text{SB}}\) — door Spearman-Brown gecorrigeerde betrouwbaarheid.
  • \(r_{\text{drop}}\) — item-totaal-correlatie als het item zelf eruit is gehaald (corrected item-total correlation).
  • \(se_{\text{m}}\) — de standaardmeetfout standard error of measurement: hoe ver de score van één persoon gemiddeld naast zijn ware score valt. In dit hoofdstuk rekenen we hem als \(se_{\text{m}} = SD \cdot \sqrt{1 - \alpha}\). Je formuleblad schrijft dezelfde som met andere letters; die vertaling staat bij de opgave over de standaardmeetfout.
  • \(s_{\text{e}}\) — de standaardafwijking van de meetfout. Dat is per definitie hetzelfde getal als \(se_{\text{m}}\), en daarom zet het formuleblad er een gelijkteken tussen.
  • \(N\) — omvang van de hele steekproef. \(n\) — omvang van een deelgroep daarbinnen.
TipVuistregels zijn afspraken, geen wetten
  • \(\alpha\)-grens voor gebruik in onderzoek: \(\geq .70\). Voor klinische beslissingen op individueel niveau: \(\geq .80\), bij voorkeur \(\geq .90\).
  • Schaal-lengte: \(k \geq 5\) voor stabiele \(\alpha\)-schatting. Onder \(k = 3\): rapporteer met expliciete waarschuwing.
  • Steekproef-grootte voor reliability-schatting: \(N \geq 100\) voor betrouwbare \(\alpha\). Bij \(N < 50\): bootstrap-CI is gepast.
  • Item-totaal-correlatie: \(r_{\text{drop}} \geq .30\) voor gangbare items. \(< .30\) = kandidaat voor verwijdering.
  • Spearman-Brown drempel: na correctie naar volledige schaal-lengte; gebruik bij split-half waar je twee parallelle helften hebt.

Verschillende vakgroepen hanteren iets andere drempels. Kom je er in een tentamenvraag of in een artikel een tegen die van deze afwijkt, dan is dat geen fout van jou: noem de grens die je aanhoudt, en zeg erbij waarom. Een drempel is een afspraak, en een afspraak die je opschrijft kan iemand met je oneens zijn — een drempel die je stil aanneemt niet.

NoteCode in dit hoofdstuk — wat moet je kunnen typen?

Code is standaard open als je hem moet kunnen typen op het R-practical-tentamen: psych::alpha(), cor(), rowMeans(), rowSums(), var(), psych::splitHalf(). Code die alleen ter illustratie dient — gt-tabellen, ggplot-decoratie, item-pair-matching-algoritme — staat ingeklapt met een knopje “Toon code”.

2.0 Project- en datavoorbereiding

Open de meegestuurde projectmap (02_reliability/) en dubbelklik op 02_reliability.Rproj.

install.packages(c("tidyverse", "psych"))
  1. Open de hoofd-dataset.
# load() opent het bestand en zet het object dat erin zit klaar onder zijn
# eigen naam -- vandaar dat er nergens `iets <- load(...)` staat.
load("data/bos_dieren_piekeren.RData")

# str() geeft de bouwtekening: hoeveel rijen, welke kolommen, van welk soort.
str(bos_dieren_piekeren)
'data.frame':   200 obs. of  13 variables:
 $ dier_id             : Factor w/ 200 levels "d001","d002",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ geslacht            : Factor w/ 2 levels "man","vrouw": 1 2 1 1 2 2 1 1 1 2 ...
 $ diersoort           : Factor w/ 4 levels "bunzing","egel",..: 4 4 3 3 4 3 1 3 4 4 ...
 $ item1_terugkijken   : num  3 3 3 2 3 3 5 5 2 2 ...
 $ item2_nachtgedachten: num  2 3 2 4 5 3 3 3 4 1 ...
 $ item3_anderengedrag : num  3 2 5 3 3 4 1 4 1 1 ...
 $ item4_ergevoel      : num  2 3 4 3 3 4 4 4 3 1 ...
 $ item5_zinloos       : num  3 3 5 1 3 2 5 1 5 1 ...
 $ item6_loslaten      : num  2 1 5 3 3 2 4 5 1 1 ...
 $ item7_doorzetten    : num  3 5 4 4 2 2 1 3 2 3 ...
 $ item8_zorgen        : num  4 2 4 2 4 3 4 2 2 1 ...
 $ item9_terug         : num  4 2 5 5 2 3 4 3 3 1 ...
 $ item10_aanwezigheid : num  2 3 5 5 2 5 4 3 2 1 ...

Per dier: een dier_id, geslacht, diersoort, en tien items op een \(5\)-puntsschaal die samen de Bos-Piekeren-Schaal (BPS) vormen.

  • item1_terugkijken: “Ik blijf hangen in wat er gisteren is gebeurd.”
  • item2_nachtgedachten: “’s Nachts spelen problemen door mijn kop.”
  • item3_anderengedrag: “Ik vraag me af wat anderen van mij vinden.”
  • item4_ergevoel: “Ik voel me schuldig over kleine dingen.”
  • item5_zinloos: “Ik vind sommige dingen achteraf zinloos.”
  • item6_loslaten: “Ik krijg gedachten niet zomaar uit mijn hoofd.”
  • item7_doorzetten: “Ik laat me niet snel uit het veld slaan.”ongepoold: hoog op dit item = láge piekeren. De wezel had hem zo opgeschreven en is vergeten hem om te keren bij scoring. Komt straks aan de beurt.
  • item8_zorgen: “Ik maak me zorgen over de toekomst.”
  • item9_terug: “Ik kom terug op gesprekken die niet goed liepen.”
  • item10_aanwezigheid: “Het kost moeite om bij het hier-en-nu te blijven.”

Allemaal \(1 =\) bijna nooit, \(5 =\) bijna altijd. Eén ontbrekende waarde op item6_loslaten[73].

2.1 Cronbach’s α en item-totaal-correlaties

Hangen de items samen?

\(\alpha\),” zei de wezel. “Eén getal dat samenvat hoe goed je items op één golflengte zitten. Bij hoge \(\alpha\) doen ze dat — onder lage \(\alpha\) niet.”

NoteVoor je gaat rekenen — vijf vragen aan jezelf
  1. Wie of wat wordt er gemeten? De wezel heeft \(200\) bosdieren op tien BPS-items genoteerd.
  2. Wat wordt er gemeten? Tien items, elk \(1\)-\(5\), plus twee groeps-variabelen.
  3. Onafhankelijk of afhankelijk? Geen voorspelmodel. We willen weten: hangen de items genoeg samen om één som-score te rechtvaardigen?
  4. Meetniveau? Items: ordinaal, behandeld als interval. Som-score: interval (\(10\)-\(50\)). Geslacht: nominaal. Diersoort: nominaal.
  5. Welke techniek? Bij internal consistency: Cronbach’s \(\alpha\) + item-statistieken. Bij parallelle helften: split-half + Spearman-Brown. Beide oefenen we hier.

T1 — Welke reliability-soort?

NoteVraag T1 — Pen-en-papier

Voor elk vignet: kies tussen internal consistency (\(\alpha\), KR-20, split-half), test-retest, inter-rater (\(\kappa\), ICC), of parallel-forms.

Wat tussen haakjes staat zijn de maten die bij die soort horen. Je hoeft ze hier nog niet te kunnen uitrekenen en je hebt ze niet nodig om de vraag te maken — kies de soort. KR-20 komt verderop nog langs; \(\kappa\) en ICC blijven buiten dit hoofdstuk.

a) Een psycholoog wil weten of de tien items van haar nieuwe depressie-vragenlijst samen één construct meten.

b) Een onderzoeker meet bij \(80\) patiënten op \(t_0\) en zes weken later op \(t_1\) dezelfde stress-vragenlijst — werkt de schaal stabiel?

c) Twee psychiaters scoren \(50\) patiënten elk op een PTSS-symptoomschaal, op basis van interview. Komen hun scores overeen?

d) Een uitgever heeft twee versies van dezelfde rekenkundetoets (vorm A en vorm B). Geven ze dezelfde score per leerling?

e) Een toetsenmaker knipt een rekenvaardigheidstoets van \(40\) opgaven in twee helften van \(20\), en kijkt of een leerling op beide helften ongeveer even goed scoort. Eén afname, één moment.

a) Internal consistency (\(\alpha\)). Tien items, één meetmoment, geen rater-vraag — gewoon: meten ze hetzelfde construct?

b) Test-retest. Twee meetmomenten op dezelfde personen, dezelfde test. Pearson-\(r\) tussen \(t_0\) en \(t_1\).

c) Inter-rater (ICC voor continue scores, \(\kappa\) voor categorische). Twee beoordelaars, hetzelfde object, vraag is consistentie tussen beoordelaars.

Dit is de enige soort in deze rij die je in dit hoofdstuk niet leert uitrekenen, en dat is met opzet: interbeoordelaarsbetrouwbaarheid valt buiten deze cursus. Je hoeft hem hier alleen te herkennen — aan het patroon twee beoordelaars, één object — en te weten dat \(\alpha\) er niet voor deugt. Wat je er wél voor gebruikt staat in Wat blijft liggen: Cohen’s \(\kappa\) bij een categorisch oordeel, de ICC bij continue scores.

d) Parallel-forms. Twee versies van hetzelfde construct — bedoeld als equivalent. Pearson-\(r\) tussen vorm A en vorm B.

e) Internal consistency, en wel via split-half. Dit is de valkuil van de rij: twee helften zien eruit als twee vormen, dus parallel-forms ligt voor de hand. Het verschil zit in de afname. Bij d) zijn het twee toetsen die apart zijn gemaakt en apart worden afgenomen; hier is er één toets, één afname, en de tweedeling komt pas achteraf op de tafel van de onderzoeker. Alles wat je uit één afname over samenhang binnen de toets haalt, is interne consistentie — split-half is daar één route in, Cronbach’s \(\alpha\) een andere. En let op: de correlatie tussen de twee helften is de betrouwbaarheid van een halve toets, dus die moet nog met Spearman-Brown naar volle lengte worden opgehoogd. Dat doe je verderop, bij de split-half zelf.

Vuistregel. Eén meetmoment, items binnen schaal = internal consistency (\(\alpha\), of split-half). Twee meetmomenten, dezelfde test = test-retest. Twee beoordelaars, één object = inter-rater. Twee apart afgenomen versies van een test = parallel-forms. Zit je te twijfelen: tel eerst hoe vaak er gemeten is, en pas daarna wat er met de uitkomst gebeurt.

2.1.a Verkenning — item-statistieken

# De tien itemnamen één keer in een rijtje. c() is kort voor combine: het plakt
# losse waarden aan elkaar tot één rijtje. Zo hoef je die namen verderop niet
# tien keer over te tikken -- en vertik je je ook niet.
items <- c("item1_terugkijken", "item2_nachtgedachten", "item3_anderengedrag",
           "item4_ergevoel",    "item5_zinloos",        "item6_loslaten",
           "item7_doorzetten",  "item8_zorgen",         "item9_terug",
           "item10_aanwezigheid")

Algemene vorm.

# Item-means en SDs.
sapply(mijn_data[, items], mean, na.rm = TRUE)
sapply(mijn_data[, items], sd,   na.rm = TRUE)

# Item-correlatiematrix.
round(cor(mijn_data[, items], use = "complete.obs"), 2)

Voor onze dieren.

Ook hier staat een aantal sommen in twee schrijfwijzen naast elkaar, in tabbladen. Net als in thema 1: Base R staat vooraan en is het enige dat op het tentamen komt; dplyr staat ernaast om te kijken, en je hoeft er niets van te kunnen typen. Ben je het pijpje |> of \(x) kwijt, dan staan die uitgelegd in het kader Twee tekens die je in elk dplyr-blok terugziet in thema 1.

# sapply() past een functie toe op elke kolom en geeft je een rijtje getallen
# terug, netjes met de itemnamen erbij.
round(sapply(bos_dieren_piekeren[, items], mean, na.rm = TRUE), 2)
   item1_terugkijken item2_nachtgedachten  item3_anderengedrag 
                3.13                 3.10                 3.13 
      item4_ergevoel        item5_zinloos       item6_loslaten 
                3.09                 2.98                 3.07 
    item7_doorzetten         item8_zorgen          item9_terug 
                3.02                 3.08                 3.00 
 item10_aanwezigheid 
                2.92 
# na.rm = TRUE laat de ontbrekende waarde op item6 weg. Zonder die schakelaar
# krijgt dat ene item een gemiddelde van NA en de rest gewoon een getal -- één
# gat maakt dus één kolom stil onbruikbaar.
round(sapply(bos_dieren_piekeren[, items], sd,   na.rm = TRUE), 2)
   item1_terugkijken item2_nachtgedachten  item3_anderengedrag 
                1.24                 1.27                 1.43 
      item4_ergevoel        item5_zinloos       item6_loslaten 
                1.28                 1.19                 1.27 
    item7_doorzetten         item8_zorgen          item9_terug 
                1.32                 1.23                 1.22 
 item10_aanwezigheid 
                1.24 
# summarise() perst de tabel samen tot één regel; across() doet dat voor alle
# tien de items in één keer, en all_of() zegt dat hun namen in het rijtje
# `items` staan en niet hier in de code.
bos_dieren_piekeren |>
  summarise(across(all_of(items), \(x) mean(x, na.rm = TRUE))) |>
  round(2)
  item1_terugkijken item2_nachtgedachten item3_anderengedrag item4_ergevoel
1              3.13                  3.1                3.13           3.09
  item5_zinloos item6_loslaten item7_doorzetten item8_zorgen item9_terug
1          2.98           3.07             3.02         3.08           3
  item10_aanwezigheid
1                2.92
bos_dieren_piekeren |>
  summarise(across(all_of(items), \(x) sd(x, na.rm = TRUE))) |>
  round(2)
  item1_terugkijken item2_nachtgedachten item3_anderengedrag item4_ergevoel
1              1.24                 1.27                1.43           1.28
  item5_zinloos item6_loslaten item7_doorzetten item8_zorgen item9_terug
1          1.19           1.27             1.32         1.23        1.22
  item10_aanwezigheid
1                1.24

Bij tien items zie je waarom dit een keuze blijft en geen regel. Base R zet de namen boven de getallen en breekt af per drie; dplyr maakt één tabel van tien kolommen breed, die in blokken onder elkaar doorloopt. Even lang ongeveer — base R neemt er hier zelfs twee printregels méér — maar bij base R staat elke naam pal boven zijn eigen getal, en dat leest bij tien items makkelijker.

Kijk daarbij ook naar de decimalen in de dplyr-tabel: item9_terug staat er als kale 3 en item2_nachtgedachten als 3.1. Dat is dezelfde afdruk-eigenaardigheid als in thema 1, en nu per kolom in plaats van per rijtje — elke kolom kiest zijn eigen breedte. Voor je erover rapporteert zet je zo’n getal dus altijd zelf op twee decimalen.

Toon code (item-correlatiematrix)
# cor() op een hele tabel geeft een matrix: elk item tegen elk ander item, met
# een diagonaal van enen (elk item correleert perfect met zichzelf).
# use = "complete.obs" gooit de dieren met een gat eruit vóór het rekenen.
cor_BPS <- cor(bos_dieren_piekeren[, items], use = "complete.obs")
round(cor_BPS, 2)
                     item1_terugkijken item2_nachtgedachten item3_anderengedrag
item1_terugkijken                 1.00                 0.41                0.25
item2_nachtgedachten              0.41                 1.00                0.34
item3_anderengedrag               0.25                 0.34                1.00
item4_ergevoel                    0.35                 0.39                0.29
item5_zinloos                     0.38                 0.38                0.30
item6_loslaten                    0.41                 0.37                0.36
item7_doorzetten                 -0.53                -0.46               -0.33
item8_zorgen                      0.47                 0.52                0.29
item9_terug                       0.43                 0.43                0.32
item10_aanwezigheid               0.47                 0.48                0.40
                     item4_ergevoel item5_zinloos item6_loslaten
item1_terugkijken              0.35          0.38           0.41
item2_nachtgedachten           0.39          0.38           0.37
item3_anderengedrag            0.29          0.30           0.36
item4_ergevoel                 1.00          0.33           0.38
item5_zinloos                  0.33          1.00           0.44
item6_loslaten                 0.38          0.44           1.00
item7_doorzetten              -0.37         -0.40          -0.38
item8_zorgen                   0.52          0.43           0.38
item9_terug                    0.39          0.41           0.50
item10_aanwezigheid            0.40          0.36           0.36
                     item7_doorzetten item8_zorgen item9_terug
item1_terugkijken               -0.53         0.47        0.43
item2_nachtgedachten            -0.46         0.52        0.43
item3_anderengedrag             -0.33         0.29        0.32
item4_ergevoel                  -0.37         0.52        0.39
item5_zinloos                   -0.40         0.43        0.41
item6_loslaten                  -0.38         0.38        0.50
item7_doorzetten                 1.00        -0.48       -0.41
item8_zorgen                    -0.48         1.00        0.43
item9_terug                     -0.41         0.43        1.00
item10_aanwezigheid             -0.46         0.44        0.40
                     item10_aanwezigheid
item1_terugkijken                   0.47
item2_nachtgedachten                0.48
item3_anderengedrag                 0.40
item4_ergevoel                      0.40
item5_zinloos                       0.36
item6_loslaten                      0.36
item7_doorzetten                   -0.46
item8_zorgen                        0.44
item9_terug                         0.40
item10_aanwezigheid                 1.00
Toon code (item-correlatiematrix)
# cat() drukt tekst af zoals je hem typt; "\n" is een regelovergang.
cat("\nGemiddelde inter-item-correlatie:\n")

Gemiddelde inter-item-correlatie:
Toon code (item-correlatiematrix)
# upper.tri() pakt alleen de driehoek bóven de diagonaal. Dat moet, want de
# matrix bevat elke correlatie twee keer en de diagonaal van enen erbij --
# gemiddel je de hele matrix, dan trekken die enen het getal omhoog.
mean_r <- mean(cor_BPS[upper.tri(cor_BPS)])
round(mean_r, 3)
[1] 0.231
NoteVragen 2.1.a

a) Liggen de item-means dicht bij elkaar?

b) Welke item heeft de laagste correlaties met de rest?

c) Wat is de gemiddelde inter-item-correlatie? Past die bij een redelijk werkende schaal?

d) Voorspel op basis van \(k\) en \(\bar{r}\) wat \(\alpha_{\text{std}}\) ongeveer wordt.

a) Item-means liggen tussen \(2.92\) en \(3.13\) — vrijwel gelijk. Dat is gewenst voor split-half (zie 2.2): items met sterk afwijkende moeilijkheid zijn lastig te paren.

b) item7_doorzetten valt op met negatieve correlaties met vrijwel alle andere items (\(r = -.33\) tot \(-.53\)). Dat is een sterk signaal: dit item is ongepoold (negatief geformuleerd t.o.v. de rest van de schaal). Voordat we \(\alpha\) berekenen moet hij worden omgepoold — zie 2.1.b en 2.1.c. Daarnaast heeft item3_anderengedrag lagere maar wel positieve correlaties — kandidaat voor item-deletie-discussie, maar dat speelt pas ná ompoling van item7.

c) Gemiddelde inter-item-correlatie vóór ompoling: \(\bar{r} = .23\) — kunstmatig laag door de negatieve correlaties van item7. Na ompoling van item7: \(\bar{r} = .40\) — past bij een schaal die één construct meet met enige item-variatie.

d) Voorspelling vóór ompoling: \(\alpha_{\text{std}} = (10 \cdot .23) / (1 + 9 \cdot .23) = .75\) — onderschatting. Voorspelling na ompoling: \(\alpha_{\text{std}} = (10 \cdot .40) / (1 + 9 \cdot .40) = .87\). Verschil \(= .12\)substantieel, en precies waarom ompolen niet optioneel is.

APA-stijl. (rapportage volgt na ompoling — zie 2.1.d)

2.1.b Recoden / ompolen — hoog wordt laag

Het item dat de andere kant op staat

De wezel rolde door zijn correlatiematrix en bleef bij item 7 hangen.

“Min vier-en-veertig,” zei hij. “Negatieve correlatie met de rest.”

“Item is kapot,” zei de bunzing.

“Item is andersom geschreven,” zei de wezel. “Ik laat me niet uit het veld slaan. Hoog op die zin = lage piekeren. Tegen de rest van de schaal in. Niet kapot — alleen ongepoold.”

“Wat doe je ermee?”

“Recoden. Ompolen. Score van \(5\) wordt \(1\), \(4\) wordt \(2\), \(3\) blijft \(3\). Dan loopt hij weer mee.”

NoteWat is ompolen — en waarom moet het?

Bij vragenlijsten zijn sommige items negatief geformuleerd: hoge score = laag construct. Voorbeelden in een piekeren-schaal:

  • “Ik blijf hangen in nare gedachten” — hoog = veel piekeren ✓ (positief geformuleerd voor piekeren)
  • “Ik laat me niet uit het veld slaan” — hoog = weinig piekeren ✗ (omgekeerd geformuleerd)

Ongepolde items werken tegen de schaal:

  • Negatieve item-totaal-correlaties.
  • Lage of zelfs negatieve \(\alpha\).
  • Misleidende som-scores als je toch optelt.

Oplossing: ompolen vóór je alpha berekent. Op een \(5\)-punts Likert (\(1\)-\(5\)):

\[ \text{nieuwe score} = (\text{max} + \text{min}) - \text{oude score} = 6 - \text{oude score} \]

Op \(1\)-\(7\) Likert: \(8 - \text{score}\). Algemeen: \((\text{max} + \text{min}) - \text{score}\).

Hoe weet je of een item omgepoold moet?

  1. Theoretisch — bij item-constructie weet je welke items omgekeerd geformuleerd zijn. Markeer ze in de data-dictionary.
  2. Empirisch — bekijk de correlatiematrix. Items met overwegend negatieve correlaties met de rest zijn ongepoolde kandidaten.
  3. Auto-detectie via psych::alpha(..., check.keys = TRUE)psych keert items met negatieve item-totaal-correlatie automatisch om en waarschuwt.
WarningPas op — uni doet het soms niet, wij wel

Sommige cursussen / workboeken slaan ompoling over en gaan direct door naar Cronbach’s \(\alpha\). Voor dit werkboek geldt: altijd checken op ongepolde items vóór \(\alpha\). Een gepubliceerde \(\alpha\) op een schaal met ongepoolde items is een ongeldige schatting — geen kleine fout, maar een fundamentele meet-claim die niet klopt.

Tijdsinvestering: \(30\) seconden per schaal (correlatiematrix scannen op negatieve waarden). Risico bij overslaan: alpha onderschat, schaal ten onrechte als onbetrouwbaar beoordeeld, of erger — onterecht als betrouwbaar.

2.1.c Recoden in R — drie routes

In onze dataset staat één ongepoold item: item7_doorzetten (“Ik laat me niet snel uit het veld slaan”). Hoog op dit item = láge piekeren. De wezel had hem zo geformuleerd en is vergeten hem om te keren bij scoring. Vóór alle volgende analyses ompolen we hem.

Eerste stap: kijk naar de correlaties. In 2.1.a heb je de correlatiematrix al gezien — item7_doorzetten heeft negatieve correlaties met alle andere items. Dat is het signaal.

# Alleen de correlaties van item7 met de rest -- duidelijker dan de hele matrix.
# De naam vóór de komma kiest een rij: cor_full["item7_doorzetten", ] is de
# hele regel van item7. Zou je hem ná de komma zetten, dan kreeg je de kolom --
# bij een correlatiematrix dezelfde getallen, maar dat is toeval en geen regel.
cor_full <- cor(bos_dieren_piekeren[, items], use = "complete.obs")
round(cor_full["item7_doorzetten", ], 2)
   item1_terugkijken item2_nachtgedachten  item3_anderengedrag 
               -0.53                -0.46                -0.33 
      item4_ergevoel        item5_zinloos       item6_loslaten 
               -0.37                -0.40                -0.38 
    item7_doorzetten         item8_zorgen          item9_terug 
                1.00                -0.48                -0.41 
 item10_aanwezigheid 
               -0.46 

Route 1 — handmatig met aritmetiek

Er zijn twee schrijfwijzen voor het ompolen zelf. Wat je erna doet om te kijken of het gelukt is, is in beide gevallen hetzelfde, en dat staat daarom één keer onder de tabbladen.

# 5-punts Likert: nieuwe waarde = 6 - oude waarde. Waar die 6 vandaan komt:
# hoogste antwoord plus laagste antwoord, dus 5 + 1. Bij een 7-puntsschaal
# wordt het 8 - oude waarde.
bos_dieren_piekeren$item7_doorzetten_REC <- 6 - bos_dieren_piekeren$item7_doorzetten
# mutate() zet de omgepoolde kolom erbij. Binnen mutate() noem je het item bij
# zijn kale naam -- geen dollarteken, want dplyr weet al in welke tabel hij
# kijkt. Dat is het hele verschil met de regel links.
bos_dieren_piekeren <- bos_dieren_piekeren |>
  mutate(item7_doorzetten_REC = 6 - item7_doorzetten)

Heb je er drie of vier, dan hoef je die regel niet drie of vier keer te schrijven. across() doet ze in één keer:

ompool <- c("item7_doorzetten", "item3_anderengedrag")

bos_dieren_piekeren |>
  mutate(across(all_of(ompool), \(x) 6 - x, .names = "{.col}_REC"))

.names = "{.col}_REC" bepaalt hoe de nieuwe kolommen gaan heten: {.col} is de oude naam, dus item7_doorzetten wordt item7_doorzetten_REC. Laat dat niet weg — dan schrijft across() over de oorspronkelijke kolommen heen, en dan zijn je ruwe antwoorden weg zonder dat iets dat meldt.

# Natrekken of het gelukt is: na ompoling horen de correlaties van item7 met de
# rest positief te worden. Blijven ze negatief, dan meet dat item echt iets
# anders, en is ompolen niet de oplossing.
items_REC <- c("item1_terugkijken", "item2_nachtgedachten", "item3_anderengedrag",
               "item4_ergevoel",    "item5_zinloos",        "item6_loslaten",
               "item7_doorzetten_REC",  "item8_zorgen",     "item9_terug",
               "item10_aanwezigheid")

# Een naam tussen blokhaken vóór de komma kiest een rij en geen kolom:
# cor_REC["item7_doorzetten_REC", ] is de hele regel van item7.
cor_REC <- cor(bos_dieren_piekeren[, items_REC], use = "complete.obs")
round(cor_REC["item7_doorzetten_REC", ], 2)
   item1_terugkijken item2_nachtgedachten  item3_anderengedrag 
                0.53                 0.46                 0.33 
      item4_ergevoel        item5_zinloos       item6_loslaten 
                0.37                 0.40                 0.38 
item7_doorzetten_REC         item8_zorgen          item9_terug 
                1.00                 0.48                 0.41 
 item10_aanwezigheid 
                0.46 

Alle correlaties zijn nu positief — item7_doorzetten_REC loopt mee met de andere items.

Route 2 — psych::reverse.code() met sleutelvector

# Sleutelvector: 1 = laat item ongemoeid; -1 = pol om.
# Lengte gelijk aan het aantal items (10), met -1 op de plek van item7.
keys_vec <- c(1, 1, 1, 1, 1, 1, -1, 1, 1, 1)

# mini en maxi zijn de laagste en hoogste mogelijke antwoordwaarde. Die moet je
# zélf opgeven: reverse.code() leest ze niet af uit de data, en dat is ook
# terecht -- als niemand een 1 of een 5 heeft geantwoord staat de grens er niet
# in, en dan zou hij de verkeerde omkering rekenen.
bos_REC <- psych::reverse.code(keys_vec,
                               bos_dieren_piekeren[, items],
                               mini = 1,
                               maxi = 5)

# colnames() geeft de kolomnamen. De omgepoolde kolom krijgt automatisch een
# minteken achter zijn naam, zodat je later kunt zien dat er iets met hem is
# gebeurd.
colnames(bos_REC)
 [1] "item1_terugkijken"    "item2_nachtgedachten" "item3_anderengedrag" 
 [4] "item4_ergevoel"       "item5_zinloos"        "item6_loslaten"      
 [7] "item7_doorzetten-"    "item8_zorgen"         "item9_terug"         
[10] "item10_aanwezigheid" 

psych::reverse.code() levert een data-frame waarin de omgepoolde kolom is hernoemd (suffix -). Voor downstream-gebruik kun je hem aankoppelen aan de oorspronkelijke data of vervangen.

Route 3 — auto-detectie via psych::alpha(check.keys = TRUE)

# check.keys = TRUE laat psych zelf zoeken naar ongepolde items -- hij kijkt
# naar negatieve item-totaal-correlaties en keert die items om.
res_auto <- psych::alpha(bos_dieren_piekeren[, items], check.keys = TRUE)

# $keys laat zien wat hij besloten heeft: de itemnamen, met een minteken vóór
# de naam van elk item dat hij heeft omgekeerd. Lees dat altijd na -- zo zie je
# of hij hetzelfde item heeft aangewezen als jij. Let op het verschil met de
# sleutelvector van route 2: die schrijf je als 1 en -1, deze komt eruit als
# namen.
res_auto$keys
[[1]]
 [1] "item1_terugkijken"    "item2_nachtgedachten" "item3_anderengedrag" 
 [4] "item4_ergevoel"       "item5_zinloos"        "item6_loslaten"      
 [7] "-item7_doorzetten"    "item8_zorgen"         "item9_terug"         
[10] "item10_aanwezigheid" 

psych::alpha print een waarschuwing dat item7_doorzetten ongepoold is, en keert hem automatisch om voor de \(\alpha\)-berekening. Handig — maar valideer altijd theoretisch dat de auto-omkering klopt.

Alle drie de routes komen op hetzelfde neer; wat verschilt is hoeveel je zelf opschrijft en hoeveel je aan psych overlaat. Route 1 laat je de rekenregel zien, route 3 verbergt hem — en dat is precies waarom je hem één keer met de hand hoort te doen.

# Vanaf hier wijst `items` naar het omgepoolde item7 in plaats van naar het
# oorspronkelijke. De oude kolom blijft wel in de data staan -- we hebben hem
# niet weggegooid, alleen niet meer in de lijst gezet. Dat is met opzet: zo kun
# je altijd terug naar de ruwe antwoorden.
items <- c("item1_terugkijken", "item2_nachtgedachten", "item3_anderengedrag",
           "item4_ergevoel",    "item5_zinloos",        "item6_loslaten",
           "item7_doorzetten_REC",  "item8_zorgen",     "item9_terug",
           "item10_aanwezigheid")
NoteVragen 2.1.c

a) Welk getal trek je af bij een \(7\)-punts Likert (\(1\)-\(7\))?

b) Welke drie signalen wijzen op een ongepoold item?

c) Wat is het effect op \(\alpha\) van een ongepoold item dat je niet ompolt?

d) Wanneer is auto-detectie via check.keys = TRUE riskant?

a) \(8 - \text{score}\). Algemene formule: \((\text{max} + \text{min}) - \text{score}\). Bij \(1\)-\(7\): \(7 + 1 = 8\).

b) (1) Negatieve correlatie tussen item en rest van de schaal. (2) Negatieve item-totaal-correlatie (\(r_{\text{drop}} < 0\)). (3) Itemtekst die conceptueel tegengesteld geformuleerd is t.o.v. wat de schaal meet (theoretische check).

c) \(\alpha\) onderschat de werkelijke betrouwbaarheid sterk — kan dalen tot ver onder \(.50\) of zelfs negatief worden. Schaal lijkt onbetrouwbaar terwijl hij dat niet is — alleen één item wijst de andere kant op.

d) Bij kleine \(N\) of bij schalen met echte negatieve correlaties (onverwante constructen die toevallig in dezelfde dataset zitten) kan check.keys = TRUE ten onrechte items omkeren. Vuistregel: gebruik auto-detectie als diagnostiek, valideer altijd theoretisch — en vermeld in je rapport welke items zijn omgepoold en op basis van welk argument.

2.1.d Cronbach’s α — fitten en interpreteren

Algemene vorm.

# Snelle alpha + item-statistieken.
res <- psych::alpha(mijn_data[, items])
res$total       # alpha raw + std + andere globale maten
res$item.stats  # per item: raw.r, r.drop, mean, sd
res$alpha.drop  # alpha als item-eruit

Voor onze dieren.

# check.keys = FALSE zegt: pol niets voor me om. Dat staat hier met opzet zo,
# want je hebt item7 hierboven zelf al omgepoold -- zou psych het nóg eens
# doen, dan stond hij weer verkeerd.
# De uitkomst is geen los getal maar een pakketje met meer tabellen erin; met
# het dollarteken haal je er één uit ($total, $item.stats, $alpha.drop).
alpha_res <- psych::alpha(bos_dieren_piekeren[, items],
                          check.keys = FALSE)

# raw_alpha rekent met de ruwe item-varianties, std.alpha doet alsof elk item
# even zwaar weegt. Liggen die twee ver uit elkaar, dan verschillen je items
# sterk in spreiding. average_r is de gemiddelde correlatie tussen twee items.
# Die drie heb je nodig. G6(smc), S/N en ase komen er gratis bij omdat psych ze
# toch al uitrekent -- kijk er niet naar, ze vallen buiten dit hoofdstuk.
round(alpha_res$total[, c("raw_alpha", "std.alpha", "G6(smc)",
                          "average_r", "S/N", "ase")], 3)
 raw_alpha std.alpha G6(smc) average_r   S/N   ase
     0.868     0.869   0.864     0.399 6.644 0.014

Hieronder kies je vijf van de kolommen die psych heeft uitgerekend. Ook dat kan op twee manieren, en hier zit het verschil in de aanhalingstekens.

# Per item: raw.r is de item-totaal-correlatie, r.drop diezelfde correlatie
# maar met het item zelf uit het totaal gehaald, plus het gemiddelde en de SD.
# In [ , c("n", "raw.r", ...) ] staan de kolomnamen tussen aanhalingstekens:
# base R wil hier tekst, geen kale namen.
round(alpha_res$item.stats[, c("n", "raw.r", "r.drop", "mean", "sd")], 3)
                       n raw.r r.drop  mean    sd
item1_terugkijken    200 0.691  0.603 3.130 1.241
item2_nachtgedachten 200 0.702  0.614 3.100 1.272
item3_anderengedrag  200 0.584  0.458 3.135 1.427
item4_ergevoel       200 0.650  0.550 3.095 1.282
item5_zinloos        200 0.646  0.553 2.980 1.186
item6_loslaten       199 0.674  0.582 3.065 1.268
item7_doorzetten_REC 200 0.712  0.622 2.980 1.322
item8_zorgen         200 0.725  0.645 3.080 1.229
item9_terug          200 0.691  0.604 3.000 1.224
item10_aanwezigheid  200 0.701  0.615 2.915 1.243
# select() kiest kolommen, en daar mogen de namen kaal -- zonder
# aanhalingstekens, zonder c() eromheen. Dat is het hele verschil met de
# schrijfwijze links.
alpha_res$item.stats |>
  select(n, raw.r, r.drop, mean, sd) |>
  round(3)
                       n raw.r r.drop  mean    sd
item1_terugkijken    200 0.691  0.603 3.130 1.241
item2_nachtgedachten 200 0.702  0.614 3.100 1.272
item3_anderengedrag  200 0.584  0.458 3.135 1.427
item4_ergevoel       200 0.650  0.550 3.095 1.282
item5_zinloos        200 0.646  0.553 2.980 1.186
item6_loslaten       199 0.674  0.582 3.065 1.268
item7_doorzetten_REC 200 0.712  0.622 2.980 1.322
item8_zorgen         200 0.725  0.645 3.080 1.229
item9_terug          200 0.691  0.604 3.000 1.224
item10_aanwezigheid  200 0.701  0.615 2.915 1.243
# $alpha.drop heeft één regel per item, en op die regel staat wat alpha wordt
# als je juist dát item weglaat. Dus: hoger dan de alpha hierboven betekent
# "de schaal wordt beter zonder hem".
round(alpha_res$alpha.drop[, c("raw_alpha", "std.alpha", "average_r")], 3)
                     raw_alpha std.alpha average_r
item1_terugkijken        0.854     0.855     0.396
item2_nachtgedachten     0.853     0.854     0.394
item3_anderengedrag      0.867     0.867     0.419
item4_ergevoel           0.858     0.859     0.404
item5_zinloos            0.857     0.859     0.404
item6_loslaten           0.855     0.857     0.400
item7_doorzetten_REC     0.852     0.854     0.393
item8_zorgen             0.850     0.852     0.390
item9_terug              0.854     0.855     0.396
item10_aanwezigheid      0.853     0.854     0.395
NoteVragen 2.1.d

a) Wat is Cronbach’s \(\alpha\) (raw)? Past het bij de vooraf-voorspelling?

b) Welke item heeft de laagste \(r_{\text{drop}}\)? Wat zegt dat?

c) Als je dat zwakke item zou verwijderen, wat zou \(\alpha\) worden?

d) Stel je hebt een schaal met \(\alpha = .65\). Wat zijn je opties om hem te verbeteren?

a) \(\alpha_{\text{raw}} = .87\) — goed. Komt overeen met de vooraf-voorspelling op basis van \(k = 10\) en \(\bar{r} = .40\).

b) item3_anderengedrag: \(r_{\text{drop}} = .46\) — het laagste van de tien, tegen \(.55\) tot \(.65\) voor de rest. Het meet minder hetzelfde construct dan de andere items. Let op wat dat wél en niet betekent: de vuistregel hierboven legt de grens bij \(r_{\text{drop}} < .30\), en dit item zit daar ruim boven. Het is dus het zwakste van een stel goede items, geen kandidaat voor verwijdering. “Zwakst” is een rangorde, “te zwak” is een oordeel — die twee lopen in verslagen voortdurend door elkaar.

c) Uit de alpha.drop-output: \(\alpha\) zonder item3_anderengedrag wordt \(.8666\), tegen \(.8678\) nu. Dus niet hoger maar iéts lager. Item3 doet weinig kwaad omdat de schaal verder sterk is, maar voegt ook weinig toe. Bij een korte schaal zou verwijdering aanzienlijk effect hebben; bij \(k = 10\) nauwelijks.

d) Drie opties: (1) Items toevoegen — meer items met goede \(\bar{r}\) verhogen \(\alpha\) (\(\alpha\)-vs-\(k\)-formule). (2) Items verwijderen die niet samenhangen — kan helpen als ze de gemiddelde \(\bar{r}\) omhoog trekken. (3) Items herformuleren als de zwakte ligt aan vraagstelling, niet aan construct. Zonder nieuwe data: route 2 als snelste fix.

Inzicht. \(\alpha\) is niet een eigenschap van een schaal — het is een eigenschap van deze schaal in deze populatie. Bij een andere populatie (klinisch versus niet-klinisch, jongeren versus ouderen) kan \(\alpha\) anders uitkomen. Vandaar de verplichte vermelding “in this sample α = …”.

TipAPA-rapportage — Cronbach’s α in lopende tekst

De Bos-Piekeren-Schaal toonde goede internal consistency in deze steekproef (\(N = 200\) bosdieren), Cronbach’s α = .87, \(\bar{r} = .40\). Item-totaal-correlaties (gecorrigeerd) varieerden van \(r_{\text{drop}} = .46\) (item 3, “Ik vraag me af wat anderen van mij vinden”) tot \(r_{\text{drop}} = .65\) (item 8, “Ik maak me zorgen over de toekomst”). Geen enkel item verhoogde de α bij verwijdering.

ImportantDon’t: \(\alpha\) onder \(.60\) publiceren als “acceptabel”

Een schaal met \(\alpha = .58\) en de tekst “de internal consistency was acceptabel” — ik heb het in echte papers gezien, en het maakt me boos. Dat is geen acceptabele consistency. Dat is een schaal die niet meet wat hij beweert te meten in deze steekproef.

Je hebt twee opties: óf je herziet de schaal (items eruit, items erbij, andere bewoording), óf je rapporteert eerlijk dat de schaal in deze sample onbetrouwbaar was en interpreteert resultaten met grote voorzichtigheid. Je kunt niet een \(\alpha = .58\) rapporteren en doen alsof het een betrouwbaar instrument is.

Wie dat tóch doet — meestal omdat de deadline drukt en de reviewer streng is — bouwt een literatuur op getallen die niet meten wat ze beweren. Dat is wetenschappelijk vandalisme. “Ruw is Ruk”, en \(\alpha < .60\) ook.

T2 — Cronbach’s α handrekenen

NoteVraag T2 — Pen-en-papier

Een vragenlijst van \(5\) items heeft een gemiddelde inter-item-correlatie van \(\bar{r} = .30\).

a) Bereken \(\alpha_{\text{std}}\).

b) Wat als je \(5\) extra equivalente items toevoegt (\(k = 10\))?

c) Wat als je \(\bar{r}\) verhoogt naar \(.40\) bij \(k = 5\)?

d) Welk effect is groter — items toevoegen of items verbeteren?

a) \(\alpha = (5 \cdot .30) / (1 + 4 \cdot .30) = 1.50 / 2.20 \approx .68\). Twijfelachtig.

b) \(\alpha = (10 \cdot .30) / (1 + 9 \cdot .30) = 3.00 / 3.70 \approx .81\). Goed.

c) \(\alpha = (5 \cdot .40) / (1 + 4 \cdot .40) = 2.00 / 2.60 \approx .77\). Acceptabel.

d) Items toevoegen geeft hier het grotere effect (\(+.13\) vs \(+.09\)). De Spearman-Brown-formule (zie 2.2) maakt dit expliciet: bij gelijke item-kwaliteit kun je de schaal “beter” maken door hem langer te maken.

Inzicht. \(\alpha\) is een functie van twee dingen — schaal-lengte (\(k\)) en item-kwaliteit (\(\bar{r}\)). Bij ontwerp-keuzes: weeg af welke bijdrage haalbaar is.

2.2 Split-half + Spearman-Brown

Twee helften, één schaal

“Eerst halveren,” zei de wezel. “Items in twee groepen — als de twee groepen iets meten dat samenhangt, dan meten we hetzelfde.”

Idee: deel de schaal in twee gelijke helften, bereken twee aparte som-scores, correleer ze. Een hoge correlatie = beide helften meten hetzelfde. Probleem: de correlatie is lager dan \(\alpha\) omdat kortere schalen lagere reliability hebben. Spearman-Brown corrigeert hiervoor.

2.2.a Splitsen — Bens algoritme: matchen op gelijksoortige gemiddelden

Een naïeve splitsing (item \(1\)-\(5\) versus \(6\)-\(10\)) is gevoelig voor systematische verschillen tussen “vroege” en “late” items. Een betere aanpak: items paren op gelijksoortige gemiddelden, dan elk paar splitsen over de twee helften.

Bij Bens werkboek hoort een algoritme:

  1. Bereken voor elk item het gemiddelde.
  2. Maak een afstandsmatrix: \(|M_i - M_j|\) voor elk paar items.
  3. Selecteer iteratief het paar met de kleinste afstand. Markeer beide items als “gepaird”.
  4. Herhaal tot alle items in paren zitten.
  5. Verdeel binnen elk paar willekeurig over helft A en helft B.

Dit is eenvoudiger dan het klinkt. We doen het twee keer — één keer met de hand, één keer in R.

Toon code (item-pair-matching algoritme)
item_means <- sapply(bos_dieren_piekeren[, items], mean, na.rm = TRUE)

# Afstandsmatrix tussen item-means.
dist_matrix <- as.matrix(dist(item_means))
diag(dist_matrix) <- Inf  # eigen-afstand op Inf om zelf-paren te voorkomen.

# Iteratief paren maken.
paren <- list()
ongepairde <- seq_along(items)

set.seed(42)  # voor reproduceerbaarheid van de splitsing.
while (length(ongepairde) >= 2) {
  sub <- dist_matrix[ongepairde, ongepairde, drop = FALSE]
  # Vind paar met kleinste afstand.
  min_idx <- which(sub == min(sub), arr.ind = TRUE)[1, ]
  i <- ongepairde[min_idx[1]]
  j <- ongepairde[min_idx[2]]
  paren[[length(paren) + 1]] <- c(i, j)
  ongepairde <- setdiff(ongepairde, c(i, j))
}

# Splits paren over helft A en helft B (random).
helft_A <- helft_B <- integer(0)
for (p in paren) {
  if (runif(1) < 0.5) {
    helft_A <- c(helft_A, p[1]); helft_B <- c(helft_B, p[2])
  } else {
    helft_A <- c(helft_A, p[2]); helft_B <- c(helft_B, p[1])
  }
}

cat("Helft A:", items[helft_A], "\n")
Helft A: item5_zinloos item1_terugkijken item4_ergevoel item6_loslaten item9_terug 
Toon code (item-pair-matching algoritme)
cat("Helft B:", items[helft_B], "\n")
Helft B: item7_doorzetten_REC item3_anderengedrag item2_nachtgedachten item8_zorgen item10_aanwezigheid 
# Stel: helft A = items 1, 3, 5, 7, 9; helft B = items 2, 4, 6, 8, 10.
# (In praktijk laat je de matching-output beslissen — hier voor reproduceerbaarheid
# zo gefixeerd.)
helft_A <- c("item1_terugkijken",   "item3_anderengedrag",
             "item5_zinloos",       "item7_doorzetten_REC",
             "item9_terug")
helft_B <- c("item2_nachtgedachten","item4_ergevoel",
             "item6_loslaten",      "item8_zorgen",
             "item10_aanwezigheid")
# Twee scores per dier: het gemiddelde over zijn vijf items in helft A, en dat
# over zijn vijf in helft B.
bos_dieren_piekeren$score_A <- rowMeans(bos_dieren_piekeren[, helft_A], na.rm = TRUE)
bos_dieren_piekeren$score_B <- rowMeans(bos_dieren_piekeren[, helft_B], na.rm = TRUE)
# Binnen mutate() heeft rowMeans() een across() nodig om te weten welke
# kolommen hij moet middelen -- `helft_A` is een rijtje namen, en across()
# maakt daar de kolommen zelf van.
bos_dieren_piekeren <- bos_dieren_piekeren |>
  mutate(
    score_A = rowMeans(across(all_of(helft_A)), na.rm = TRUE),
    score_B = rowMeans(across(all_of(helft_B)), na.rm = TRUE)
  )
# use = "complete.obs" laat de dieren weg die op één van de twee helften geen
# score hebben. Zonder die regel geeft cor() gewoon NA terug, zonder te zeggen
# waaróm.
r_half <- cor(bos_dieren_piekeren$score_A,
              bos_dieren_piekeren$score_B,
              use = "complete.obs")
round(r_half, 3)
[1] 0.77
NoteVragen 2.2.a

a) Wat is de split-half-correlatie \(r_{\text{half}}\)?

b) Waarom is deze correlatie lager dan de Cronbach’s \(\alpha\) van de hele schaal?

c) Hoe verandert \(r_{\text{half}}\) als je items random over de helften verdeelt versus matched-pairs verdeelt?

d) Zou de split-half-correlatie hoger of lager worden als je een nieuwe ronde van paren maakt?

a) \(r_{\text{half}} = .77\) voor déze splitsing. De twee helften hangen sterk samen. Zet er “voor deze splitsing” bij: een andere verdeling van de tien items over twee helften geeft een ander getal, en hoeveel het scheelt zie je in 2.2.c.

b) Lager omdat elk van de twee helften korter is dan de hele schaal. Bij gelijke \(\bar{r}\) daalt \(\alpha\) met \(k\). De full-scale \(\alpha\) kun je terugkrijgen met de Spearman-Brown-correctie (zie 2.2.b).

c) Random: meer variabel; soms verkrijg je toevallig sterke helften, soms zwakke. Matched-pairs: stabieler, want extreme items (te makkelijk of te moeilijk) worden over beide helften verdeeld in plaats van geconcentreerd.

d) Variabel — een andere splitsing geeft een andere \(r_{\text{half}}\). Vandaar dat psych::splitHalf() alle mogelijke splitsingen berekent en het gemiddelde + min/max rapporteert.

Inzicht. Een enkele split-half is één getal uit een verdeling van mogelijke splits. Echte robuustheid: rapporteer de gemiddelde split-half over alle paren (zie 2.2.c) of gebruik direct \(\alpha\).

2.2.b Spearman-Brown — corrigeren naar volledige schaal-lengte

De Spearman-Brown-formule corrigeert \(r_{\text{half}}\) naar de betrouwbaarheid die de schaal als geheel zou hebben (alsof beide helften samen worden gebruikt):

\[ r_{\text{SB}} = \frac{2 \cdot r_{\text{half}}}{1 + r_{\text{half}}} \]

Algemener (voor verlenging met factor \(n\) in plaats van \(2\)):

\[ r_{\text{SB}} = \frac{n \cdot r}{1 + (n - 1) \cdot r} \]

Dezelfde formule die we gebruikten voor \(\alpha_{\text{std}}\) — dat is geen toeval. Beide steunen op het idee dat een langere schaal van equivalente items betrouwbaarder is per definitie.

r_half <- cor(bos_dieren_piekeren$score_A,
              bos_dieren_piekeren$score_B,
              use = "complete.obs")

# De formule met n = 2 ingevuld: je maakt de schaal twee keer zo lang als één
# helft, en dus weer even lang als hij oorspronkelijk was. Vandaar de 2 en niet
# de 10 -- je rekent van een halve schaal naar een hele, niet van één item naar
# tien.
r_SB <- 2 * r_half / (1 + r_half)
round(c(r_half = r_half, r_SB = r_SB), 3)
r_half   r_SB 
  0.77   0.87 
NoteVraag T3 — Spearman-Brown handrekenen

Voor elk geval: bereken \(r_{\text{SB}}\) en interpreteer.

a) \(r_{\text{half}} = .60\).

b) \(r_{\text{half}} = .85\).

c) \(r_{\text{half}} = .40\) — wat zegt \(r_{\text{SB}}\) over de volledige schaal?

d) Een onderzoeker meldt \(r_{\text{SB}} = .92\) na split-half. Wat is dan ongeveer \(r_{\text{half}}\) geweest?

a) \(r_{\text{SB}} = 2 \cdot .60 / (1 + .60) = 1.20 / 1.60 = .75\).

b) \(r_{\text{SB}} = 2 \cdot .85 / (1 + .85) = 1.70 / 1.85 \approx .92\).

c) \(r_{\text{SB}} = 2 \cdot .40 / (1 + .40) = .80 / 1.40 \approx .57\). Twijfelachtig — ondanks correctie blijft het onder \(.70\). Schaal werkt niet goed in deze steekproef.

d) Inverteren: \(r_{\text{half}} = r_{\text{SB}} / (2 - r_{\text{SB}}) = .92 / 1.08 \approx .85\).

Inzicht. Spearman-Brown is een lineaire transformatie die rekening houdt met schaal-verlenging. Geen wonder, geen tovenaarskunst — gewoon de wiskundige consequentie van het feit dat langere schalen meer signaal vangen ten opzichte van ruis.

2.2.c Robuuste split-half — alle splits in één keer

# raw = TRUE laat hem elke afzonderlijke splitsing bewaren in plaats van alleen
# de samenvatting. Dat kost geheugen, maar zonder die schakelaar kun je de
# verdeling van uitkomsten niet zelf natellen -- en juist die verdeling is hier
# het punt.
sh_res <- psych::splitHalf(bos_dieren_piekeren[, items],
                           use = "complete.obs",
                           raw = TRUE)
sh_res
Split half reliabilities  
Call: psych::splitHalf(r = bos_dieren_piekeren[, items], raw = TRUE, 
    use = "complete.obs")

Maximum split half reliability (lambda 4) =  0.9
Guttman lambda 6                          =  0.86
Average split half reliability            =  0.87
Guttman lambda 3 (alpha)                  =  0.87
Guttman lambda 2                          =  0.87
Minimum split half reliability  (beta)    =  0.83
Average interitem r =  0.4  with median =  0.4
                                             2.5% 50% 97.5%
 Quantiles of split half reliability      =  0.84 0.87 0.89
NoteVragen 2.2.c

a) Wat is het gemiddelde van alle mogelijke split-halfs?

b) Wat zijn min en max?

c) De output zet als eerste regel de maximale split-half neer, en verderop het gemiddelde, het minimum en de quantielen. Waarom is dat spreidings-beeld nuttiger dan één enkel getal? En waarom zou je juist die eerste regel niet rapporteren?

d) Hoe verhoudt het gemiddelde split-half zich tot de Cronbach’s \(\alpha\) die je in 2.1.d hebt gefit?

a) \(\bar{r}_{\text{SH}} = .87\) — congruent met \(\alpha\).

b) Min \(= .83\), max \(= .90\), over 126 mogelijke splitsingen. Tussen de ongelukkigste en de gelukkigste splitsing zit dus \(.07\) — en het enige wat verschilt is wélke items in welke helft belanden.

c) Omdat één split-half één trekking uit die verdeling is. Het gemiddelde en de quantielen laten zien hoeveel je getal had kunnen schelen; het minimum waarschuwt je voor de ongelukkigste verdeling. De eerste regel van de output — “Maximum split half reliability (lambda 4)” — is juist de gunstigste splitsing van allemaal, uit 126 gekozen omdat hij het hoogste uitkwam. Die rapporteren is jezelf het beste lot uitdelen en dat de betrouwbaarheid van je schaal noemen. Rapporteer het gemiddelde, of \(\alpha\).

d) Bij schalen die goed werken liggen \(\bar{r}_{\text{SH}}\) en \(\alpha\) dicht bij elkaar (verschil \(< .02\)). Bij divergentie (\(> .05\)): vaak een teken van schaal-heterogeniteit (meerdere subschalen vermengd).

Inzicht. Cronbach’s \(\alpha\) is wiskundig gelijk aan het gemiddelde van alle mogelijke split-halfs (Cronbach 1951) — mits je elke split-half berekent met de Rulon-Flanagan-formule (\(1\) min de variantie van het verschil tussen de twee helften, gedeeld door de variantie van de somscore) en de helften even lang zijn. Dat is geen benadering maar een identiteit, en je ziet hem in de output hierboven staan: “Average split half reliability” en “Guttman lambda 3 (alpha)” zijn daar niet ongeveer gelijk maar tot op 16 decimalen hetzelfde getal. En dat terwijl de item-standaarddeviaties in deze schaal uiteenlopen van \(1.19\) tot \(1.43\). Gelijke item-varianties zijn dus géén voorwaarde.

En de andere route dan? In 2.2.a en 2.2.b heb je de split-half anders berekend: als Pearson-\(r\) tussen de twee helften, met Spearman-Brown erachteraan. Doe je dát voor alle 126 splitsingen en neem je het gemiddelde, dan kom je op \(.8682\) tegen \(\alpha = .8680\) — dat scheelt .0002. Dus: bij de Rulon-Flanagan-rekenwijze is de gelijkheid exact, bij de Spearman-Brown-route klopt ze bij benadering. Het is dezelfde schaal en dezelfde splitsingen; alleen de rekenwijze verschilt.

2.A Item-deletie — helpt het hier?

Welke items kunnen weg?

“Eerst kijken naar wie er minder bijdraagt,” zei de wezel. “Dan kijken we of we hem kunnen missen.”

Twee handelingen, en de wezel zet ze niet voor niets uit elkaar. Het zwakste item aanwijzen is de eerste. Nagaan of de schaal zonder dat item beter wordt, is de tweede — en het antwoord daarop kan gewoon nee zijn. Dat is geen mislukte analyse maar een uitkomst.

Je doet ze allebei, in deze volgorde.

# Welke items hebben de laagste r.drop? order() geeft je niet de gesorteerde
# waarden maar de PLEKKEN in de gesorteerde volgorde: order(c(30, 10, 20))
# wordt 2 3 1, want de kleinste staat op plek 2. Die plekken zet je dan vóór de
# komma tussen de blokhaken, en zo staan de rijen op orde.
item_stats <- alpha_res$item.stats[, c("raw.r", "r.drop", "mean", "sd")]
round(item_stats[order(item_stats$r.drop), ], 3)
                     raw.r r.drop  mean    sd
item3_anderengedrag  0.584  0.458 3.135 1.427
item4_ergevoel       0.650  0.550 3.095 1.282
item5_zinloos        0.646  0.553 2.980 1.186
item6_loslaten       0.674  0.582 3.065 1.268
item1_terugkijken    0.691  0.603 3.130 1.241
item9_terug          0.691  0.604 3.000 1.224
item2_nachtgedachten 0.702  0.614 3.100 1.272
item10_aanwezigheid  0.701  0.615 2.915 1.243
item7_doorzetten_REC 0.712  0.622 2.980 1.322
item8_zorgen         0.725  0.645 3.080 1.229

Sorteren is de plek waar dplyr het duidelijkst korter is. Je noemt de kolom en klaar; die tussenstap met plekken hoeft niet.

# arrange() zet de rijen op orde, van klein naar groot. Voor andersom zet je
# desc() om de kolom: arrange(desc(r.drop)).
alpha_res$item.stats |>
  select(raw.r, r.drop, mean, sd) |>
  arrange(r.drop) |>
  round(3)
                     raw.r r.drop  mean    sd
item3_anderengedrag  0.584  0.458 3.135 1.427
item4_ergevoel       0.650  0.550 3.095 1.282
item5_zinloos        0.646  0.553 2.980 1.186
item6_loslaten       0.674  0.582 3.065 1.268
item1_terugkijken    0.691  0.603 3.130 1.241
item9_terug          0.691  0.604 3.000 1.224
item2_nachtgedachten 0.702  0.614 3.100 1.272
item10_aanwezigheid  0.701  0.615 2.915 1.243
item7_doorzetten_REC 0.712  0.622 2.980 1.322
item8_zorgen         0.725  0.645 3.080 1.229
# Alpha als elk item eruit gaat. Het minteken vóór de kolom draait de richting
# om, zodat de hoogste alpha-na-weglaten bovenaan komt -- want dát is het item
# waar de vraag over gaat. In dplyr zou je hier arrange(desc(raw_alpha))
# schrijven.
ad <- alpha_res$alpha.drop[, c("raw_alpha", "std.alpha")]
ad <- ad[order(-ad$raw_alpha), ]
round(ad, 3)
                     raw_alpha std.alpha
item3_anderengedrag      0.867     0.867
item4_ergevoel           0.858     0.859
item5_zinloos            0.857     0.859
item6_loslaten           0.855     0.857
item1_terugkijken        0.854     0.855
item9_terug              0.854     0.855
item10_aanwezigheid      0.853     0.854
item2_nachtgedachten     0.853     0.854
item7_doorzetten_REC     0.852     0.854
item8_zorgen             0.850     0.852
NoteVragen 2.A

a) Welk item heeft de laagste \(r_{\text{drop}}\)? Wordt \(\alpha\) daadwerkelijk hoger als je het verwijdert?

b) Je hebt bij a) gezien wat er in déze schaal gebeurt. Stel nu even het tegenovergestelde, bij een andere vragenlijst — acht items, \(\alpha = .79\), en weglaten van één item tilt hem naar \(.80\). Zou je het doen?

c) In welk geval zou je een zwak item toch in de schaal houden?

d) Wat is het verschil tussen “het item is een zwak item” en “het item meet iets anders”?

a) item3_anderengedrag heeft de laagste \(r_{\text{drop}}\), namelijk \(.46\). Maar op de tweede vraag is het antwoord nee: verwijder je het, dan gaat \(\alpha\) van \(.8678\) naar \(.8666\) — omlaag dus, niet omhoog. Sterker nog: in deze schaal verhoogt geen enkel van de tien items de \(\alpha\) als je het weghaalt (de hoogste alpha.drop is \(.8666\), nog altijd onder de huidige \(\alpha\)). Dat is precies waarom deze vraag zo staat: het zwakste item aanwijzen is één handeling, en nagaan of weghalen echt helpt is een tweede. Wie de eerste voor de tweede aanziet, gooit items weg die de schaal beter maakten.

b) Niet zomaar — en let op dat dit een gedachte-experiment is bij een andere lijst dan die van ons; in onze schaal stijgt \(\alpha\) bij geen enkel item. Zeven items met \(\alpha = .80\) tegen acht met \(\alpha = .79\): een kortere schaal die even betrouwbaar meet is winst, want je vraagt je respondent minder. Maar er staat iets tegenover. Dekt dat achtste item een deel van het construct dat de andere zeven niet raken, dan koop je één honderdste \(\alpha\) met een gat in je inhoudelijke dekking. Vraag dus eerst: meet dit item iets dat ik theoretisch belangrijk vind? Zo ja: laten staan, ook bij een lagere \(r_{\text{drop}}\). Een schaal is geen getal dat je maximaliseert.

c) Drie redenen om een zwak item te houden: (1) theoretische dekking — het item meet een aspect dat anders niet wordt gedekt. (2) face-validiteit — of de lijst er voor de invuller uitziet alsof hij meet wat hij beweert te meten. Haal je er de enige vraag uit die een respondent met het onderwerp verbindt, dan krijg je een schaal die vreemd aanvoelt om in te vullen, en dat kost je serieuze antwoorden. (3) historische continuïteit — items meenemen zodat je met eerdere studies kunt vergelijken.

d) Zwak item: meet hetzelfde construct, maar minder duidelijk (meer ruis). Item meet iets anders: zit op een ander construct of factor. Onderscheid via factoranalyse (komt thema 4 PCA, thema 5 CFA) — bij een multi-dimensionele schaal zijn er meerdere subschalen, en de “zwakheid” kan eigenlijk een andere subschaal blootleggen.

Inzicht. \(\alpha\) vooronderstelt één onderliggende factor. Bij multi-dimensionele schalen onderschat \(\alpha\) de werkelijke betrouwbaarheid van een subschaal. Vandaar dat na alpha-analyse vaak een EFA/CFA volgt (zie thema 4-5).

Dezelfde vraag, andere schaal — de egels

Bij de bosdieren was het antwoord nee. Dat is de gewone uitkomst bij een stel items dat al goed loopt, maar je moet het andere geval één keer van dichtbij hebben gezien, anders herken je het niet als het langskomt.

Een tweede onderzoeker legde 143 egels een korte lijst voor over doorzettingsvermogen — de Egel-Doorzet-Schaal, zes items op een \(5\)-puntsschaal.

kolom de vraag zoals de egel hem las
item1_opnieuw “Als iets niet meteen lukt, probeer ik het nog een keer.”
item2_afmaken “Ik maak af waar ik aan begin.”
item3_andereweg “Loopt het vast, dan zoek ik een andere weg.”
item4_volhouden “Ik houd vol, ook als het lang duurt.”
item5_nietafgeschrikt “Een moeilijke klus schrikt me niet af.”
item6_alleenwerken “Ik werk het liefst alleen.”

Kijk eerst naar die zes zinnen, vóór je iets uitrekent. Vijf ervan vragen naar hetzelfde: blijf je doorgaan als het tegenzit? De zesde vraagt naar iets anders — of je gezelschap prettig vindt bij het werk. Je kunt je voorstellen hoe hij op de lijst is gekomen; wie volhoudt redt zich vaak alleen wel. Maar volhouden en liever alleen zijn twee eigenschappen, en een egel kan de ene hebben zonder de andere.

Dat is een inhoudelijk vermoeden. Nu de cijfers.

load("data/egels_doorzetten.RData")

eds_items <- c("item1_opnieuw", "item2_afmaken", "item3_andereweg",
               "item4_volhouden", "item5_nietafgeschrikt", "item6_alleenwerken")

# check.keys = FALSE ook hier: je wil zien wat de schaal doet zoals hij is
# opgeschreven. Zou psych zelf gaan ompolen, dan repareert hij precies het
# probleem dat je wil bekijken.
alpha_eds <- psych::alpha(egels_doorzetten[, eds_items], check.keys = FALSE)

# Dezelfde drie tabellen als bij de bosdieren, in dezelfde volgorde: eerst de
# schaal als geheel, dan per item, dan wat elk item weglaten zou doen.
round(alpha_eds$total[, c("raw_alpha", "std.alpha", "average_r")], 3)
 raw_alpha std.alpha average_r
     0.762     0.764      0.35
round(alpha_eds$item.stats[, c("raw.r", "r.drop", "mean", "sd")], 3)
                      raw.r r.drop  mean    sd
item1_opnieuw         0.722  0.564 3.322 1.303
item2_afmaken         0.712  0.548 2.720 1.318
item3_andereweg       0.759  0.630 3.622 1.203
item4_volhouden       0.722  0.564 3.063 1.312
item5_nietafgeschrikt 0.751  0.605 3.385 1.305
item6_alleenwerken    0.397  0.160 2.951 1.296
round(alpha_eds$alpha.drop[, c("raw_alpha", "std.alpha")], 3)
                      raw_alpha std.alpha
item1_opnieuw             0.712     0.713
item2_afmaken             0.716     0.718
item3_andereweg           0.696     0.696
item4_volhouden           0.712     0.713
item5_nietafgeschrikt     0.700     0.703
item6_alleenwerken        0.812     0.812
NoteVragen 2.A — vervolg

e) Welk item heeft hier de laagste \(r_{\text{drop}}\)? Klopt dat met wat je uit de zes zinnen voorspelde?

f) Wordt \(\alpha\) hoger als je dat item weglaat? Hoeveel, en zou je het doen?

e) item6_alleenwerken, met \(r_{\text{drop}} = .16\). De andere vijf zitten tussen \(.55\) en \(.63\) — dat is geen rangorde met een staartje, dat is één item dat er los van staat. En het is precies het item dat je op inhoud al had aangewezen. Dat is de prettige uitkomst: de statistiek bevestigt hier een vermoeden dat je zonder rekenen ook al had.

f) Ja. \(\alpha\) gaat van \(.7624\) naar \(.8116\) — een winst van \(.0492\). En hier vallen de twee bezwaren weg die je normaal tegen weghalen inbrengt. Het eerste is inhoudelijke dekking: haal je een item weg, dan verlies je meestal een stukje van wat je wilde meten. Hier niet — dit item meet doorzettingsvermogen juist níét, dus er valt niets weg. Het tweede is schaallengte: korter meten is meestal onbetrouwbaarder meten. Hier ook niet, want \(\alpha\) gaat omhoog en niet omlaag. Weghalen dus — met in je verslag de reden erbij, en die reden is “dit item meet een ander construct”, niet \(\alpha\) ging omhoog”.

Let op de \(r_{\text{drop}}\), niet op de winst. Die \(.16\) is positief, en dat is geen detail. Was hij negatief geweest, dan had je met een ongepoold item te maken en was het antwoord ompolen — zie 2.1.b — en niet weggooien. Een negatief item is niet waardeloos; het staat achterstevoren.

TipWelk van de twee gevallen heb je voor je?

Je hebt nu allebei gezien, op echte uitvoer:

waar je naar kijkt Bos-Piekeren-Schaal Egel-Doorzet-Schaal
aantal items 10 6
\(\alpha\) \(.8678\) \(.7624\)
laagste \(r_{\text{drop}}\) \(.46\) \(.16\)
beste \(\alpha\) na weglaten \(.8666\) \(.8116\)
verandering in \(\alpha\) \(-.0012\) (omlaag) \(+.0492\) (omhoog)
wat je doet laten staan dat ene item eruit

De vuistregel: kijk naar de item-restcorrelatie, niet naar de winst. De winst vertelt je pas achteraf iets, en hij verleidt je tot vissen — laat er eentje weg, kijk of het getal omhoog gaat, herhaal. Zo bouw je een schaal die op jouw steekproef mooi rekent en op de volgende niet meer.

De \(r_{\text{drop}}\) vertelt je waarom. Zit een item onder de \(.30\) terwijl de rest er ruim boven zit, dan meet het iets anders, en dan heb je een inhoudelijk verhaal dat je kunt opschrijven en verdedigen. Zitten alle items boven de \(.30\), zoals bij de bosdieren, dan is er geen zwak item — dan is er een zwákste, en dat is een rangorde en geen oordeel.

En verwacht de eerste situatie vaker dan de tweede. In Leidens eigen college komt bij de schaal Need for Cognition dezelfde uitkomst langs, met dezelfde toelichting erbij: geen enkel item eruit, want alle item-totaalcorrelaties zijn duidelijk positief en geen enkel item maakt \(\alpha\) kleiner. Krijg jij dat resultaat, dan is er niets misgegaan. Je hebt gekeken, en dat is de handeling.

T4 — KR-20 versus α (binaire items)

NoteVraag T4 — Pen-en-papier

KR-20 (Kuder-Richardson formula 20) is de variant van \(\alpha\) voor binaire items (0/1, juist/onjuist).

a) Wat is het structurele verschil tussen \(\alpha\) en KR-20?

b) Wat gebeurt er als je \(\alpha\) uitrekent op binaire items?

c) In welke situatie kies je KR-20 boven \(\alpha\)?

d) Heeft psych::alpha() automatische KR-20-detectie?

a) \(\alpha\) neemt continue items aan (Likert, intervalschaal). KR-20 is identiek aan \(\alpha\) maar gespecialiseerd voor binaire items: vervangt itemvariantie door \(p_i \cdot q_i\) (waar \(p\) = proportie correct, \(q = 1 - p\)). Wiskundig zijn ze dezelfde formule — KR-20 is gewoon \(\alpha\) toegepast op \(0/1\)-items.

b) Hetzelfde resultaat. Op binaire items reduceert \(\alpha\)-formule naar KR-20. Geen verschil — andere naam, dezelfde berekening.

c) Geen praktische keuze meer in moderne software. Conventie blijft: bij binaire (juist/onjuist, ja/nee) items rapporteer je KR-20; bij Likert Cronbach’s \(\alpha\). Inhoudelijk dezelfde maat.

d) Ja — psych::alpha() werkt op binaire én continue data. Je hoeft niet expliciet KR-20 te kiezen.

Inzicht. KR-20 is een historisch artefact uit de tijd vóór computers. Vandaag: gewoon \(\alpha\). Ken de term voor papers uit de jaren \(1950\)-\(1980\).

T5 — Item-totaal-correlatie interpretatie

NoteVraag T5 — Pen-en-papier

In een schaal-analyse rapporteert een onderzoeker:

Item   raw.r   r.drop
A      0.60    0.50
B      0.75    0.65
C      0.55    0.40
D      0.85    0.80

a) Welke item is het sterkst gerelateerd aan de totaalscore?

b) Welke is het zwakst?

c) Wat is het verschil tussen raw.r en r.drop?

d) Welke moet je primair rapporteren?

a) Item D (\(r_{\text{drop}} = .80\)) — sterkst.

b) Item C (\(r_{\text{drop}} = .40\)) — zwakst.

c) raw.r: correlatie tussen item en totaalscore inclusief het item zelf. r.drop: correlatie tussen item en totaalscore zonder het item (gecorrigeerde item-totaal-correlatie). De r.drop is altijd lager dan raw.r omdat het zelf-effect is verwijderd.

d) r.drop — anders is de correlatie kunstmatig opgeblazen door het zelf-effect (item correleert met zichzelf via de som-score).

Vuistregel. Items met \(r_{\text{drop}} < .30\) zijn kandidaat voor herziening of verwijdering. \(r_{\text{drop}} \geq .50\) is goed.

T6 — Item-deletie en α-verbetering

NoteVraag T6 — Pen-en-papier

Een schaal met \(k = 5\) items heeft \(\alpha = .65\). De alpha.drop-output toont:

Item drop   alpha-na-deletie
A             .70
B             .60
C             .55
D             .62
E             .68

a) Welk item is het zwakste — verwijdering geeft de grootste \(\alpha\)-stijging?

b) Welk item is het sterkste — verwijdering geeft de grootste \(\alpha\)-daling?

c) Stel je verwijdert item A. Wat is de nieuwe \(\alpha\) + nieuwe schaallengte?

d) Is het altijd een goed idee om het zwakste item te verwijderen?

a) Item A — verwijdering verhoogt \(\alpha\) van \(.65\) naar \(.70\). Sterkste verbetering.

b) Item C — verwijdering verlaagt \(\alpha\) naar \(.55\). Sterkste daling = sterkste bijdrage aan schaal.

c) Nieuwe \(\alpha = .70\), \(k = 4\). Iets minder data, iets betere internal consistency.

d) Nee — drie tegenargumenten: (1) Content-validiteit kan verloren gaan. (2) \(\alpha\) kan stabieler zijn met meer items ondanks lagere \(r\). (3) Verlies van power voor follow-up-toetsen omdat schaal-variantie daalt.

Inzicht. \(\alpha\)-stijging is één criterium, niet het criterium. Theoretische verdediging blijft de beste basis voor item-keuze.

T7 — Wat is een “goede” α?

NoteVraag T7 — Pen-en-papier

Voor elk gebruik: welke \(\alpha\)-drempel is gepast?

a) Een onderzoeker gebruikt een schaal als groep-niveau-uitkomst in een experiment.

b) Een psychiater gebruikt een schaal-score om individuele beslissingen over medicatie te nemen.

c) Een student gebruikt een nieuwe schaal in haar bachelorscriptie, voor exploratief onderzoek.

d) Een toegelaten testbatterij voor neuropsychologische diagnose.

a) \(\alpha \geq .70\). Bij groepsniveau-vergelijkingen middelen ruisstoringen uit; iets hogere ondergrens dan strikte \(.80\) niet absolute eis.

b) \(\alpha \geq .90\). Individueel-niveau-beslissingen vereisen lage measurement-error per persoon. \(se_{\text{m}} = SD \cdot \sqrt{1 - \alpha}\) — bij lage \(\alpha\) is \(se_{\text{m}}\) groot, en individuele scores onbetrouwbaar.

c) \(\alpha \geq .70\) als doel. Bij nieuwe schaal in exploratie kan \(\alpha = .60\)-\(.70\) acceptabel zijn als alle andere items goed werken; rapporteer met expliciete waarschuwing.

d) \(\alpha \geq .90\), ofwel reëel \(> .85\) met grote \(N\) + diverse populatie. Diagnostiek vereist ondergrens hoog.

Inzicht. Hoe hoger de individuele consequentie, hoe hoger de \(\alpha\)-eis. Groepsniveau-onderzoek mag iets soepeler; individuele beslissingen vereisen strenger.

T8 — De standaardmeetfout

Tot nu toe ging alles over de schaal: is die betrouwbaar genoeg. De standaardmeetfout standard error of measurement vertaalt dat naar één persoon. Hij zegt hoe ver iemands geobserveerde score gemiddeld naast zijn ware score valt — en dus hoe breed de band is waarbinnen je die ware score mag vermoeden.

\[ se_{\text{m}} = SD \cdot \sqrt{1 - \alpha} \]

Een betrouwbare schaal (\(\alpha\) dicht bij \(1\)) laat weinig over onder dat wortelteken, en dan is de fout klein. Kijk wat er aan de uiterste gebeurt: een schaal die niks meet heeft \(\alpha = 0\), en dan is \(\sqrt{1 - 0} = 1\), dus \(se_{\text{m}} = SD\). Bij \(SD = 10\) wordt de band rond een score dan \(\pm 1.96 \cdot 10\), oftewel bijna \(40\) punten breed — even breed als de hele groep. Die ene score vertelt je dan niets meer dan de groep zelf.

TipWaarom kleine letters, en niet SEM

Er zijn twee “standaardfouten” die op elkaar lijken en over verschillende dingen gaan. De standaardfout van het gemiddelde zegt hoe ver een steekproefgemiddelde naast het populatiegemiddelde ligt — dat gaat over een gemiddelde van veel mensen. De standaardmeetfout gaat over de score van één persoon. En allebei worden ze SEM afgekort — sterker nog, in thema 4 en 5 staan dezelfde drie letters voor weer iets anders.

Die drie letters zeggen je dus niet wat er bedoeld wordt. Een subscript wel, en dat is waarom dit hoofdstuk \(se_{\text{m}}\) schrijft en niet SEM. Ben, over een formuleblad dat wél een kale \(s\) liet staan: “dat zou de s van de error moeten zijn — met dat e’tje eronder. Niet verwarren met de standaard error, dat is iets anders.”

Je neemt een formuleblad mee het tentamen in, en daar staat deze som met andere symbolen:

\[ se_{\text{m}} = s_{\text{e}} = s_{\text{o}} \sqrt{1 - R_{xx}} \]

Dat is geen andere formule maar dezelfde, in de algemene notatie. Van links naar rechts, na de \(se_{\text{m}}\) die je al kent:

  • \(s_{\text{e}}\) — de s van de error: de standaardafwijking van de meetfouten. Dat ís de standaardmeetfout, niet iets wat eraan gelijk blijkt te zijn; het gelijkteken staat er omdat het twee namen voor één ding zijn.
  • \(s_{\text{o}}\) — de s van de observed scores: de standaardafwijking van de scores zoals je ze gemeten hebt. Dat is wat wij \(SD\) noemen. Let op wélke: bij een schaal is dat de \(SD\) van de somscore over alle items, niet die van een los item.
  • \(R_{xx}\) — de betrouwbaarheid van de test, hóé je hem ook geschat hebt: met split-half, met test-hertest, of met Cronbach’s \(\alpha\). In dit hoofdstuk schatten we hem met \(\alpha\), dus daar mag je \(\alpha\) invullen.

Zie je op het tentamen \(R_{xx} = .80\) staan, dan is dat dus hetzelfde getal als de \(\alpha = .80\) in de opgave hierna.

NoteVraag T8 — Pen-en-papier

Voor een schaal met \(SD = 10\) en \(\alpha = .80\):

a) Bereken \(se_{\text{m}}\).

b) Een persoon scoort \(X = 65\) op T-score-schaal. Wat is het \(95\%\)-betrouwbaarheidsinterval rond zijn ware score?

c) Bij \(\alpha = .95\) wat zou \(se_{\text{m}}\) worden? En het CI?

d) Welke implicatie heeft een hoge \(se_{\text{m}}\) voor klinische beslissingen?

a) \(se_{\text{m}} = 10 \cdot \sqrt{1 - .80} = 10 \cdot \sqrt{0.20} = 10 \cdot 0.4472 = 4.472 \approx 4.47\).

b) \(95\%\)-CI: \(X \pm 1.96 \cdot se_{\text{m}} = 65 \pm 1.96 \cdot 4.472 = 65 \pm 8.77 = [56.23, 73.77]\). Brede band. Die \(1.96\) is de \(z\)-waarde die \(95\) procent van een normale verdeling tussen zich in heeft.

c) Bij \(\alpha = .95\): \(se_{\text{m}} = 10 \cdot \sqrt{1 - .95} = 10 \cdot \sqrt{0.05} = 10 \cdot 0.2236 = 2.236 \approx 2.24\). CI: \(X \pm 1.96 \cdot 2.236 = 65 \pm 4.38 = [60.62, 69.38]\). Aanzienlijk smaller.

d) Bij hoge \(se_{\text{m}}\): de score van een individu is een schatting met grote onzekerheid. Cliënt scoort \(T = 65\) (\(\alpha = .80\)): we zijn \(95\%\) zeker dat zijn echte T-score tussen \(56\) en \(74\) ligt — dat valt deels onder en deels boven de “verhoogd”-cutoff. Klinische beslissing op zo’n schatting is gevaarlijk.

Inzicht. \(\alpha\) rapporteren zonder \(se_{\text{m}}\) erbij is incompleet. De standaardmeetfout vertaalt \(\alpha\) naar wat het betekent voor de individuele score. Voor klinisch gebruik altijd allebei rapporteren.

T9 — Reliability bij kleine n

NoteVraag T9 — Pen-en-papier

Een onderzoeker meet bij \(N = 30\) deelnemers een \(5\)-item-schaal en rapporteert \(\alpha = .82\).

a) Wat is je voornaamste zorg?

b) Wat is een redelijke methode om de onzekerheid te kwantificeren?

c) Stel het \(95\%\)-bootstrap-CI is \([.65, .92]\). Wat zegt dat?

d) Mag deze schaal gebruikt worden voor klinische beslissingen?

a) Steekproef-grootte \(N = 30\) is te klein voor stabiele \(\alpha\)-schatting. Vuistregel: \(N \geq 100\) voor schaal-validatie. Bij \(N = 30\) is het CI rond \(\alpha\) breed; één getal is misleidend.

b) Bootstrap-CI rond \(\alpha\). psych::alpha(mijn_data[, items], n.iter = 1000) of een eigen bootstrap; het interval staat daarna in res$boot.ci. Geeft een interval in plaats van een puntschatting.

c) Het CI loopt van \(.65\) (twijfelachtig) tot \(.92\) (uitstekend). De ware \(\alpha\) kan dus overal in dat bereik liggen. Het puntschattings-getal \(.82\) overdrijft de zekerheid.

d) Nee, niet zonder grotere validatie-studie. Bij \(N = 30\) en deze brede onzekerheid is klinisch gebruik onverantwoord. Onderzoek-gebruik op groepsniveau (met expliciete waarschuwing): mogelijk.

Inzicht. \(\alpha\) als puntschatting verbergt de onzekerheid. Bij kleine \(N\) rapporteer je het bootstrap-CI mee.

T10 — Test-retest versus internal consistency

NoteVraag T10 — Pen-en-papier

Een schaal heeft \(\alpha = .92\) (excellent internal consistency) maar \(r_{\text{retest}} = .55\) (test-retest, \(6\) weken interval).

a) Wat suggereert dit patroon over de schaal?

b) Welke factor kan dit verklaren?

c) Welk type reliability is voor trait-meting belangrijker?

d) Welk type voor state-meting?

a) De schaal meet iets consistents binnen een meetmoment (alle items hangen sterk samen) maar dat ene-iets is niet stabiel over tijd (\(r_{\text{retest}} = .55\) is matig).

b) Drie verklaringen: (1) State-construct — de schaal meet iets dat fluctueert (bv. acute angst, momentane stemming). Internal consistency is hoog (op één moment); retest is laag (op twee momenten). (2) Echte verandering — bv. interventie tussen \(t_0\) en \(t_1\). (3) Meet-instrument-instabiliteit — onwaarschijnlijk bij hoge \(\alpha\), want dan zou de within-moment-meting ook ruisen.

c) Test-retest — een trait is per definitie stabiel; meet-instrument moet die stabiliteit reproduceren.

d) Internal consistency — een state is per definitie fluctuatie; binnen-moment-stabiliteit is wat je test, niet over-tijd-stabiliteit.

Inzicht. \(\alpha\) alleen vertelt het verhaal niet. Voor traits: \(\alpha\) + test-retest. Voor states: \(\alpha\) + (eventueel) experience sampling reliability.

Examen-stijl vragen

Vier kortere oefeningen plus één mini-practical

NoteVraag E1 — α-output interpreteren
Reliability analysis (psych::alpha)
  raw_alpha  std.alpha   G6(smc)   average_r
       0.78       0.79      0.81        0.43

Item statistics (per item):
       n   raw.r   r.drop
i1   200    0.60    0.45
i2   200    0.65    0.52
i3   199    0.42    0.25
i4   200    0.71    0.58
i5   200    0.66    0.53

Welke conclusie is het meest correct?

  1. De schaal heeft uitstekende internal consistency.
  2. Item 3 is een zwak item (\(r_{\text{drop}} = .25\)) — kandidaat voor verwijdering.
  3. Item 4 is het zwakste item.
  4. De schaal heeft te kleine \(N\) voor \(\alpha\)-schatting.

b) Item 3 heeft \(r_{\text{drop}} = .25\), onder de \(.30\)-drempel. De andere items hebben \(r_{\text{drop}}\) tussen \(.45\)-\(.58\). Dit maakt item 3 een duidelijke kandidaat voor herziening of verwijdering.

Optie a: \(\alpha = .78\) is “acceptabel”, niet “uitstekend” (\(\geq .90\)). Optie c: item 4 heeft de hoogste \(r_{\text{drop}}\), niet de laagste — dus het is het sterkste, niet het zwakste. Optie d: \(N = 200\) is ruim genoeg voor \(\alpha\)-schatting.

NoteVraag E2 — Spearman-Brown handrekenen

In een split-half-analyse vond een onderzoeker \(r_{\text{half}} = .72\). Welke is de Spearman-Brown gecorrigeerde betrouwbaarheid?

  1. \(r_{\text{SB}} = .77\)
  2. \(r_{\text{SB}} = .84\)
  3. \(r_{\text{SB}} = .89\)
  4. \(r_{\text{SB}} = .72\) (geen correctie nodig)

b) \(r_{\text{SB}} = 2 \cdot .72 / (1 + .72) = 1.44 / 1.72 \approx .84\).

Optie a (.77) en c (.89) zijn rekenfouten. Optie d miskent dat split-half altijd correctie vereist (twee helften zijn samen kortere schalen dan de hele schaal).

NoteVraag E3 — α-na-deletie interpreteren

Een schaal met \(k = 6\) items toont:

Item   alpha-na-deletie
i1                .80
i2                .82
i3                .79
i4                .85   ← hoogste
i5                .81
i6                .80

De huidige \(\alpha = .81\). Welke conclusie?

  1. Verwijdering van item 4 zou de schaal aanzienlijk verbeteren — overweeg eruit halen.
  2. Item 4 is het sterkste item — bewaar zeker.
  3. Alle items zijn equivalent.
  4. De schaal werkt niet (alle alphas onder .90).

a) Verwijdering van item 4 zou \(\alpha\) verhogen van \(.81\) naar \(.85\) — een kleine maar reële winst. Plus: een hogere alpha-na-deletie wijst erop dat item 4 minder samenhangt met de rest dan de andere items. Theoretische check vereist (b is omgekeerd: lager item-na-deletie = sterker bijdragend).

Optie b: omgekeerd. Hoger alpha-na-deletie = item is zwak, niet sterk. Optie c: variatie van \(.79\)-\(.85\) is niet equivalent. Optie d: \(\alpha = .81\) is goed, niet “werkt niet”.

NoteVraag E4 — De standaardmeetfout en het CI

Een schaal heeft \(SD = 12\) en \(\alpha = .85\) in een steekproef van \(N = 250\). Een cliënt scoort \(X = 60\).

a) Bereken \(se_{\text{m}}\).

b) Bouw een \(95\%\)-CI rond zijn ware score.

c) Klopt de score “\(60\)” als precieze waarde, of is het een schatting?

a) \(se_{\text{m}} = 12 \cdot \sqrt{1 - .85} = 12 \cdot \sqrt{0.15} = 12 \cdot 0.3873 \approx 4.65\).

b) \(95\%\)-CI: \(60 \pm 1.96 \cdot 4.65 \approx 60 \pm 9.1 = [50.9, 69.1]\).

c) Schatting. De waarheid van zijn ware score ligt \(95\%\)-zeker in \([51, 69]\) — een aanzienlijke band. Een score van exact \(60\) is misleidend; rapporteer altijd \(X \pm se_{\text{m}}\) of een CI.

R-practical opdrachtje

De pissebed onder de steen — opnieuw

NoteVraag E5 — Mini-reliability bij de pissebed

Een ecoloog meet bij \(70\) pissebedden hun emotie-regulatie via zes items op een \(5\)-puntsschaal. De dataset staat in data/pissebed_emotie.RData en bevat het object pissebed_emotie met pissebed_id plus peb1 t/m peb6. Sla je R-commando’s op in één scriptbestand: pissebed.R.

a) Bereken Cronbach’s \(\alpha\) (raw + standardized) plus item-totaal-correlaties.

b) Welke item is het zwakst? Wat is het effect op \(\alpha\) als je het verwijdert?

c) Voer een split-half analyse uit met psych::splitHalf(). Wat is de gemiddelde split-half-correlatie?

d) Bereken \(se_{\text{m}}\) voor de schaal. Let op welke \(SD\) daarin hoort: die van de somscore over de zes items (bereik \(6\) tot \(30\)), en die reken je zelf uit de data — niet die van een los item. Bouw daarna een \(95\%\)-CI rond een score van \(X = 24\).

Schrijf één APA-zin met je conclusie over de betrouwbaarheid.

load("data/pissebed_emotie.RData")
str(pissebed_emotie)
'data.frame':   70 obs. of  7 variables:
 $ pissebed_id: Factor w/ 70 levels "p01","p02","p03",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ peb1       : num  5 3 3 5 4 2 4 4 1 3 ...
 $ peb2       : num  2 1 3 4 5 3 3 3 2 5 ...
 $ peb3       : num  4 1 3 4 5 2 3 3 2 5 ...
 $ peb4       : num  4 1 3 2 5 3 3 3 2 4 ...
 $ peb5       : num  5 4 3 1 4 2 3 4 4 4 ...
 $ peb6       : num  4 2 3 3 3 2 3 3 3 5 ...
# paste0() plakt tekst aan elkaar: paste0("peb", 1) wordt "peb1". Geef je hem
# een rijtje mee -- 1:6 is 1 2 3 4 5 6 -- dan doet hij het voor elk getal en
# krijg je "peb1" tot "peb6" terug. Zo hoef je zes namen niet met de hand over
# te tikken, en vertik je je ook niet.
peb_items <- paste0("peb", 1:6)

alpha_peb <- psych::alpha(pissebed_emotie[, peb_items], check.keys = FALSE)
round(alpha_peb$total[, c("raw_alpha", "std.alpha", "average_r")], 3)
 raw_alpha std.alpha average_r
     0.766     0.769     0.356
round(alpha_peb$item.stats[, c("raw.r", "r.drop", "mean", "sd")], 3)
     raw.r r.drop  mean    sd
peb1 0.681  0.517 3.157 1.199
peb2 0.707  0.555 3.186 1.183
peb3 0.641  0.437 2.786 1.350
peb4 0.678  0.501 3.171 1.274
peb5 0.704  0.541 3.200 1.246
peb6 0.673  0.517 3.114 1.136
round(alpha_peb$alpha.drop[, c("raw_alpha", "std.alpha")], 3)
     raw_alpha std.alpha
peb1     0.730     0.735
peb2     0.721     0.724
peb3     0.753     0.753
peb4     0.734     0.736
peb5     0.724     0.726
peb6     0.731     0.734
# splitHalf() rekent niet één splitsing maar alle mogelijke, en geeft je het
# gemiddelde plus de uitersten. Het getal dat de vraag wil is de gemiddelde
# split-half; de rest van de uitvoer mag je laten liggen.
sh_peb <- psych::splitHalf(pissebed_emotie[, peb_items], use = "complete.obs")
sh_peb
Split half reliabilities  
Call: psych::splitHalf(r = pissebed_emotie[, peb_items], use = "complete.obs")

Maximum split half reliability (lambda 4) =  0.84
Guttman lambda 6                          =  0.75
Average split half reliability            =  0.77
Guttman lambda 3 (alpha)                  =  0.77
Guttman lambda 2                          =  0.77
Minimum split half reliability  (beta)    =  0.71
Average interitem r =  0.36  with median =  0.38
# De standaardmeetfout hoort bij de som-score, dus ook de SD van de som-score
# -- uit de data, niet uit een aanname over hoe breed een 6-item-schaal
# "meestal" ligt. De variabele heet se_m omdat je formuleblad hem zo schrijft;
# een R-naam kan geen subscript, dus het onderstreepje doet dat werk.
SD_sum <- sd(rowSums(pissebed_emotie[, peb_items]))
alpha_raw <- alpha_peb$total$raw_alpha

se_m <- SD_sum * sqrt(1 - alpha_raw)

# De 24 staat er als los getal omdat de vraag hem geeft: bouw een interval rond
# een score van X = 24. Die 24 volgt dus niet uit de data en hoort er ook niet
# uit te komen. 1.96 is de z-waarde die 95 procent van een normale verdeling
# tussen zich in heeft.
CI_low  <- 24 - 1.96 * se_m
CI_high <- 24 + 1.96 * se_m
round(c(SD = SD_sum, alpha = alpha_raw, se_m = se_m,
        CI_low = CI_low, CI_high = CI_high), 2)
     SD   alpha    se_m  CI_low CI_high 
   5.03    0.77    2.43   19.24   28.76 

a) \(\alpha_{\text{raw}} = .77\), \(\alpha_{\text{std}} = .77\). Item-totaal-correlaties tussen \(r_{\text{drop}} = .44\) (peb3, zwakste) en \(r_{\text{drop}} = .55\) (peb2, sterkste).

b) peb3 is het zwakst. Verwijdering levert géén winst op: \(\alpha\) zakt van \(.77\) naar \(.75\). Net als bij de bosdieren geldt: zwakste item \(\neq\) item dat weg moet. En in een \(6\)-item-schaal kost weghalen bovendien inhoudelijke dekking; dat verdedig je theoretisch vóór je het doet, niet achteraf.

c) Gemiddelde split-half \(= .77\), congruent met \(\alpha\).

d) \(se_{\text{m}} = SD_{\text{som}} \cdot \sqrt{1 - \alpha} = 5.025 \cdot \sqrt{0.234} = 2.43\). CI rond \(X = 24\): \(24 \pm 4.76 = [19.24, 28.76]\).

Drie decimalen in de tussenstappen, en dat is geen slordigheid maar het punt: met \(SD = 5.03\) en \(\sqrt{0.23}\) tikt je rekenmachine \(2.41\) uit, en dan denk je dat je je vergist hebt. Een uitgeschreven som moet kloppen met de getallen die er staan.

Bij \(N = 70\) pissebedden vertoonde de zes-item emotie-regulatie-schaal acceptabele internal consistency, Cronbach’s α = .77 (raw), \(\bar{r} = .36\). Item-totaal-correlaties (gecorrigeerd) varieerden van \(r_{\text{drop}} = .44\) (peb3) tot \(r_{\text{drop}} = .55\) (peb2). De gemiddelde split-half-correlatie (\(r_{\text{SH}} = .77\)) bevestigde de α-schatting. De standaardmeetfout op de som-schaal (\(se_{\text{m}} = 2.43\)) levert een \(95\%\)-CI van \(\pm 4.76\) punten rond een individuele score.

R-spiekblad — van ruwe data tot rapportage

# 1. Pakketten + data laden ---------------------------------------------
library(tidyverse)
library(psych)

load("data/bos_dieren_piekeren.RData")

# Originele items-vector (item7_doorzetten = ongepoold).
items_orig <- c("item1_terugkijken", "item2_nachtgedachten", "item3_anderengedrag",
                "item4_ergevoel",    "item5_zinloos",        "item6_loslaten",
                "item7_doorzetten",  "item8_zorgen",         "item9_terug",
                "item10_aanwezigheid")

# 2. Verkenning — item-statistieken ------------------------------------
round(cor(bos_dieren_piekeren[, items_orig], use = "complete.obs"), 2)
# >>> let op: item7_doorzetten heeft NEGATIEVE correlaties — moet ompool

# 3. Ompolen (handmatig, route 1) --------------------------------------
bos_dieren_piekeren$item7_doorzetten_REC <- 6 - bos_dieren_piekeren$item7_doorzetten

items <- c("item1_terugkijken", "item2_nachtgedachten", "item3_anderengedrag",
           "item4_ergevoel",    "item5_zinloos",        "item6_loslaten",
           "item7_doorzetten_REC", "item8_zorgen",      "item9_terug",
           "item10_aanwezigheid")

# 4. Cronbach's alpha + item-stats (op omgepoolde data) ----------------
res <- psych::alpha(bos_dieren_piekeren[, items], check.keys = FALSE)
res$total       # alpha raw + std + average_r
res$item.stats  # raw.r, r.drop per item
res$alpha.drop  # alpha als item-eruit

# 5. Split-half + Spearman-Brown ---------------------------------------
helft_A <- items[c(1, 3, 5, 7, 9)]
helft_B <- items[c(2, 4, 6, 8, 10)]

score_A <- rowMeans(bos_dieren_piekeren[, helft_A], na.rm = TRUE)
score_B <- rowMeans(bos_dieren_piekeren[, helft_B], na.rm = TRUE)

r_half <- cor(score_A, score_B, use = "complete.obs")
r_SB   <- 2 * r_half / (1 + r_half)
c(r_half = r_half, r_SB = r_SB)

# Robuust over alle splits.
sh_res <- psych::splitHalf(bos_dieren_piekeren[, items], use = "complete.obs")
sh_res

# 6. Standaardmeetfout en betrouwbaarheids-interval -------------------
SD_sum <- sd(rowSums(bos_dieren_piekeren[, items], na.rm = TRUE))
alpha  <- res$total$raw_alpha

# se_m: zo staat hij op je formuleblad. Een R-naam kan geen subscript, dus
# schrijf je het e'tje met een onderstreepje.
se_m <- SD_sum * sqrt(1 - alpha)
se_m

# Voor één score X: CI = X +/- 1.96 * se_m.
X <- 35
c(CI_low = X - 1.96 * se_m, CI_high = X + 1.96 * se_m)

# 7. Item-deletie iteratief ------------------------------------------
# Welke item zou je weghalen als je alpha wil maximaliseren?
ad <- res$alpha.drop[, c("raw_alpha", "std.alpha")]
ad[order(-ad$raw_alpha), ]

Wat blijft liggen

Onderwerpen die buiten dit thema blijven

Cronbach’s \(\alpha\) + split-half + Spearman-Brown is de hoofdingang. Voor verdere studie:

  • McDonald’s \(\omega\) — robuuster dan \(\alpha\) bij multi-dimensionele schalen. psych::omega(). Aanbevolen alternatief.
  • Bootstrap-CI’s voor \(\alpha\) — bij kleine \(N\). psych::alpha(..., n.iter = 1000), interval in $boot.ci.
  • Generaliseerbaarheids-theorie (G-theory) — variantie-decompositie over meerdere meetfacetten (rater, item, gelegenheid). Cronbach et al. (1972).
  • Reliability bij IRTinformatie-functie in plaats van \(\alpha\). Komt thema 6.
  • Test-equating — twee versies van een test op gelijke schaal brengen. Lord (1980).
  • Inter-rater reliability — een volwaardige vorm van betrouwbaarheid, die deze cursus niet behandelt: stemmen twee beoordelaars overeen die hetzelfde object scoren? Je hebt er andere maten voor nodig dan \(\alpha\) — Cohen’s \(\kappa\) bij een categorisch oordeel, Fleiss’ \(\kappa\) bij meer dan twee beoordelaars, en de ICC bij continue scores.

Voor verdieping: Crocker & Algina (1986); Streiner, Norman & Cairney (2015, Health Measurement Scales); Cronbach (1951, Coefficient alpha and the internal structure of tests).

Aan het eind van de dag

De wezel keek tevreden — voor zijn doen, wat betekent: niet ontevreden.

\(\alpha = .87\),” zei hij. “Goed genoeg. En nee, item 3 mag er niet uit — ik heb het nagekeken, de schaal wordt er niet beter van. Zwakste is niet hetzelfde als slecht.”

“En de meetfout?” vroeg de bunzing.

“Klein genoeg voor onderzoek, te groot voor klinische individuele beslissing op één score.” Hij zweeg. “Tweede meting eroverheen helpen, of een schaal met \(\alpha > .90\).”

“En morgen?”

“Validity,” zei de wezel. “Of dit construct eigenlijk wel meet wat we beweren te meten. Je kunt iets perfect betrouwbaar verkeerd meten. Daar gaan we het over hebben.”

De vos keek nieuwsgierig op vanuit de schaduw — hij was al langs voor zijn eigen hoofdstuk. “Validity? Mooi. Iemand moet die boel eens uitpluizen.”

De bunzing knikte en kroop weg. Boven het bos werd het donker, en de wezel deed zijn ogen halfdicht zonder iets te zeggen.

Verantwoording

Dit werkboek is geschreven voor studenten die psychometrie leren via R. Het is materiaal van CountCamp en niet van de opleiding: het volgt de weken van de cursus, maar het is er geen officieel onderdeel van. De voorbeelden, datasets, vragen en formuleringen zijn origineel; de didactische volgorde is dat bewust niet — die volgt de indeling van het college. De gebruikte drempels en formules zijn standaard psychometrische conventies; verwijzingen naar Cronbach (1951), Crocker & Algina (1986) en Streiner, Norman & Cairney (2015) volgen de gebruikelijke citaatpraktijk in dit veld.

Waar dit thema een eigen weg gaat, en waar het de cursus volgt. Eigen keuze is de NA-drempel uit thema 1, die hier ook geldt: hoogstens één ontbrekende waarde. Ook eigen keuze is dat je interbeoordelaarsbetrouwbaarheid hier niet leert uitrekenen: je hoeft hem alleen te herkennen aan het patroon twee beoordelaars, één object, en welke maten je ervoor zou gebruiken staat achterin bij Wat blijft liggen. Die keuze is gemaakt omdat wij hem in de dia’s van dit vak niet zijn tegengekomen — kijk dat na in je eigen college-sheets, want daar en niet hier staat wat er op je tentamen kan komen. De cursus volgen we in het kader Wat is reliability?, dat de vier soorten betrouwbaarheid in dezelfde volgorde en met dezelfde namen behandelt als het college. En de standaardmeetfout heet hier \(se_{\text{m}}\) omdat het formuleblad hem zo noemt — het blad dat je mee het tentamen in neemt. Alleen het subscript zetten wij rechtop en het formuleblad schuin: het is een naampje — de m van measurement — en geen variabele.

En waar dit werkboek en de cursus elkaar tegenspreken, wint de cursus: botst iets hieruit met je college, met het werkboek van de opleiding of met je formuleblad, dan winnen die drie.

Versie: September 2026 — CountCamp Lab

Back to top