Creates a survey::svydesign() object from a tbl_sample, using
the sampling design metadata (strata, clusters, weights, and
finite population corrections) captured during execute().
Usage
as_svydesign(x, ...)
# S3 method for class 'tbl_sample'
as_svydesign(
x,
...,
nest = TRUE,
method = NULL,
systematic_variance = c("warn", "approximate", "error")
)Arguments
- x
A
tbl_sampleobject produced byexecute().- ...
Additional arguments passed to
survey::svydesign(), or tosurvey::twophase()for a two-phase sample. In particular, you can passpps = survey::ppsmat(joint_matrix)to supply exact joint inclusion probabilities instead of the default Brewer approximation (see Details). Every argument must be named, and its name must be one the receiving function accepts:nestandmethodfollow the...and so are matched exactly, and a near miss such asnesis reported rather than forwarded. The design arguments themselves (ids,strata,weights,probs,fpc,data, andsubsetfor a two-phase sample) are derived from the sample and cannot be given here.- nest
If
TRUE(the default), relabel cluster ids to enforce nesting within strata, which suits most complex survey designs. Passed tosurvey::svydesign(). It has no effect on a two-phase sample, which is exported withsurvey::twophase(), and giving it there raises a warning.- method
For two-phase samples, the variance method passed to
survey::twophase(). One of"full","approx", or"simple". This argument is only accepted for two-phase samples.- systematic_variance
What to do about the variance approximation used for systematic stages: simple random sampling for
systematic, Brewer's forpps_systematic."warn"(default) applies it and warns once per call, naming every affected stage and its approximation."approximate"applies it silently, for a caller who has acknowledged it, and"error"refuses. Census stages are exempt, since a stage that took everything within reach contributes no variance, and so is apps_systematicfirst stage exported with a caller-suppliedppsobject. The choice, the affected stages and each stage's approximation are recorded in the"samplyr_systematic_variance"attribute of the result.as_svrepdesign()takes the same argument for its own approximation of these stages.
Value
A survey.design2 object for single-phase and multi-stage samples,
or a twophase/twophase2 object for two-phase samples.
Details
Every executed stage contributes one ids term, one fpc term and, when
stratified, one strata term, so survey::svydesign() represents the
multi-stage structure in its linearization (Sarndal et al. 1992, ch.
4.3):
Cluster ids (
ids): thecluster_by()variable of a clustered stage. A stage clustered by several variables, which execution treats as one cluster id, gets one synthesized interaction column, becausesurvey::svydesign()reads each formula term as a separate stage. A final unclustered stage gets a synthesized row-identity column so that its sampling variance is represented. A WR or PMR stage uses its.draw_kcolumn, and survey treats each occurrence as independent for Hansen-Hurwitz variance estimation. This is exact for WR and the documented approximation for PMR.Strata (
strata): aligned withids. A stage stratified by several variables exports their cross-classification as one synthesized column, since survey silently ignores extra variables within a stage's term. Trailing unstratified stages are omitted, and unstratified stages before a stratified stage get a constant placeholder column.Weights (
weights): the.weightcolumn, the product of the per-stage weights described in sample_columns.FPC (
fpc): aligned withids.survey::svydesign()requires every FPC term on the same scale, so one of two encodings is used:Count scale (designs without unequal-probability WOR stages):
.fpc_k, the stratum population count \(N_h\), for equal-probability WOR stages, and a syntheticInfcolumn (no correction, Hansen-Hurwitz variance) for WR/PMR stages.Fraction scale (multi-stage designs with a PPS WOR, balanced, or custom WOR stage): every WOR stage passes its per-unit stage sampling fraction \(1 / w_k = \pi_k\), and WR/PMR stages pass 0 (no correction). A multi-stage design with a random-size Poisson stage is refused by linearization export.
A single-stage PPS WOR design passes \(\pi_i\) directly, which survey interprets as inclusion probabilities.
For a two-stage stratified-cluster design with a final element stage, the exported call is equivalent to:
survey::svydesign(
ids = ~ ea_id + .id_2, # stage-1 clusters, stage-2 elements
strata = ~ region, # stage-1 strata
weights = ~ .weight, # product of per-stage weights
fpc = ~ .fpc_pi_1 + .fpc_f_2, # per-stage sampling fractions
data = sample,
nest = TRUE
)Multi-stage designs
Exactness depends on the variance treatment available for each method
(variance_estimation). A design whose first stage is a census of PSUs
correctly attributes all variance to the later stages. Executing stages
separately, as stage1 <- execute(design, psu_frame, stages = 1) then
sample <- execute(stage1, listing_frame), still gives one multi-stage
design, exported with survey::svydesign().
An unclustered element-sampling stage followed by further stages is
not nested cluster sampling, because the later selections are
conditional on the realized element sample, which is phase sampling.
execute() refuses it (samplyr_error_stage_parent_id). Express it as a
two-phase sample instead: execute the element stage under its first-phase design, then a
new second-phase design with that sample as its frame.
Two-phase samples and waves
A new phase-2 sampling_design executed with the phase-1 tbl_sample
as its frame, as in phase2 <- execute(design2, phase1), records a
previous-phase link, and as_svydesign() calls survey::twophase().
A materialized wave, execute(master, wave = t), is the other two-phase
case. Its second phase is the panel activation: within a frozen block the
master took a simple random sample without replacement of the realized
quota, so the blocks are the phase-2 strata and their sizes the phase-2
population counts. The master is retained as the first phase and supplies
the rows the wave did not keep. Columns added to the wave for analysis
are carried into the exported design. Wave or phase-2 analysis columns
replace same-named first-phase columns and are missing on unsampled
rows. Columns absent from the wave remain available from the master, so
dropping a wave column does not erase the master's measurements. Design
identifiers, strata and internal sampling columns keep their recorded
meanings. Keep earlier measurements under separate names if both are
needed.
On a stratified master whose stratum means differ strongly relative to
the variation within them, the two-phase variance of a total can be
negative, and survey::svytotal() returns NaN with base R's
sqrt(v): NaNs produced. That is survey::twophase()'s exact estimator,
computed only when an estimator is called, so samplyr cannot intercept
it. method = "approx" gives a finite standard error. A mean is
unaffected.
A clustered first phase needs its second phase drawn inside each of its
units, with stratify_by(<unit>), or by taking whole phase-1 units
before sampling inside them. In a simulation both gave 0.93 to 1.03 of
the true variance and never a negative one. When phase 2 draws smaller
units across the phase-1 clusters, the estimator is right over repeated
samples but not in one (variance_estimation has the measured error),
and the export warns (samplyr_warning_twophase_across_units). The
weights are exact either way.
survey::twophase() takes no pps for the first phase, so a two-phase
sample or wave whose phase 1 was drawn with unequal probabilities without
replacement is refused (samplyr_error_twophase_phase1_pps,
samplyr_error_wave_phase1_pps). So are cube, first-stage
pps_poisson and the spatial methods, which are unsupported at either
phase. Equal-probability first phases export, stratified, clustered,
multistage and with-replacement alike. No two-phase sample, a wave
included, has a replicate export. The weights of a refused sample are
exact, so totals and means are right. For a variance, an ultimate-cluster
approximation treats phase 1's units as drawn with replacement and
carries everything below in them. It is conservative, by the margins
variance_estimation reports, and much more so when phase 2 was drawn
across the phase-1 units:
survey::svydesign(ids = ~ea_id, strata = ~region, weights = ~.weight,
data = as.data.frame(phase2))Modified samples and domain analysis
as_svydesign() raises an error on a tbl_sample whose row set changed
after execute() (rows removed by dplyr::filter() or [, added, or
duplicated by a join) or whose internal design columns (.weight,
.weight_k, .fpc_k, ...) were overwritten, dropped, or renamed. The
sample is verified against an integrity record stored at execution (row
count and a hash of the weights, design metadata, and strata and cluster
columns), so changes the dplyr hooks cannot see (base assignment,
rbind(), vctrs operations, third-party verbs) are also caught, and an
overwrite that left every value identical passes. Row reordering,
one-to-one joins, and adding ordinary data columns do not mark the
sample. One complete replicate extracted from a replicated execution
(filter(.replicate == r)) is verified against the execution metadata
and remains supported.
Dropping out-of-domain rows before conversion is not domain estimation. The point estimate can agree, but its variance estimate is generally wrong, often too small, because the domain sample size is random under the design. Convert the full sample first and then subset the design:
svy <- as_svydesign(sample)
survey::svymean(~y, subset(svy, domain))
# or with srvyr:
as_survey_design(sample) |> filter(domain) |> summarise(...)Variance by selection method
Which estimator each selection method reaches, how exact it is, and which designs are refused are in variance_estimation.
pps is read as follows. "brewer" is the default treatment and keeps
every stage. FALSE states that no stage is PPS, so it is refused on a
design with one. "overton", survey::HR() and the matrix objects
(survey::ppsmat(), survey::poisson_sampling()) are single-stage in
survey, so a multi-stage sample is exported at stage 1 with a warning. A
matrix object is indexed by row, so it also needs one row per stage-1
unit, and a sample with several is refused
(samplyr_error_pps_rows_per_psu). Any other value is refused
(samplyr_error_pps_argument). A two-phase or wave export takes no pps,
because survey::twophase() does not apply it to the phase-2 variance
(samplyr_error_twophase_phase2_pps). A phase 2 of one stage drawn with
pps_sampford, pps_cps, pps_brewer, pps_sps or pps_pareto is
exported with its joint inclusion probabilities, computed on the phase-1
sample, and needs method = "full". Any other unequal-probability,
balanced or spatial phase 2 is refused with the same class.
A shared estimation weight
A sample from share_weights() carries weights for a population other
than the one that was selected, so it is exported as its source-target
contributions: one row per link, weighted by the recorded coefficient
times the source unit's design weight. This gives the generalized weight
share total exactly for any link structure, provided every selected
source unit has at least one contribution. A selected source unit with
no link must still count in the variance, which contribution rows cannot
do without inventing a target row, so this route refuses it and names
as_svrepdesign() instead. The result has more rows than the
transformation returned, but no estimate changes: a total sums the same
terms, and a mean's denominator is the estimated target population size
either way.
An unequal-probability or random-size source design is also refused
here, because its variance comes from a structure indexed by the
source sample's rows, which the contribution rows no longer are. Use
as_svrepdesign(), which replicates the source design and applies the
sharing inside every replicate.
The survey package is required but not imported. It must be
installed to use this function.
References
Sarndal, C.-E., Swensson, B. and Wretman, J. (1992). Model Assisted Survey Sampling. Springer.
See also
execute() for producing tbl_sample objects,
survey::svydesign() for the underlying function,
as_survey_design.tbl_sample for converting directly to a srvyr tbl_svy,
as_svrepdesign() for replicate-weight export,
as_svydesign.frame_stack() for overlapping frames
Other survey export:
as_survey_design.tbl_sample(),
as_survey_rep.tbl_sample(),
as_svrepdesign(),
stack_waves(),
variance_estimation,
variance_estimators()
Examples
# Stratified sample -> survey design
sample <- sampling_design() |>
stratify_by(region, alloc = "proportional") |>
draw(n = 300) |>
execute(bfa_eas, seed = 42)
svy <- as_svydesign(sample)
survey::svymean(~households, svy)
#> mean SE
#> households 71.668 3.6922
# Two-stage sample: PPS selection of EAs, then households from a listing
selected <- sampling_design() |>
add_stage() |>
stratify_by(region) |>
cluster_by(ea_id) |>
draw(n = 5, method = "pps_brewer", mos = households) |>
add_stage() |>
draw(n = 8) |>
execute(bfa_eas, stages = 1, seed = 2025)
listing <- selected |>
as.data.frame() |>
dplyr::reframe(hh_id = seq_len(households), .by = ea_id)
sample <- execute(selected, listing, seed = 2026)
# Brewer's variance approximation at the PPS stage
svy <- as_svydesign(sample)
# A joint-probability matrix instead, for a single-stage Sampford sample,
# whose matrix is exact. A matrix needs one row per stage-1 unit.
sampford <- sampling_design() |>
stratify_by(region) |>
draw(n = 5, method = "pps_sampford", mos = households) |>
execute(bfa_eas, seed = 2025)
jip <- joint_expectation(sampford, bfa_eas)
svy_joint <- as_svydesign(sampford, pps = survey::ppsmat(jip[[1]]))
survey::svytotal(~population, svy_joint)
#> total SE
#> population 20854071 297547