DARTER - Projekt 708421
Projektspecifik vejledning til BS & Demens-kohortestudiet
DARTER - Diabetes And inteRgenerational Transmission of hEalth determinants over the life couRse (projekt 708421).
Denne sektion er kun for dem der arbejder på DARTER-projektet. Indholdet her bygger ovenpå den generelle DST-vejledning og tilføjer det projekt-specifikke.
Søgbar variabel- og registeroversigt for DARTER Alle variable og registre der er ansøgt i projektet er samlet i en søgbar tabel: steno-aarhus.github.io/darter-project →
Ny på projektet? Start med den generelle vejledning og vend tilbage hertil: → Fase 1 - Planlæg dit studie → Fase 2 - R: det allermest nødvendige → Fase 3 - Log ind på DST
I denne sektion
| Side | Indhold |
|---|---|
| Denne side | Setup (fastreg + duckplyr) og en genanvendelig LPR-udtræksfunktion |
| Registersti og datastores | Bekræftede stier og adgangsmetoder til alle registre på 708421 |
| DARTER-specifikke faldgruber | Quirks der er specifikke for dette projekt |
Initielt setup for DARTER
Registerdata på DARTER indlæses med fastreg::read_register("navn") - præcis som i den generelle vejledning. Du skal blot pege fastreg på DARTERs parquet-mappe én gang per script; se Indlæsningsskabeloner.
Installér nyeste duckplyr i starten af hver session
DST har duckplyr forudinstalleret, men i en gammel version, der mangler funktionalitet - flere af mønstrene i denne vejledning virker ikke med den. Hent derfor den nyeste version fra CRAN, og gentag efter hvert logout / server-reset (resettet sætter pakken tilbage til den gamle, forudinstallerede version). duckplyr leverer DuckDB-motoren bag compute() (se Store registre nedenfor).
install.packages("duckplyr") # hent nyeste CRAN-version - kør inden library()
packageVersion("duckplyr") # tjek versionen i din session; >= 1.1 er finInden du kører et script: kontroller at path_output øverst i hvert script peger på din workspace-mappe (defineret under Basestier i Registersti og datastores).
Anbefaling: lav en hjælpefunktion til LPR-udtræk
LPR-udtræk kræver ofte at du kombinerer LPR2 somatisk, LPR2 psykiatrisk og LPR3 - og gør det samme for hvert nyt udfald i projektet. Hvis der er flere udfald/kovariate kan det godt betale sig at samle dette i én genanvendelig funktion fremfor at kopiere koden gentagne gange.
Fordele: - Ét sted at rette, hvis noget ændres (fx et nyt register eller en ny kolonne) - Kodeblokken til hvert udfald reduceres fra ~40 linjer til ét funktionskald - Fejl introduceres ét sted i stedet for i hver kopi
Sådan laver du funktionen - definer den øverst i dit script eller i en separat functions.R-fil:
Se den fulde get_lpr_diagnoses()-funktion
library(fastreg)
library(dplyr)
# icd_codes: 3-tegns ICD-koder UDEN D-præfiks, fx c("F03", "G30"). PÅKRÆVET (se advarsel).
# diagtypes: diagnose-TYPE - "A"=aktions, "B"=bi, "G"=grundmorbus (kun LPR2). Standard c("A", "B").
get_lpr_diagnoses <- function(pnr_vector, icd_codes, diagtypes = c("A", "B")) {
#-------------------------------------------------------------
# Åbn registre (LPR2 somatisk + psykiatrisk + LPR3)
#-------------------------------------------------------------
lpr_adm <- read_register("lpr_adm") %>% rename_with(tolower) # LPR2 somatisk kontakter
lpr_diag <- read_register("lpr_diag") %>% rename_with(tolower) # LPR2 somatisk diagnoser
psyk_adm <- read_register("t_psyk_adm") %>% rename_with(tolower) %>%
rename(pnr = v_cpr, recnum = k_recnum) # LPR2 psykiatrisk kontakter
psyk_diag <- read_register("t_psyk_diag") %>% rename_with(tolower) %>%
rename(recnum = v_recnum) # LPR2 psykiatrisk diagnoser
lpr3_k <- read_register("lpr_a_kontakt") %>% rename_with(tolower) %>%
filter(lprindberetningssystem == "LPR3") # KRITISK: behold kun rækker fra LPR3-systemet - undgå overlappende rækker
lpr3_d <- read_register("lpr_a_diagnose") %>% rename_with(tolower) # LPR3 diagnoser
#-------------------------------------------------------------
# LPR2 somatisk
#-------------------------------------------------------------
lpr2_dx <- lpr_adm %>%
semi_join(tibble(pnr = pnr_vector), by = "pnr") %>% # kun kohorten - mønstret er forklaret i Fase 9 (Hospitalskontakter)
select(pnr, recnum, date_contact = d_inddto) %>%
inner_join(
lpr_diag %>% filter(c_diagtype %in% !!diagtypes) %>% select(recnum, c_diag, c_diagtype),
by = "recnum"
) %>%
filter(substr(c_diag, 2, 4) %in% !!icd_codes) %>% # filtrér på KODER FØR collect() - kun relevante rækker hentes ind i R
collect() %>%
mutate(icd3 = substr(c_diag, 2, 4)) # "DF03" -> "F03": fjern D-præfiks
#-------------------------------------------------------------
# LPR2 psykiatrisk
#-------------------------------------------------------------
lpr2_psyk_dx <- psyk_adm %>%
semi_join(tibble(pnr = pnr_vector), by = "pnr") %>% # kun kohorten - se Fase 9
select(pnr, recnum, date_contact = d_inddto) %>%
inner_join(
psyk_diag %>% filter(c_diagtype %in% !!diagtypes) %>% select(recnum, c_diag, c_diagtype),
by = "recnum"
) %>%
filter(substr(c_diag, 2, 4) %in% !!icd_codes) %>%
collect() %>%
mutate(icd3 = substr(c_diag, 2, 4))
#-------------------------------------------------------------
# LPR3
#-------------------------------------------------------------
lpr3_dx <- lpr3_k %>%
semi_join(tibble(pnr = pnr_vector), by = "pnr") %>% # kun kohorten - se Fase 9
select(pnr, dw_ek_kontakt, date_contact = kont_starttidspunkt) %>%
inner_join(
lpr3_d %>%
filter(diag_kode_type %in% !!diagtypes, # NB: "G" (grundmorbus) findes kun i LPR2, ikke LPR3
is.na(senere_afkraeftet) | senere_afkraeftet != "Ja") %>%
select(dw_ek_kontakt, c_diag = diag_kode, c_diagtype = diag_kode_type),
by = "dw_ek_kontakt"
) %>%
filter(substr(c_diag, 2, 4) %in% !!icd_codes) %>%
collect() %>%
mutate(date_contact = as.Date(date_contact), # datetime → dato
icd3 = substr(c_diag, 2, 4))
bind_rows(lpr2_dx, lpr2_psyk_dx, lpr3_dx) # returner samlet tabel
}semi_join eller filter(... %in% ...)? Begge udvælger rækker, men bruges til hver sit:
semi_join(tibble(pnr = pnr_vector), by = "pnr"): til din kohorte. En stor R-vektor af pnr’er skubbes mere pålideligt ned i Arrow/DuckDB som en lille tabel end etfilter(pnr %in% ...), der kan blive langsomt eller helt afvist (især med ældreduckplyr).filter(substr(c_diag, 2, 4) %in% !!icd_codes): til en kort kodeliste. Her erfilterfint - men husk!!, der sender den lokale R-vektor ind i forespørgslen (uden!!leder DuckDB efter en kolonne med det navn). Baggrunden står i Udtræk fra LPR.
Brug funktionen - ét kald pr. udtræk, skift kun icd_codes
kohort <- readRDS("datasets/full_cohort.rds")
pnr_liste <- unique(kohort$pnr)
# Angiv de ICD-koder du vil have (3 tegn, uden D). Funktionen filtrerer FØR data hentes ind i R.
demens_dx <- get_lpr_diagnoses(
pnr_vector = pnr_liste,
icd_codes = c("F00", "F01", "F02", "F03", "G30", "G31"), # demens (G30/G31 er ICD G-koder)
diagtypes = c("A", "B") # "A"=aktions, "B"=bi, "G"=grundmorbus (kun LPR2). Udvid fx til c("A","B","G")
)
# Returnerer én række pr. diagnose: pnr | date_contact | c_diag | icd3 | c_diagtype (A/B/G)
# c_diagtype gør sensitivitetsanalyser mulige, fx kun aktionsdiagnoser: filter(c_diagtype == "A")
# Flere udfald? Giv unionen af alle koder her og opdel bagefter i R på icd3 - så scannes registrene kun én gang.
# Første forekomst efter index-dato pr. person
demens <- demens_dx %>%
inner_join(kohort %>% select(pnr, index_date), by = "pnr") %>%
filter(date_contact > index_date) %>%
group_by(pnr) %>% arrange(date_contact) %>% slice(1) %>% ungroup() %>%
select(pnr, demens_dato = date_contact)
resultat <- kohort %>% select(pnr) %>% left_join(demens, by = "pnr")
saveRDS(resultat, "datasets/extract_dementia.rds")Angiv altid icd_codes - hent aldrig alle diagnoser. Funktionen filtrerer på dine koder før collect(), så kun de relevante rækker hentes ind i R’s RAM. Derfor er icd_codes et påkrævet argument.
Fjern ikke kode-filteret for at “tage det hele”: hver A/B/G-diagnose for en hel kohorte på tværs af LPR2 og LPR3 kan blive millioner af rækker. Det fylder R’s hukommelse, og et så tungt udtræk kan få dig smidt af DST-serveren.
Dette er DARTER-varianten (med read_register() og de bekræftede registernavne for 708421, pr. juni 2026). Den generelle open_dataset()-version og forklaringen bag mønstret står i Udtræk fra LPR.
Store registre - compute() vs collect()
get_lpr_diagnoses() afslutter hvert udtræk med collect() (henter ind i R). På et meget stort register (fx LMDB eller laboratoriesvar) kan du i stedet pipe til compute(), som materialiserer resultatet i DuckDB uden at fylde R’s RAM - reducér altid med semi_join()/filter()/select() før compute(). Selve teknikken og forskellen på compute() og collect() er forklaret generelt i Fase 5 - Udtræk trin for trin.
Se også
get_lpr_diagnoses() ovenfor pakker mønstret fra den generelle vejledning ind:
- Fase 8 - Find dine registre: hvilket register indeholder hvad
- Fase 9 - Hospitalskontakter (LPR): forklaringen bag to-fase strategien, LPR2/LPR3 og D-præfikset
- Fase 10 - Byg din kohorte: her laver du
full_cohort.rds, som funktionen ovenfor læser - Registersti og datastores: de bekræftede stier på 708421
Videre i pipelinen: Fase 7 - Inspicér data · Fase 12 - Saml & klargør datasættet · Fase 14 - Eksport og hjemsendelse