Hopp til innholdet

Optometri

Tillegg A: Datasettene i R

Kapittelet om statistikk regner på tre datarammer: klinikkdatasettet med 71 pasienter, metodedatasettet, som er de fire trykkmålingene fra de samme 71 pasientene under egne navn, og biometridatasettet med 74 personer. R-kodeblokkene der forutsetter at alle tre alt ligger i minnet – de skriver summary(IOP) og t.test(Corvis, GAT, paired = TRUE) uten å bygge noe først, mens tabellene i kapittelet bare viser de tolv første radene av hvert sett. Her står hele settene som kjørbar kode. Lim blokkene under inn i R én gang i starten av økten, i den rekkefølgen de står, så kjører hver kodeblokk i kapittelet slik den er skrevet.

Verdiene er målte, publiserte forskningsdata, ikke tall valgt for et pent regnestykke. Klinikk- og metodedatasettet er de 71 høyre øynene i en japansk studie av tonometre hos pasienter med primær åpenvinkelglaukom under trykksenkende behandling [181]; biometridatasettet er høyre øye hos de 74 deltakerne i en norsk studie fra optometriutdanningen ved USN, der friske voksne fikk målt refraksjon og aksiallengde med tre instrumenter [183]. Begge datasettene er utgitt under lisensen Creative Commons Navngivelse 4.0 (CC BY 4.0), som tillater gjenbruk og bearbeiding mot at opphavet oppgis. Opphavet er de to artiklene i referanselisten og datasettene de bygger på: doi 10.6084/m9.figshare.11954748 for Nakao, Kiuchi og Okumichi (2020) og doi 10.23642/usn.21909591.v1 for Pedersen, Svarverud, Hagen, Gilson og Baraas (2023). Bearbeidingen – utvalget av kolonner, avrundingene og de avledede kolonnene – er beskrevet under hvert sett, så du kan gå fra de publiserte filene til tallene her og tilbake.

To forbehold hører med. Det første er at settene er ekte, men små: 71 og 74 rader er nok til å vise hva metodene gjør, ikke til å avgjøre et klinisk spørsmål. Det andre er hva som ikke kan sluttes av dem. Trykktallene i klinikkdatasettet er målt hos pasienter med glaukom under behandling, så fordelingen viser et behandlet og kontrollert trykk – ikke trykkfordelingen i en ubehandlet befolkning – og en samvariasjon i materialet, som den mellom kjønn og myopi, er en egenskap ved dette selekterte utvalget, ikke en påstand om befolkningen. Biometridatasettet er unge, friske voksne, de fleste kvinner, rekruttert til en instrumentstudie; det sier noe om hvordan aksiallengde og refraksjon henger sammen, ikke noe om hvor vanlig myopi er. Talleksemplene ellers i boken og de stipulerte parametrene i statistikkapitlet (μ=16 mmHg og σ=3.5 mmHg i normalfordelingseksemplene) er fortsatt konstruerte, og ingen konklusjon om et instrument eller en pasientgruppe kan hentes ut av dem.

Klinikkdatasettet

Den publiserte filen har én rad per pasient – høyre øye hos 71 pasienter, målt samme dag med Goldmann-tonometer (GAT), et berøringsfritt tonometer (NCT) og Corvis ST, som gir både en ukorrigert avlesning (Corvis) og en biomekanisk korrigert (bIOP) – og tolv kolonner. Boken bruker elleve av dem, under kortere navn og med disse bearbeidingene:

  • •

    alder: alderen står i filen med desimaler og er rundet til hele år.

  • •

    kjonn: filens M/F er skrevet M/K.

  • •

    SER: sfærisk ekvivalent i dioptri, som i filen; den har tre desimaler der refraksjonen ligger mellom kvartdioptriene, og de er beholdt.

  • •

    K: filen oppgir hornhinnens gjennomsnittlige krumningsradius r i millimeter. Boken regner den om til gjennomsnittlig keratometri i dioptri med keratometer-indeksen nk=1.3375 fra kapittel 9 og 12, K=(nk−1)/r=337.5/r med r i mm, rundet til to desimaler.

  • •

    IOP: Goldmann-avlesningen, som i filen (én desimal). Det er denne kolonnen kapittelet kaller trykket når det bare sier IOP.

  • •

    NCT: det berøringsfrie tonometeret, hele mmHg som i filen.

  • •

    Corvis og bIOP: i filen står hver av dem som snittet av tre målinger, med mange desimaler; de er rundet til én desimal med R sin round(), som ved en eksakt halv desimal følger flyttallet og derfor ikke alltid runder opp (8.85 blir 8.8, men 7.75 blir 7.8). Tallene under er fasit.

  • •

    CCT: sentral hornhinnetykkelse, i filen snittet av tre målinger, rundet til hele µ⁢m.

  • •

    AL: aksiallengde i millimeter, som i filen.

