Case-control

Nested case-control - sampl kontroller til dine cases

Published

July 2, 2026

Denne side fortsætter fra Byg din studiepopulation. I et nested case-control-studie er din gruppe fra forsiden i stedet dine cases (dem der fik udfaldet), og deres index-dato er udfaldsdatoen. Til hver case sampler du et antal kontroller: personer uden udfaldet, der var i risiko netop da casen fik sit udfald.

Warning

Stadig under udvikling. Strukturel vejledning - tilpas til dit eget projekt, og bekræft pakkenavne (heaven::incidenceMatch, Epi::ccwc) på dit projekt før brug.

Note

Funktioner brugt her. left_join() (tilknyt en variabel) og transmute() (lav nye kolonner, behold kun dem) forklares i Sammenligningskohorte og Kobl udtræk sammen. pmin(), if_else() og as.factor() er i Guide til funktioner. Nyt her: incidenceMatch() / Epi::ccwc() til sampling og survival::clogit() til analysen.

Note

Kohorte eller case-control? Begge designs kan besvare det samme spørgsmål; case-control er især effektivt, når udfaldet er sjældent, eller når en kovariat er dyr at udtrække for hele kohorten. Se Fase 1 - hvilken type studie for designvalget.

Case-control vs. nested case-control - hvad er forskellen?
  • Klassisk case-control: du finder cases (med udfaldet) og vælger kontroller (uden udfaldet) fra befolkningen, ofte uden en defineret kohorte med opfølgning bag. Eksponering måles typisk bagudrettet (fx interview) - sårbart over for recall- og selektionsbias, og valget af kontroller er svært.
  • Nested case-control: case-control-studiet ligger inde i en defineret kohorte (fx en registerkohorte, der følges over tid). Cases er dem, der får udfaldet under opfølgningen; kontroller samples fra dem, der var i risiko (udfaldsfri) netop da casen fik udfaldet (risk-set / incidens-densitets-sampling). Eksponering kommer fra registerdata indsamlet før udfaldet → mindre recall-bias.

I registerforskning på DST laver man stort set altid den nestede variant: kohorten findes allerede i registrene. Fordele: eksponering er målt på forhånd, og odds ratio fra incidens-densitets-sampling estimerer rate-/hazard ratio uden antagelse om sjældent udfald. Det er den, denne side viser.


Princippet: incidens-densitets-sampling

Kontroller udvælges ved risk-set / incidens-densitets-sampling: for hver case udtrækkes kontroller, der på casens index-dato (= udfaldsdatoen) (1) endnu ikke har fået udfaldet og (2) opfylder inklusionskriterierne. En person kan være kontrol for én case og senere selv blive case - det er korrekt i dette design (og det er præcis det, risikosættet fanger).

Det er den samme mekanik som matchingen i Sammenligningskohorte - kun “event” er ændret: her er det udfaldet (case), ikke en eksponering. Derfor genbruger denne side også person-tabellen derfra.


Trin 3 - Byg datasættet til matching

(Trin 1 og 2 - identificér cases og ekskludér prævalente tilfælde - ligger på forsiden.)

Du skal bruge én række per person med matchvariable og de datoer, eligibilitet afhænger af. Byg den præcis som poolen i Sammenligningskohorte, Trin 3-4 (demografi + earliest_bef + dødsdato + udvandringsdato + lookback). Til case-control gælder dog:

  • Eksponering er ikke et eligibilitetskrav her (modsat sammenligningskohorten, hvor en kontrol skal være eksponeringsfri på index). I case-control er eksponering netop det, du undersøger: du måler den for både cases og kontroller bagefter og bruger den ikke til at afgøre, hvem der kan være kontrol. En kontrol skal blot være udfaldsfri (og opfylde dine øvrige kriterier) på casens index.
  • Du skal vide, hvem der er case (fik udfaldet) og hvornår (udfaldsdato = index).
Vis koden: byg datasættet til matching
#=====================================================
# Trin 3: byg datasættet til matching
#=====================================================
# 'befolkning' = én række per person fra Sammenligningskohorte (pnr, sex, birth_year,
#                death_date, emigration_date, earliest_bef_year). Se Sammenligningskohorte, Trin 3-4.
STUDIE_SLUT <- as.Date("2022-12-31")              # vi vælger: sidste dag i studiet
udfald <- readRDS("sti/til/outcome_dates.rds")    # pnr, first_outcome_date (FØRSTE udfald; NA = aldrig)

