3 Lagring af data
Data lagres i databaser, hvad enten det er på papir, i tekstfiler, i regneark i eller i store datavarehuse. De fleste databasesystemer er såkaldte relationelle databaser, som lagrer relaterede data i tabeller, hvor hver række repræsenterer én post, fx en fødsel, og hver kolonne repræsenterer de tilknyttede variable, fx fødselsdato, gestationsalder, fødselsvægt og ruptur.
3.1 Strukturér data
Det er helt afgørende for datakvaliteten og mulighederne for at opgøre og analysere data at fastholde, at et datasæt altid er en rektangulært størrelse med én post per række, én variabel per kolonne og én datatype per variabel – og ingen tomme felter. Derfor tjener det sig hurtigt ind, hvis man allerede før projektstart tænker grundigt over, hvordan man bedst strukturerer data.
En effektiv og nyttig måde at sikre en god datastruktur på er at oprette en såkaldt codebook, som er en liste, der definerer og beskriver alle variable i data. Af hensyn til den videre bearbejdning og analyse af data, er det en fordel med korte variabelnavne, som er lette at skrive i computerprogrammer og regnearksformler. Men korte variabelnavne er sjældent egnede til pænt brug i tabeller, grafer og rapporter. En codebook er bindeledet mellem computersprog og menneskesprog og beskriver som minimum hver variabels korte navn, lange navn, datatype, enheder og udfaldsrum:
variabel | etiket | type | enhed | udfaldsrum |
---|---|---|---|---|
id | Fødselsnummer | heltal | 1 - ∞ | |
dt | Fødselsdato | dato | 2000-01-01 - 2030-01-01 | |
ga | Gestationsalder | heltal | dage | 100 - 300 |
bw | Fødselsvægt | kommatal | gram | 100 - 10000 |
lac | Mellemkødslæsion | ordinal | 1 / 2 / 3a / 3b / 4 |
Variabellisten kan bruges til datavalidering ved at benytte udfaldsrummets værdier som gyldige værdier, og den kan bruges til at oversætte variabelnavne til mere sigende dataetiketter i grafer og tabeller.
Man kan naturligvis udvide listen efter behov. Ofte er det nyttigt med en længere tekstuel beskrivelse af en variabel, og et felt til noter eller bemærkninger kan også være på plads.
Med ovenstående struktur og variabeldefinitioner kunne begyndelsen på et datasæt se således ud:
id | dt | ga | bw | lac | note |
---|---|---|---|---|---|
1 | 2020-01-28 | 264 | 2810 | 0 | |
2 | 2020-01-28 | 282 | 3820 | 3a | sædefødsel |
3 | 2020-01-29 | 276 | 3310 | 0 | |
4 | 2020-01-30 | 294 | 4200 | 0 | |
5 | 2020-01-30 | 279 | 3500 | 0 | |
6 | 2020-02-01 | 280 | 3210 | 1 | |
… | … | … | … | … | … |
Hvis man benytter dedikerede databasesystemer bliver man fra starten tvunget til at tage stilling til datastruktur og -typer og oprette en codebook. Dette gælder desværre ikke for almindelige regnearksløsninger som fx Excel, som ikke bare tillader hvad som helst hvor som helst men oven i købet ofte ændrer data uden at først at spørge om lov. Mere om regneark følger.
3.2 Opdel data i tabeller
Det kan ofte være nyttigt at opdele sine data i flere tabeller, som hver især rummer et udsnit af variable, som hører logisk sammen.
Eksemplet i Tabel 3.1 rummer data fra en audit af tryksår hos indlagte patienter. Hver række repræsenterer en enkelt patient. Id-kolonnen indeholder patientens unikke id (i virkeligheden cpr-nummer).
Fordi en patient kan have ingen eller vilkårligt mange tryksår, har man været nødt til at oprette tre variable (kolonner) til hvert tryksår. Tabellen overholder altså ikke reglerne om én række per post (tryksår) og ingen tomme felter.
id | alder | koen | placering_1 | kategori_1 | aarsag_1 | placering_2 | kategori_2 | aarsag_2 | placering_3 | kategori_3 | aarsag_3 | placering_4 | kategori_4 | aarsag_4 | placering_5 | kategori_5 | aarsag_5 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 55 | Mand | |||||||||||||||
2 | 69 | Kvinde | Balle | 1 | Tryk/shear | Andet | 2 | KAD | |||||||||
3 | 62 | Kvinde | Haleben | 2 | Fugt | ||||||||||||
4 | 26 | Mand | |||||||||||||||
5 | 27 | Mand | Næse | 1 | Sonde | Hånd | 2 | SAT-måler | Hånd | 2 | SAT-måler | Hånd | 2 | SAT-måler | Hånd | 2 | SAT-måler |
6 | 69 | Kvinde | |||||||||||||||
7 | 23 | Kvinde | |||||||||||||||
8 | 59 | Kvinde | |||||||||||||||
9 | 21 | Mand | |||||||||||||||
10 | 14 | Mand | Albue | 2 | Tryk/shear | ||||||||||||
11 | 76 | Kvinde | |||||||||||||||
12 | 59 | Mand | |||||||||||||||
13 | 49 | Mand |
Tabellen rummer data om 9 tryksår hos 13 patienter. Men det meste af tabellen er tom, fordi ikke alle patienter har lige mange tryksår. Det ville ikke en gang give mening at angive manglende data (NA) i de tomme felter. Data mangler jo ikke – de findes slet ikke.
Og for at gøre ondt værre, så tvinger formatet os til at oprette tre nye kolonner til hvert nyt tryksår. I eksemplet findes 5 tryksår hos en enkelt patient. Men hvad nu, hvis vi møder en patient med 6, 9 eller 13 tryksår? Vi bliver altså nødt til at designe tabellen sådan, at den med sikkerhed kan rumme alle fremtidige patienter med vilkårligt antal tryksår.
Nu troede man ikke det kunne blive værre. Men formatet er også nærmest umuligt at arbejde med, når data skal opgøres og analyseres. Fordi oplysninger om de enkelte tryksår findes i forskellige kolonner, er det ikke enkelt at tælle det samlede antal tryksår for slet ikke at tale om at opgøre tryksårene efter sværhedsgrad, placering og årsag.
Løsningen er at opdele data i separate tabeller til hhv. patienter og tryksår og at designe sin dataindsamling, så de rigtige variable havner i de rigtige tabeller som i Tabel 3.2.
|
|
Patienttabellen indeholder én række per patient, og tryksårstabellen indeholder én række per tryksår. De to tabeller har id-variablen til fælles, som naturligt forbinder dem og gør det enkelt at opgøre data på kryds og tværs af både patienter og tryksår. Vi kan let se, at patient nr. 2, som er en 69-årig kvinde har to tryksår af sværhedsgrad 1 og 2. Patient nr. 1 (55-årig mand) har ingen tryksår og optræder derfor ikke i tryksårstabellen.
Hvis vi ønsker at vide, hvor mange procent af patienterne, som har mindst et tryksår, skal vi blot dividere antallet af unikke id’er i tryksårstabellen med antallet af id’er i patienttabellen, 4 / 13 = 31%. Prøv samme øvelse på data i Tabel 3.1.
Det er tilsvarende enkelt at undersøge fordelingen af tryksårs sværhedsgrader, placeringer og årsager med data fra tryksårstabellen.
3.4 Benyt ISO-format til datoer
Skriv altid datoer i det eneste umisforståelige datoformat, der findes: åååå-mm-dd. Formatet er international standard (ISO 8601) for skrivning af datoer. Fx skrives 12. januar 2022 som 2022-01-12.
Kun sådan kan man sikre sig mod misforståelser mellem forskellige nationale og lokale datoformater. Hvis der fx står 02/01/22, har vi ingen jordisk chance for at vide, om der menes den 1., 2. eller 22. januar eller februar og i hvilket århundrede.
3.5 Benyt bindestreg til CPR-numre
Skriv altid CPR-numre med bindestreg, fx 012345-6789. På den måde tvinger man Excel og andre “hjælpsomme” dataprogrammer til at opfatte CPR-nummer som en tekstvariabel. I modsat fald risikerer man, at CPR opfattes som et tal, og at foranstillede nuller bliver fjernet.
3.6 Vælg det rigtige system til indtastning og lagring af data
Det fornuftige valg af databasesystem afhænger bl.a. af projektets størrelse, kompleksitet, forventede levetid og behovet for lagring af personfølsomme oplysninger. Og så man skal være opmærksom på forskellen mellem dataindtastning og datalagring. De to foregår ofte helt adskilt. Man kan sagtens indtaste data på en webformular og lagre dem i Excel eller en SQL-database. Tilsvarende kan man benytte Excel til indtastning af data, som siden eksporteres og lagres i kommaseparerede tekstfiler.
3.6.1 Tekstfiler
Det eneste reelt fremtidssikre format til lagring af data er tekstfiler. En tekstfil lagrer data i form at tegn og symboler, i praksis bogstaver, tal og udvalgte specialtegn som fx bindestreg. Tekstfiler kan læses af både mennesker og computere, og der findes næppe noget noget dataprogram i fortid, nutid og fremtid, som ikke kan både læse og skrive data i tekstfiler. Derfor er teksfiler særligt velegnede til langtidsopbevaring af data og til udveksling af data mellem systemer og analyseprogrammer.
Tekstfiler opbevarer data i rækker og kolonner som beskrevet ovenfor. Den første række indeholder variabelnavne, og herefter rummer hver række én post. Alle rækkerne skal være lige lange, dvs. indeholde det samme antal kolonner, og alle felter skal være udfyldte – også når data mangler.
Kolonnerne adskilles af et separatortegn, som i princippet kan være hvad som helst, så længe dette tegn ikke benyttes til andet end adskillelse af kolonner. Mest almindeligt at nok kommategn (,). Men på dansk (og mange andre sprog) kan det være uhensigtsmæssigt at benytte komma, fordi vi også bruger det som decimalseparatortegn. I stedet kan man benytte semikolon (;) eller tabulatortegn ( ).
Data til vores registrering af fødselskomplikationer kunne fx se således ud i en teksfil:
id;dt;ga;bw;lac;note
1;2020-01-28;264;2810;0;NA
2;2020-01-28;282;3820;3a;sædefødsel
3;2020-01-29;276;3310;0;NA
4;2020-01-30;294;4200;0;NA
5;2020-01-30;279;3500;0;NA
6;2020-02-01;280;3210;1;NA
Tekstfiler bærer ofte efternavnet “csv” (comma separated values) eller “tsv” (tabulator separated values).
Tekstfiler egner sig dårligt til dataindtastning. Det er simpelthen for svært at holde styr på kolonner og rækker. I stedet kan man, som nævnt, indtaste data i et dedikeret indtastningsprogram eller regneark og siden gemme data i tekstformat.
3.6.2 Regneark
Regneark har én stor fordel over alle andre systemer til datalagring: De er let tilgængelige både i anskaffelse og i brug. Har man ikke en licens til Microsoft Excel, finder der gratis alternativer, fx LibreOffice, som ikke lader noget tilbage at ønske. Og enhver sundhedsarbejder kan efter få minutters introduktion finde ud af at indtaste data og foretage beregninger i regneark. Desuden tillader regneark dataindtastning direkte i databasen (regnearket selv), og de rummer enkle faciliteter til validering af data ved indtastning.
Men regneark rummer også nogle faldgruber, man som dataarbejder let ramler i. Et studie fra 2021 fandt, at 30% af 10.000 publicerede genetiske studier indeholdt datafejl pga. Excels autokorrektions-“facilitet” [3]. Desuden er det begrænset, hvor mange data, der er plads til i et regneark. I september-oktober 2020 mistede den engelske sundhedsvæsen data om næsten 16.000 covid-19-tilfælde pga. overfyldte regneark, som uden at gøre væsen af sig, bare slettede de poster, der ikke var plads til [4].
Mange kender problemet med cpr-numre, som får slettet foranstillede 0’er, fordi Excel tror, at et cpr-nummer er en numerisk variabel.
Regneark forsøger at være hjælpsomme ved selv at gætte sig til datatyper og ovenikøbet konvertere data fra en type til en anden uden først at spørge om lov. Det kan i nogle situationer være nyttigt. Men til vores formål er det helt ødelæggende.
Derfor, hvis man vælger – og det kan der være gode grunde til – at benytte regneark til indsamling og opbevaring af data kan man med fordel forsøge at overholde disse principper til forebyggelse af typiske regnearksfejl:
Fasthold rektangulære data: Hold fast i, at et datasæt er en rektangulær størrelse med rækker og kolonner. Rækkerne repræsenterer poster, og kolonnerne repræsenterer variable. Hver række har lige mange kolonner, og alle felter er udfyldt (eventuelt med “NA”).
Undgå overskrifter i flere niveauer og flettede felter: Den første række i datasættet skal indeholde variabelnavne – intet andet. Alle efterfølgende rækker skal indeholde poster – intet andet.
Tildel datatype til alle kolonner: Beslut og håndhæv én og kun en datatype per kolonne, og indfør fornuftige regler for datavalidering allerede ved indtastning, så det bliver svært at taste forkerte data ind.
Beskyt rådata: Gem rådata på deres helt eget faneblad, som ikke må indeholde andet end de ubearbejdede dataelementer fra indtastningen. Mellemregninger, afledte variable, grafer og andet skrammel bør henvises til separate faneblade.
Lås regnearket eller dele af det: Det er måske ikke nødvendigt med kodeordsbeskyttelse. Låsningen har blot til hensigt at forhindre, at man uforvarende kommer til at overskrive rådata og formler.
Hvis man har brug for at gemme personfølsomme oplysninger, er regneark no-go. De er simpelthen for let tilgængelige.
Kort sagt: regneark kan være nyttige til især mindre, lokale projekter med overskuelige datamængder, og hvor kun en eller få personer ad gangen skal have adgang til data. Men hvis projektet omfatter personfølsomme oplysninger, store datamængder eller mange samtidige brugere måske med forskellige roller, er der ingen vej uden om specialbyggede løsninger.
3.6.3 Dedikerede databasesystemer
SQL-databaser, fx SQL Server, MySQL og Oracle, er skabt til at rumme ubegrænsede datamængder og levere ekstremt hurtige dataudtræk. SQL-databaser forudsætter, at man har helt styr på datastruktur og datatyper og rummer avancerede faciliteter til styring af brugere og adgange, som kan tildeles enkeltbrugere og brugergrupper helt ned på post- og feltniveau. Derfor egner SQL-databaser sig til opbevaring af personfølsomme data.
SQL-databaser indeholder sjældent faciliteter til direkte indtastning af data. Det er derfor nødvendigt at opbygge skræddersyede indtastningsformularer i dertil egnede programmer.
Det kræver særlige kompetencer – ofte hele uddannelser – at opbygge og vedligeholder SQL-databaser og at bygge dataindtastningsformularer. Med mindre man allerede har disse kompetencer i sit udviklingsteam, kan det blive en både dyr og tidskrævende affære at bruge SQL-databaser til mindre lokale udviklingsprojekter.
3.6.4 Integerede dataindsamlings- og lagringssystemer
Integrerede systemer forsøger at gøre det let både at opbygge robuste web-baserede indtastningsformularer, sikker og ubegrænset datalagring, effektiv styring af brugere og roller og let adgang til dataudtræk til videre behandling og analyse.
Der findes mange kommercielle produkter i denne kategori, fx SurveyXact og Survey Monkey, som gør det let at oprette dataindsamlingsformularer og spørgeskemaer. Men i skrivende stund er REDCap-systemet [5] efter min mening stjernen.
REDCap er open source, hvilket gør systemet frit og gratis tilgængeligt. Ligesom dedikerede databasesystemer er REDCap et serversystem, som forudsætter at man har forstand på opsætning og drift af databaser og servere. Men når først systemet er sat op, er det relativt enkelt at gå til. Efter en kort introduktion vil de fleste i løbet af en eftermiddag kunne opbygge en enkel database med tilhørende indtastningsformular inklusiv datavalidering. Og så er REDCap godkendt til lagring af persondata i forbindelse med kliniske forsøg og kvalitetsudvikling.
Fra REDCap er det let både at eksportere rådata i forskellige formater og at læse data direkte ind i gængse statistikprogrammer. Man behøver altså ikke længere besvære sig med manuelle dataudtræk, hvilket ofte er nødvendigt med andre systemer.
Hvis ikke man selv har forstand eller resurser til at opsætte og vedligeholde sin egen REDCap-server (og det har de færreste), kan man leje serverplads i professionelt drevne REDCap-systemer rundt om i verden. I Danmark har flere regioner REDCap og stiller det gratis til rådighed for forskere og udviklere.