Ingen andre rådata er rørt. To ting ved filen slik den er publisert bør du vite om. Radene 1–58 ligger sortert etter alder, og de siste tretten er lagt til etterpå; derfor ser alderskolonnen «sortert» ut, og de tolv første pasientene, som tabellen i kapittelet viser, er alle 43–53 år. Og rad 56 og 57 er identiske i alle kolonner – etter alt å dømme en dublett i originalfilen. Boken beholder filen som den er publisert, med 71 rader; en oppmerksom leser som finner de to like radene, har sett riktig.

Kodeblokkene i kapittelet skriver kolonnenavnene bart: summary(IOP), ikke summary(klinikk$IOP). Derfor bygger vi først hver kolonne som en egen vektor og setter dataramma sammen av dem til slutt. Da finnes tallene begge steder samtidig – som løse navn og som kolonner i klinikk – og begge skrivemåtene i kapittelet virker. Kolonnene i dataramma arver navnene fra vektorene, så rekkefølgen i data.frame() er den samme som i tabellen.

Første del er pasientopplysningene, refraksjonen og aksiallengden. Tell gjerne verdiene i én av vektorene: alle skal ha 71 elementer, én per pasient, og den siste linjen kontrollerer det.

R-kode

# ---- Klinikkdatasettet, del 1: pasient og refraksjon (71 pasienter)
# kjonn blir staaende som tekst (chr); R 4.0 og nyere lager ikke
# faktorer av tekstkolonner av seg selv.
alder <- c(43, 44, 44, 49, 49, 49, 50, 50, 50, 51, 52, 53, 54, 55, 58, 58, 60,
61, 61, 62, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 66, 66, 67, 67,
68, 68, 69, 70, 70, 71, 71, 71, 72, 72, 72, 73, 73, 73, 74, 74, 75,
77, 77, 77, 78, 79, 79, 79, 31, 32, 42, 44, 51, 52, 54, 57, 68, 70,
77, 78, 79)
kjonn <- c("M", "M", "K", "K", "K", "M", "M", "M", "M", "M", "M", "K", "M", "M",
"K", "K", "M", "M", "M", "M", "K", "M", "K", "M", "M", "M", "M", "M",
"K", "M", "K", "M", "M", "M", "M", "K", "M", "K", "K", "K", "M", "M",
"M", "M", "M", "K", "K", "K", "K", "K", "K", "K", "M", "M", "M", "M",
"M", "K", "K", "K", "K", "M", "K", "K", "M", "K", "K", "M", "M", "K",
"K")
SER <- c(-5.750, -7.750, -10.125, -10.750, -0.125, -8.000, -6.750, -5.375,
-9.500, -5.000, -5.250, -6.375, -0.500, -0.750, -6.500, 0.000, -2.875,
-3.750, -3.125, -6.000, -4.000, -8.375, 0.125, -3.250, -7.375, 0.000,
-1.375, -1.875, -5.625, -5.000, -6.750, -4.875, -1.375, -3.750, -3.750,
-2.875, -1.500, 2.125, -0.125, -2.250, 2.250, -2.625, -1.375, -5.500,
-6.000, -6.250, 1.625, 2.625, 2.250, -1.875, 0.250, -0.250, -7.125,
0.375, 3.125, -0.250, -0.250, 1.750, -4.000, -4.250, -4.875, -4.500,
-9.125, -4.625, -6.750, -1.500, -0.625, -4.500, 0.875, 2.625, -1.625)
AL <- c(24.79, 27.98, 29.21, 27.02, 23.56, 27.06, 24.95, 26.34, 28.26, 25.48,
26.81, 25.70, 23.04, 24.46, 25.19, 23.26, 25.94, 26.29, 26.62, 26.61,
24.03, 28.08, 22.73, 25.48, 27.50, 23.87, 24.58, 25.56, 25.54, 26.28,
27.04, 27.19, 24.55, 27.69, 25.65, 25.65, 24.82, 22.91, 23.57, 23.75,
24.46, 25.91, 25.15, 24.05, 26.21, 25.88, 23.95, 22.86, 22.77, 23.76,
23.33, 22.57, 26.54, 24.00, 22.75, 22.77, 22.77, 23.22, 26.20, 26.96,
24.15, 27.17, 27.99, 26.21, 27.88, 24.35, 22.09, 25.55, 23.43, 22.43,
23.65)
length(alder) #> [1] 71