alle <- befolkning %>%
  left_join(udfald, by = "pnr") %>%               # tilføj udfaldsdato (NA = aldrig udfald)
  transmute(                                       # behold KUN de kolonner vi navngiver
    pnr,
    case       = if_else(!is.na(first_outcome_date), 1L, 0L),  # 1 = case (fik udfaldet), 0 = potentiel kontrol
    sex        = as.factor(sex),                   # matchvariabel SKAL være factor/character
    birth_year = as.factor(birth_year),            # matchvariabel
    case_index = first_outcome_date,               # casens index = udfaldsdatoen (NA hvis aldrig)
    # end_fu = hvornår personen forlader risikosættet: den TIDLIGSTE af død, udvandring,
    #          eget udfald (de bliver selv case der) eller studieslut. pmin = tidligste.
    end_fu     = pmin(death_date, emigration_date, first_outcome_date, STUDIE_SLUT, na.rm = TRUE)
  )

Trin 4 - Sampl kontroller

To veje. Begge laver incidens-densitets-sampling; vælg én.

Vej A - heaven::incidenceMatch() (søster til exposureMatch() fra Sammenligningskohorte, men “event” er udfaldet).

Vis koden (Vej A): sampl med incidenceMatch()
#=====================================================
# Trin 4 (Vej A): sampl med incidenceMatch()
#=====================================================
library(heaven)   # incidenceMatch

# Argument (venstre for =) <- værdi vi sætter (typisk et kolonnenavn i anførselstegn)
matched <- incidenceMatch(
  ptid         = "pnr",                  # kolonnen med person-id
  event        = "case",                 # kolonnen der er 1 for case (udfald), 0 for potentiel kontrol
  terms        = c("sex", "birth_year"), # matchvariable (eksakt match; factor/character)
  data         = alle,                   # datasættet fra Trin 3
  n.controls   = 5,                      # antal kontroller per case
  case.index   = "case_index",           # casens index-dato (udfaldsdatoen)
  end.followup = "end_fu",               # hvornår man ophører med at kunne være kontrol
  seed         = 20260620                # reproducerbarhed
)
# Output: data.table med 'case.id' der identificerer hvert matchsæt (1 case + dens kontroller)

Vej B - Epi::ccwc() (counter-matched/risk-set sampling ud fra ind- og udtrædelsestider). Bekræft argumenter med ?Epi::ccwc.

Vis koden (Vej B): sampl med Epi::ccwc()
#=====================================================
# Trin 4 (Vej B): sampl med Epi::ccwc()
#=====================================================
library(Epi)   # ccwc - case-control within cohort

kohorte <- alle %>%
  mutate(
    entry = as.Date("2010-01-01"),                # studiestart (tilpas; fx 18-årsdag eller første eligible dato)
    exit  = end_fu,                               # ud-tid = slut på risikotid (fra Trin 3)
    fail  = case                                  # 1 hvis personen er case ved exit
  )

ncc <- ccwc(
  entry    = entry, exit = exit, fail = fail,     # ind-tid, ud-tid, udfald ved exit
  controls = 5,                                   # kontroller per case
  match    = list(sex, birth_year),               # matchvariable
  include  = list(pnr),                           # behold pnr i output
  data     = kohorte
)
# Output: matchsæt-id'et hedder her 'Set' (ikke 'case.id')
Note

Samme regler som i Sammenligningskohorte: anvend inklusions-/eksklusionskriterier FØR sampling og på alle (cases + pool); sæt en seed; og tag stilling til med/uden replacement (kontroller kan typisk bruges til flere cases) - det skal håndteres i analysen. incidenceMatch() håndterer selv risk-set-tidsdimensionen via case.index + end.followup.


Analyse (kort)

Selve analysen hører til Regression (Fase 13) - her blot kort, så du ved, hvor det bærer hen. Matchede case-control-data kan analyseres med betinget logistisk regression (survival::clogit() med et strata()-led per matchsæt), så matchningen respekteres; odds ratio fra et incidens-densitets-design estimerer rate-/hazard ratio. Det er standardtilgangen for matchede case-control-studier. Inden analysen tilføjer du eksponering og covariater til de matchede personer (fra Fase 11/Fase 12). Matchsæt-id’et hedder case.id (Vej A) eller Set (Vej B).


Hvad nu?

Du har et matchet datasæt (cases + kontroller) med et matchsæt-id (case.id eller Set). Brug pnr til at udtrække eksponering og covariater for alle i datasættet:

cc_pnrs <- unique(matched$pnr)   # alle pnr'er (cases + kontroller) til de øvrige udtræk
Udtræk Fase
Eksponering + covariater Fase 11
Komorbiditet (NMI) NMI
Saml til ét analysedatasæt Fase 12
Betinget logistisk regression Fase 13

Se også

Back to top