Første udtræk

Fra register til analyseklar data — trin for trin

Published

June 6, 2026

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.

Important

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:

  1. Download R: cran.r-project.org
  2. Download RStudio: posit.co/download/rstudio-desktop
  3. Å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.

Note

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å.

Note

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 fakeregs
library(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")
Tip

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 200
Tip

I 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?
NoteKreditering

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ækker

Hvad skete der?

  • open_dataset() åbnede en doven forbindelse — ingen data i R endnu
  • filter() og select() sendte instruktioner til Arrow/DuckDB — stadig ingen data i R
  • collect() 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.

Tip

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.

Warning

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")   # forskel

Disse 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:


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.

Back to top