Andre del er hornhinnen og de fire trykkmålingene. Enhetene følger tabellen: K i D, de fire trykkene i mmHg og CCT i µ⁢m.

R-kode

# ---- Del 2: hornhinne og de fire trykkmaalingene
K <- c(45.36, 44.44, 41.26, 45.64, 43.27, 43.66, 45.98, 43.41, 42.40, 43.86,
42.86, 46.68, 44.03, 40.49, 43.38, 44.58, 42.72, 42.99, 41.90, 45.55,
47.30, 43.72, 46.33, 42.27, 41.98, 42.48, 43.24, 43.86, 44.15, 44.61,
43.86, 42.59, 45.67, 41.72, 44.23, 41.46, 43.89, 45.21, 44.67, 43.60,
41.36, 42.51, 44.29, 45.67, 41.21, 43.89, 43.97, 43.97, 45.55, 44.61,
43.89, 46.01, 43.83, 41.51, 44.15, 45.92, 45.92, 44.15, 41.72, 39.94,
45.06, 42.61, 41.16, 42.80, 41.41, 43.19, 46.94, 44.41, 43.16, 43.35,
43.13)
IOP <- c(16.0, 11.3, 15.0, 16.0, 11.0, 11.3, 15.0, 10.0, 16.0, 17.0, 12.0, 14.0,
12.0, 13.0, 15.0, 12.0, 14.0, 14.0, 14.0, 15.0, 12.0, 15.5, 12.0, 8.0,
10.0, 17.0, 15.0, 13.0, 11.3, 13.0, 13.0, 12.0, 12.0, 15.0, 10.0, 12.3,
13.0, 12.0, 11.0, 15.0, 11.0, 15.0, 13.0, 11.0, 11.0, 15.0, 11.0, 16.0,
14.0, 13.0, 15.0, 16.0, 18.7, 12.0, 10.0, 14.7, 14.7, 17.0, 14.0, 13.0,
14.0, 15.7, 16.0, 14.0, 11.0, 13.7, 12.0, 13.0, 15.0, 16.0, 14.7)
NCT <- c(18, 12, 17, 16, 10, 12, 15, 9, 20, 16, 12, 13, 12, 16, 13, 9, 12, 11,
13, 13, 11, 16, 12, 11, 8, 13, 14, 12, 10, 12, 13, 11, 15, 14, 9, 12,
14, 13, 10, 12, 12, 13, 14, 8, 10, 15, 11, 15, 18, 12, 12, 16, 21, 15,
10, 10, 10, 19, 15, 13, 15, 16, 18, 13, 12, 14, 13, 13, 16, 14, 11)
Corvis <- c(17.0, 8.3, 13.7, 14.5, 7.2, 10.0, 12.0, 8.5, 15.7, 11.7, 8.5, 9.7,
11.0, 9.3, 7.3, 9.0, 9.8, 9.7, 9.3, 13.7, 11.2, 12.0, 9.7, 6.0, 6.0,
9.7, 10.8, 9.2, 6.5, 9.8, 11.7, 9.5, 11.0, 10.8, 7.8, 7.8, 11.7,
9.8, 8.3, 10.3, 10.0, 10.2, 11.7, 8.0, 6.0, 11.0, 8.5, 12.7, 14.2,
7.8, 11.0, 13.0, 22.0, 11.5, 7.3, 10.2, 10.2, 17.0, 9.2, 11.3, 13.2,
11.0, 13.2, 12.0, 7.3, 7.0, 10.3, 11.8, 15.2, 11.5, 9.2)
bIOP <- c(16.0, 8.7, 14.1, 13.4, 8.8, 9.6, 11.3, 9.3, 15.2, 10.4, 8.3, 9.9,
11.0, 8.7, 7.6, 9.0, 8.9, 9.9, 9.3, 13.5, 11.0, 10.2, 9.5, 6.1, 6.1,
9.8, 11.4, 9.1, 6.0, 10.1, 8.9, 8.3, 9.2, 10.2, 6.4, 8.4, 11.2, 9.1,
7.7, 9.9, 10.0, 10.2, 11.9, 7.9, 6.0, 10.0, 7.6, 11.8, 11.7, 6.9,
10.1, 12.8, 16.1, 10.4, 5.9, 10.9, 10.9, 15.3, 9.8, 11.6, 12.5, 10.7,
10.6, 10.2, 7.6, 6.6, 9.2, 9.9, 14.4, 8.5, 9.0)
CCT <- c(560, 532, 513, 559, 463, 553, 557, 501, 534, 580, 549, 523, 528, 564,
523, 525, 560, 512, 525, 514, 519, 576, 523, 522, 531, 511, 489, 520,
549, 506, 612, 566, 573, 534, 572, 495, 523, 536, 538, 521, 505, 504,
489, 514, 512, 539, 546, 527, 573, 546, 533, 497, 635, 532, 559, 460,
460, 529, 531, 541, 561, 551, 625, 595, 529, 555, 551, 572, 513, 592,
504)

