Første udtræk
Fra register til analyseklar data — trin for trin
Denne side viser det komplette forløb fra et råt register til et gemt datasæt klar til analyse. Du vil se det mønster, der går igen i næsten alle registerudtræk.
Disse eksempler kan ikke køres på DST-serveren. Det syntetiske datasæt (fakeregs) er ikke tilgængeligt der. Du skal bruge RStudio installeret lokalt på din computer:
- Download R: cran.r-project.org
- Download RStudio: posit.co/download/rstudio-desktop
- Åbn RStudio, opret et nyt script (File → New File → R Script), og kopier koden derover.
Når du er klar til at arbejde med rigtige registerdata, bruger du det samme mønster — men på DST-serveren og med dine projekts registerdata.
Eksemplerne bruger syntetiske data fra pakken fakeregs (MIT-licens, Anders Aasted Isaksen, Steno Diabetes Center Aarhus) — opdigtede personer med DST-registrenes struktur og kolonnenavne. Pakken bruger generate_*()-funktioner til at oprette syntetiske data, som du gemmer som parquet og øver open_dataset() på.
Næste skridt: hospitalsdiagnoser (LPR) Dette eksempel bruger lpr_adm (hospitalkontakter — kun kontaktdatoer, ingen diagnosejoin). Når du arbejder med diagnosedata fra LPR (ICD-koder), gælder ekstra regler: registret er delt i to perioder (LPR2 og LPR3), koder har et D-præfiks der skal fjernes, og du skal vælge diagnosetyper. Alt dette gennemgås i Fase 9 — Hospitalskontakter (LPR).
Forberedelse: installer fakeregs og generer syntetiske data
fakeregs er ikke på CRAN — installer direkte fra GitHub:
install.packages("pak") # kun første gang
pak::pak("steno-aarhus/fakeregs") # installer fakeregslibrary(fakeregs) # syntetiske DST-registerdata
library(dplyr) # filter, select, mutate, collect
library(arrow) # open_dataset, write_parquet
# Generer syntetiske data og gem som parquet (gøres kun én gang)
bp <- generate_background_pop() # syntetisk grundpopulation
bef_synth <- generate_bef(background_df = bp) # syntetisk BEF-register
lpr_synth <- generate_lpr_adm(background_df = bp) # syntetisk LPR-kontaktregister
dir.create("synth_data/bef", recursive = TRUE, showWarnings = FALSE) # opret mapper
dir.create("synth_data/lpr_adm", recursive = TRUE, showWarnings = FALSE)
write_parquet(bef_synth, "synth_data/bef/bef.parquet") # gem som parquet
write_parquet(lpr_synth, "synth_data/lpr_adm/lpr_adm.parquet")Stien er relativ til dit working directory. "synth_data/bef/" oprettes i den mappe R er sat til at arbejde i — tjek hvilken det er med getwd(). Vil du gemme et andet sted, brug en fuld sti: "C:/Users/ditbrugernavn/projekter/synth_data/bef/".
Nu kan du øve open_dataset() præcis som på DST-serveren.
Trin 1 — Definer din studiepopulation
Ethvert udtræk starter med en liste af pnr’er — de personer du ønsker data for. I praksis kommer den fra dit kohorte-script. Her bygger vi en lille øvelseskohorte direkte fra BEF-registret.
trin1_kohorte.R
# Åbn BEF — doven forbindelse, ingen data i R endnu
bef_data <- open_dataset("synth_data/bef/") %>%
rename_with(tolower)
# Hent 200 tilfældige pnr'er som din kohort
kohort_pnrs <- bef_data %>%
filter(year == 2015) %>% # tag ét snapshotår
select(pnr) %>%
collect() %>% # HER hentes data ind i R
slice_sample(n = 200) %>%
pull(pnr)
length(kohort_pnrs) # tjek: bør returnere 200I et rigtigt projekt er kohort_pnrs en vektor du har bygget i et tidligere script og genlæser med readRDS("datasets/full_cohort.rds") %>% pull(pnr).
Omform BEF-variable — hvad betyder koen, civst og reg?
Koden nedenfor er skrevet af Anders Aasted Isaksen (Steno Diabetes Center Aarhus) og er hentet direkte fra vignetten common_tasks_dplyr.qmd i pakken fakeregs (MIT-licens). Koden er gengivet uændret.
BEF-registret gemmer koen, civst og reg som koder — ikke som tekst. Denne omformning oversætter dem til analyseklare variable:
# Fortsætter fra Trin 1 — bef_data er allerede åbnet med open_dataset()
bef_renset <- bef_data %>%
filter(year == 2015, alder >= 18) %>%
select(pnr, year, foed_dag, koen, civst, reg, opr_land) %>%
collect() %>% # hent ind i R inden mutate
mutate(
foed_dato = as.Date(foed_dag), # dato-format
# koen: 1 = mand, 2 = kvinde (Anders Aasted Isaksen, fakeregs)
koen_tekst = if_else(koen == "1", "Mand", "Kvinde"),
# civst: ægteskabelig status (Anders Aasted Isaksen, fakeregs)
civil_status = case_when(
civst %in% c("G", "P") ~ "Gift/partner",
civst %in% c("F", "O", "E", "L") ~ "Skilt/enke",
civst == "U" ~ "Ugift",
TRUE ~ NA_character_
),
# reg: regionskoder (Anders Aasted Isaksen, fakeregs)
region = case_when(
reg == 81 ~ "Region Nordjylland",
reg == 82 ~ "Region Midtjylland",
reg == 83 ~ "Region Syddanmark",
reg == 84 ~ "Region Hovedstaden",
reg == 85 ~ "Region Sjælland",
TRUE ~ NA_character_
),
# opr_land: 5100 = Danmark (Anders Aasted Isaksen, fakeregs)
indvandrer = opr_land != 5100
)
head(bef_renset)Kilde: fakeregs/vignettes/common_tasks_dplyr.qmd, Anders Aasted Isaksen, Steno Diabetes Center Aarhus (MIT-licens).
Dette er kun et udsnit. Isaksens fulde vignette er mere gennemarbejdet og dækker yderligere variable og mønstre — se den direkte her: steno-aarhus.github.io/fakeregs/articles/common_tasks_dplyr.html
Trin 2 — Udtræk data fra et register
Nu trækker vi hospitalkontakter fra lpr_adm for vores kohorte. Mønstret er altid det samme: åbn → filtrer → vælg kolonner → collect.
trin2_udtraek.R
# Åbn lpr_adm — doven forbindelse
lpr_adm <- open_dataset("synth_data/lpr_adm/") %>%
rename_with(tolower)
# Udtræk: filter FØR collect — ellers crasher sessionen
kontakter <- lpr_adm %>%
filter(pnr %in% !!kohort_pnrs) %>% # kun vores kohort
select(pnr, recnum, d_inddto) %>% # kun de kolonner vi bruger
collect() # HER flyttes data ind i R
nrow(kontakter) # hvor mange kontaktrækker?
head(kontakter) # de første seks rækkerHvad skete der?
open_dataset()åbnede en doven forbindelse — ingen data i R endnufilter()ogselect()sendte instruktioner til Arrow/DuckDB — stadig ingen data i Rcollect()udførte forespørgslen og hentede kun de nødvendige rækker ind i R
Se Udtræk trin for trin for en detaljeret forklaring af doven evaluering.
Test på et lille udsnit først. Inden du kører et tungt udtræk på hele kohorten, så afprøv koden på nogle få personer eller rækker — så fanger du fejl hurtigt uden at vente. Fx filter(pnr %in% !!head(kohort_pnrs, 10)), eller collect() %>% head(100) mens du bygger koden.
Trin 3 — Byg analysevariable
Tilføj variabler med mutate() efter collect() — nu er du i R og kan bruge alle funktioner.
kontakter <- kontakter %>%
mutate(
dato = as.Date(d_inddto), # eksplicit dato-klasse
aar = as.integer(format(dato, "%Y")) # år fra kontaktdato
)Trin 4 — Gem og genindlæs
Gem med saveRDS() så næste script kan genindlæse det uden at køre hele udtrækkene igen.
trin4_gem.R
saveRDS(kontakter, "datasets/extract_kontakter.rds") # gem til disk — skift stien til din egen mappe
# Genindlæs i næste script:
kontakter <- readRDS("datasets/extract_kontakter.rds")Hvis du ikke skriver en fuld sti, gemmes filen i dit working directory. Kør getwd() for at se hvilken mappe det er.
datasets/-mappen gemmes kun lokalt på DST-serveren. Mellemresultater hjemsendres via outputkontrol — se 16 — Eksport og hjemsendelse.
Inspicér resultatet
Lige efter et udtræk bør du tjekke, at du fik det, du forventede:
head(kontakter) # de første seks rækker — ser det rigtigt ud?
nrow(kontakter) # antal rækker — som forventet?
length(unique(kontakter$pnr)) # hvor mange unikke personer?
colSums(is.na(kontakter)) # manglende værdier per kolonne
class(kontakter$d_inddto) # er datokolonnen Date? (ikke character)Hvis dit udtræk inkluderer eksklusionstrin — fx “fjern personer med tidlig diagnose” — er det god praksis at tælle N for hvert trin. Erstat raa og renset med dine egne variabelnavne:
# Skabelon — erstat raa og renset med dine egne variabelnavne:
cat("Rå udtræk: ", nrow(raa), "\n") # alle rækker før eksklusion
cat("Efter eksklusioner: ", nrow(renset), "\n") # efter hvert trin
cat("Ekskluderede i alt: ", nrow(raa) - nrow(renset), "\n") # forskelDisse linjer kan du ikke køre med de syntetiske øvelsesdata — de er en skabelon til brug, når du arbejder med dine egne data og har et eksklusionsforløb. Mønsteret gentages for hvert ekskluderingstrin og danner grundlag for et CONSORT-flowchart (et standardiseret flowdiagram der viser, hvor mange der blev ekskluderet ved hvert trin og hvorfor).
Dette er en hurtig fornuftskontrol. Den fulde værktøjskasse til at udforske data — summary(), table(), krydstabeller og NA-håndtering — gennemgås i Fase 7 — Inspicér din data.
Næste skridt
Du har nu lavet et komplet udtræk og gemt det. Næste skridt er at lære at udforske data grundigt:
- Fase 7 — Inspicér din data — den fulde værktøjskasse til at forstå hvad du har
- Fase 9 — Hospitalskontakter (LPR) — det komplette mønster for diagnoseudtræk
- Fase 11 — Joins og pivots — kobl to udtræk sammen
Kilde og tilpasning
Trin 1 (kohorte-opbygning fra BEF) er tilpasset fra Anders Aasted Isaksens vignette common_tasks_dplyr.qmd i fakeregs-pakken (MIT-licens, Steno Diabetes Center Aarhus). Trin 2–4 og tjeklisten er skrevet til denne vejledning.