---
title: "Calibrating to a reference survey"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Calibrating to a reference survey}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

Calibration usually targets **known** population totals from a census or frame.
Often you do not have those, but you do have a larger, well-established survey you
trust: the official continuous household survey (in Uruguay, the ECH), a labour
force survey, a census long form. `reference_sample()` lets you calibrate your
sample to the **design-weighted totals of that reference survey** instead of a
frame. The targets are then *estimates*, not census figures, and that has one
consequence you must handle: their sampling variability.

```{r setup}
library(weightflow)
```

## A reference survey is a weighted data frame

Wrap the reference microdata together with its design weights and pass it as the
`population` argument of `step_calibrate()` (or `step_model_calibration()`), with
a `formula` naming the calibration variables. Here we build a stand-in reference
by drawing a weighted subsample of the known `population`:

```{r ref}
set.seed(1)
N   <- nrow(population)
ref <- population[sample(N, 2000), ]
ref$w <- N / nrow(ref)          # the reference survey's own design weight

fit <- weighting_spec(sample_survey, base_weights = pw) |>
  step_calibrate(method = "raking", formula = ~ region + sex,
                 population = reference_sample(ref, "w")) |>
  prep()

# the calibration hit the reference's *weighted* region totals:
tapply(collect_weights(fit)$.weight, sample_survey$region, sum)
tapply(ref$w, ref$region, sum)
```

A reference whose weights are all `1` reproduces the plain-frame behaviour
exactly, because it is just an unweighted count of the frame:

```{r frame-equivalence}
frame_ref <- population
frame_ref$w <- 1
w_ref   <- (weighting_spec(sample_survey, base_weights = pw) |>
  step_calibrate(method = "raking", formula = ~ region,
                 population = reference_sample(frame_ref, "w")) |> prep())$final_weight
w_plain <- (weighting_spec(sample_survey, base_weights = pw) |>
  step_calibrate(method = "raking",
                 margins = list(region = c(table(population$region)))) |> prep())$final_weight
all.equal(w_ref, w_plain)
```

## Estimated totals carry variance, so propagate it

Because the targets are estimated from the reference survey, treating them as
fixed understates the variance of your estimates. To carry that component
through, pass the reference survey's **replicate weights** to
`reference_sample(..., replicates =)`. Each bootstrap replicate of your sample is
then paired with a reference replicate and re-estimates the totals from it
(Opsomer and Erciulescu 2021):

```{r variance}
# replicate weights for the reference survey (its own design)
rep_ref <- bootstrap_weights(weighting_spec(ref, base_weights = w),
                             replicates = 100, strata = "region", psu = "psu",
                             seed = 1, progress = FALSE)$replicates

boot <- weighting_spec(sample_survey, base_weights = pw) |>
  step_calibrate(method = "raking", formula = ~ region + sex,
                 population = reference_sample(ref, "w", replicates = rep_ref)) |>
  bootstrap_weights(replicates = 100, strata = "region", psu = "psu",
                    seed = 2, progress = FALSE)

boot_total(boot, "income")
```

Without `replicates`, the totals are treated as **fixed**, a reasonable
approximation when the reference is much larger than your sample (the same
assumption you make when calibrating to another survey's *published* totals),
but it omits the extra variance from estimating them.

## Only the bootstrap propagates this component

The pairing that carries the reference variance is a bootstrap mechanism:
`jackknife_weights()` treats the estimated totals as fixed **even when**
`replicates` is supplied. So when the estimated-totals component matters, use the
bootstrap. This is stated in `?reference_sample`; the practical rule is: reference
survey with replicate weights -> `bootstrap_weights()`.

## When to use which

- **Census / frame totals available:** plain `step_calibrate(margins = ...)`,
  with no `reference_sample()` needed.
- **Only a trusted larger survey:** `reference_sample()`; pass its replicate
  weights and use the bootstrap if the totals' sampling error is non-negligible.
- **Reference much larger than your sample:** you may treat the totals as fixed
  (omit `replicates`); the price is small.