Tredje del er den ene kategoriske variabelen, myopistatus. Den er ikke en kolonne i den publiserte filen, men avledet av SER med grensen SER≤−0.50 D, den samme kapittelet bruker når det deler i myope og ikke-myope. Den lages som en faktor – R sin type for kategoriske variabler – med nivåene oppgitt eksplisitt, slik at «ja» blir første nivå og krysstabellen i kapittelet får samme oppsett som der. Så settes dataramma sammen, og du kontrollerer den mot tabellen før du regner videre. De fem kontrollene dekker hver sin type: radantallet, variabeltypene, et sentralmål, en korrelasjon og en krysstabell. Stemmer alle fem, har du limt inn riktig.

R-kode

# ---- Del 3: myopi som faktor (IMI-grensen SER <= -0.50 D)
myopi <- factor(ifelse(SER <= -0.50, "ja", "nei"), levels = c("ja", "nei"))
# Kolonnene arver navnene fra vektorene; de loese vektorene blir staaende
klinikk <- data.frame(id = 1:71, alder, kjonn, SER, AL, K, IOP, NCT, Corvis,
bIOP, CCT, myopi)
nrow(klinikk) #> [1] 71
str(klinikk[, c("SER", "IOP", "kjonn", "myopi")])
#> 'data.frame': 71 obs. of 4 variables:
#> $ SER : num -5.75 -7.75 -10.125 -10.75 -0.125 ...
#> $ IOP : num 16 11.3 15 16 11 11.3 15 10 16 17 ...
#> $ kjonn: chr "M" "M" "K" "K" ...
#> $ myopi: Factor w/ 2 levels "ja","nei": 1 1 1 1 2 1 1 1 1 1 ...
round(mean(IOP), 2) #> [1] 13.46
round(cor(CCT, NCT - IOP), 2) #> [1] 0.41
table(kjonn, myopi)
#> myopi
#> kjonn ja nei
#> K 19 12
#> M 33 7

Metodedatasettet

Metodedatasettet er ikke nye tall, men de fire trykkolonnene fra klinikkdatasettet under de navnene seksjonen om metodesamsvar bruker. Goldmann-avlesningen får navnet GAT – GAT <- IOP lager ikke en kopi med andre verdier, bare et nytt navn på samme kolonne, så t.test(Corvis, GAT, paired = TRUE) i kapittelet og summary(IOP) i deskriptivseksjonen regner på nøyaktig de samme 71 tallene. Datasettet inneholder ingen gjentatte målinger med samme instrument; det er derfor kapittelet måler reproduserbarhet på tvers av to instrumenter der, ikke repeterbarhet. Kontrollutskriftene viser de fire gjennomsnittene og den systematiske forskjellen Corvis mot Goldmann, som kapittelet finner igjen som bias i Bland-Altman-analysen.

R-kode

# ---- Metodedatasettet: de fire trykkmaalingene paa samme oeye (mmHg)
GAT <- IOP # Goldmann er referansen; samme tall, eget navn
metode <- data.frame(id = 1:71, GAT, NCT, Corvis, bIOP)
nrow(metode) #> [1] 71
round(colMeans(metode[, -1]), 2)
#> GAT NCT Corvis bIOP
#> 13.46 13.17 10.56 9.98
round(mean(Corvis - GAT), 2) #> [1] -2.9

Biometridatasettet

Den publiserte filen fra USN-studien har 139 rader – ett øye per rad – fra 74 personer, og for hvert øye målinger fra tre instrumenter: Myopia Master (refraksjon, krumningsradier og aksiallengde), IOLMaster 700 (krumningsradier og aksiallengde) og autorefraktoren Huvitz HRK-8000A (refraksjon og krumningsradier), alle tatt i cykloplegi. Boken bruker bare høyre øye (eye_tested == "OD"), og bare målingene fra Myopia Master. Grunnen til det første er uavhengighet: to øyne fra samme person ligner hverandre langt mer enn to øyne fra ulike personer, så 139 øyne er ikke 139 uavhengige observasjoner, og hver test i kapittelet forutsetter uavhengige rader. Med ett øye per person er n=74 det antallet personer det faktisk er. At det ble høyre og ikke venstre, er en regel fastsatt før dataene ble sett – ikke et valg ut fra tallene – og høyre øye er målt hos alle 74, mens 65 av dem også har venstre øye i filen. Kolonnene er:

  • •

    alder: som i klinikkdatasettet rundet til hele år. Snittet av den avrundede kolonnen er 22.7 år; artikkelen oppgir 22.8 år, regnet av de uavrundede aldrene, og det er artikkelens tall kapittelet bruker.

  • •

    kjonn: filens Male/Female skrevet M/K.

  • •

    SER: sfærisk ekvivalent i dioptri, regnet fra Myopia Masters sfære og sylinder med SER=S+C/2 – den sfæriske ekvivalenten fra kapittel 2 og 14, her med filens minus-sylinderkonvensjon (C≤0). Trinnene på 0.125 D kommer av at instrumentet oppgir kvartdioptrier og halvparten av en sylinder blir en åttendedel.

  • •

    AL: aksiallengden fra Myopia Master, i millimeter med tre desimaler som i filen.

Ingen annen avrunding er gjort. Blokkene i kapittelet skriver with(biometri, ...), data = biometri eller biometri$AL, aldri de bare kolonnenavnene – de er alt opptatt av klinikkdatasettet. Vektorene under har derfor prefikset b_ så de ikke overskriver klinikkens alder, kjonn, SER og AL, og de fjernes med rm() når dataramma er bygd. Kontrollutskriftene er radantallet, antall menn, snittalderen (avrundet kolonne, se over) og korrelasjonen kapittelet bygger regresjonen på.

R-kode

# ---- Biometridatasettet (USN 2021): 74 friske voksne, bare hoeyre oeye
b_alder <- c(21, 21, 28, 22, 20, 20, 19, 20, 19, 22, 19, 29, 21, 21, 22, 29, 31,
22, 22, 22, 21, 25, 24, 22, 21, 20, 21, 26, 19, 21, 20, 21, 21, 24,
19, 26, 19, 21, 22, 20, 24, 26, 21, 32, 21, 20, 27, 27, 19, 27, 21,
22, 41, 19, 21, 25, 22, 25, 21, 27, 20, 24, 23, 23, 21, 19, 20, 27,
24, 23, 26, 22, 20, 19)
b_kjonn <- c("K", "K", "M", "K", "K", "K", "K", "K", "K", "K", "K", "K", "K",
"K", "K", "M", "K", "K", "K", "K", "K", "K", "K", "K", "K", "K",
"K", "M", "M", "K", "M", "M", "K", "K", "K", "M", "K", "K", "K",
"K", "K", "K", "K", "M", "K", "K", "K", "M", "M", "K", "M", "K",
"K", "M", "K", "M", "K", "K", "K", "M", "K", "K", "K", "K", "K",
"K", "K", "K", "K", "K", "M", "M", "K", "K")
b_SER <- c(-2.375, -4.125, 1.250, -1.125, 1.250, -1.000, -13.875, -6.250,
-6.125, 0.750, 0.250, -0.500, -0.125, 1.000, 0.125, 0.375, -0.375,
-1.000, 0.625, -1.125, 4.500, -0.375, -4.375, 1.125, -1.250, -1.375,
0.375, 0.625, 1.000, 0.375, 1.875, 0.625, 0.750, 0.375, 0.875,
-0.750, 6.750, 0.875, -3.000, 1.625, 3.250, 0.625, -2.375, -5.000,
0.250, 0.500, -0.125, 0.000, -1.000, 0.375, -3.000, 1.625, 0.375,
-3.250, -0.500, 0.000, -7.000, -0.375, -0.875, -2.875, -0.500,
-2.875, 1.500, 1.500, 1.000, -6.750, -1.500, -2.500, -1.500, 0.000,
1.000, -2.375, 1.125, -0.875)
b_AL <- c(25.155, 25.803, 22.414, 24.403, 22.191, 23.091, 26.983, 24.132,
23.875, 23.915, 22.643, 23.443, 23.678, 23.353, 23.586, 23.933,
23.644, 24.491, 24.281, 23.590, 22.908, 23.739, 26.479, 23.257,
24.425, 24.686, 24.123, 23.131, 23.296, 23.197, 24.304, 22.917,
22.364, 23.394, 21.777, 23.914, 21.891, 22.761, 24.376, 23.370,
23.959, 23.115, 25.172, 26.667, 23.379, 22.719, 23.165, 24.207,
24.983, 22.909, 25.988, 23.309, 22.862, 25.326, 23.059, 24.901,
25.992, 23.303, 24.116, 25.207, 23.441, 23.575, 23.083, 22.781,
23.139, 26.432, 25.498, 23.519, 23.446, 24.193, 22.388, 25.504,
23.042, 23.844)
biometri <- data.frame(id = 1:74, alder = b_alder, kjonn = b_kjonn,
SER = b_SER, AL = b_AL)
rm(b_alder, b_kjonn, b_SER, b_AL) # bare dataramma blir staaende
nrow(biometri) #> [1] 74
sum(biometri$kjonn == "M") #> [1] 16
round(mean(biometri$alder), 1) #> [1] 22.7
round(cor(biometri$AL, biometri$SER), 2) #> [1] -0.75

Med de tre datarammene i minnet kjører hver kodeblokk i kapittelet uendret. Kapittelet gjenbruker enkelte navn til andre ting underveis – d står både for en spalteavstand og for en differanse, K og L har egne betydninger i noen blokker, og myop lages på nytt som en logisk vektor der den trengs. Blir en av kolonnene over overskrevet slik, limer du bare den aktuelle blokken her inn på nytt.