execute() runs a sampling design against one or more data frames,
producing a sampled dataset with appropriate weights and metadata.
Usage
execute(
.data,
...,
stages = NULL,
seed = NULL,
panels = NULL,
panel_stage = NULL,
small_pool = NULL,
reps = NULL,
wave = NULL,
response_status = NULL,
frame_digest = c("summary", "full", "none")
)Arguments
- .data
A
sampling_designobject to start a new execution, or a partially executedtbl_sampleto continue the remaining stages of its stored design.- ...
Data frame(s) to sample from: one frame for a single-stage design or a shared hierarchy, or one frame per stage in stage order. A
tbl_samplepassed here while.datais a newsampling_designstarts a new sampling phase rather than continuing that sample's stages. Ordinary input frames must have unique column names and must not use columns reserved for execution output, such as.weight,.sample_id,.stage,.weight_k, or.fpc_kfor stagek. Frames are matched by position, so a name given here is a label. A label resembling an argument below (seedd, or the singularstage,rep,panel) is refused, because those arguments follow...and are matched exactly.A single unnamed list of data frames is the same call, for code that already holds the frames, such as a loop over registers or
replay_design(). Mixing it with separate frames is refused. Names inside the list are frame labels, so a misspelled argument must be written outside it to be reported as one. See frame_input_grammar.- stages
Integer vector of the stages to execute, or
NULL(default) for all remaining stages. From asampling_designit must start at stage 1, so an operational workflow can stop after its first contiguous batch of stages. From a partialtbl_sampleit must start at the next unexecuted stage.- seed
Integer random seed, between
-.Machine$integer.maxand.Machine$integer.max. A given seed leaves the session's random number stream untouched. Withseed = NULL, selection draws from the session stream and advances it, andreplay_design()refuses the resulting sample because its receipt cannot reproduce it.- panels
Rotation groups (panels) to partition the sample into, as an integer count, a rotation schedule (a data frame with integer
panelandwavecolumns, an optional logicalactivecolumn, an optional integervisitcolumn that opens tenures and an optional integerperiodcolumn that names each wave's reporting period), or ansvyplan_schedulefromsvyplan::design_schedule().periods()partitions it into fieldwork periods instead, each unit visited once. The output gains a.panelcolumn, and only a sample drawn with a schedule or periods can be materialized bywave. DefaultNULLmeans no panels. Cannot be combined withreps, or redeclared on a sample that already carries an assignment. panel_assignment describes the assignment and the schedules.- panel_stage
Stage whose selected units are assigned to panels, as a single stage number, or
NULL(the default) for the first executed stage. Accepted only alongsidepanels. The stage must be one the execution completes, and not the stage that setsreserveindraw()(samplyr_error_panel_stage_reserve). Later stages inherit their ancestor's panel, so assigning below stage 1 rotates units inside parents that stay in the survey. panel_assignment explains what that changes, including how it can bias estimates over time.- small_pool
What to do when a rotation schedule would leave a pool with no unit to activate at some wave.
"error"(the default, reached byNULL) refuses the assignment, and"permanent"activates those units at every wave and warns withsamplyr_warning_panel_small_pool. Meaningful only with a schedule. See panel_assignment.- reps
Integer number of independent replicate samples to draw (>= 2), or
NULL(default) for a single sample. The replicates are stacked in onetbl_samplewith a.replicatecolumn (integer 1 throughreps). Their seeds are drawn fromseed, since consecutive seeds do not give independent draws in R, and recorded in thereplicate_seedselement of the sample's metadata, so replicateralone isexecute(design, frame, seed = replicate_seeds[r]). Cannot be combined withpanelsor with stages that use permanent random numbers. A replicated sample continued, or used as a phase-2 frame, carries its replicates into the stages run now, and these cannot use permanent random numbers either.as_svrepdesign(type = "random_groups")estimates variance from the spread of the replicates, for any selection method.- wave
Integer wave of a master that carries a panel assignment, or
NULL(default). It has two uses, told apart by whether a frame is given. Without a frame,execute(master, wave = t)materializes wavet. It activates the panels the stored schedule declares active attand compounds the exact activation factor into.weight. A wave selects units the master already assigned, under the policy the master froze, so it takes none ofseed,stages,panels,panel_stage,small_pool,repsorframe_digest. Each is refused by name rather than ignored. Several distinct waves, aswave = 1:3, pool those waves into one sample with a.wavecolumn (panel_assignment gives the weights). With a frame,execute(master, listing, wave = t)draws the master's remaining stages under the units whose tenure opens att, the units of periodtforperiods(), and returns the master. It acceptsseedandstages, refuses the other arguments, and takes a master with a rotation schedule or periods. See "Drawing the later stages wave by wave" below.- response_status
A column of the sample that holds the final disposition of each listed unit, in the terms of the AAPOR Standard Definitions: whether the unit was eligible and whether it responded. It settles the stage that sets
reserveindraw().execute(sample, response_status = col)takes no other argument. The column holds AAPOR final disposition codes, read by their leading digit (1 or 1.1 an interview, 2 or 2.24 an eligible non-interview, 3 an unknown eligibility, 4 or "4.60" not eligible), or the words"interview","noninterview","unknown"and"ineligible".NAmarks a reserve unit the field did not release. Every unit of the take needs a code. See "Settling a reserve" below, and reserve_lists for the protocol and the codes.- frame_digest
Controls the frame digest, a compact execution manifest recorded with the sample and read by
frame_summary(). The digest never affects selection, weights, or estimation."summary"(default) records selection pools, resolved chances (exact for cluster stages, constant or quantile-compressed for element stages), and the selected-unit trace."full"keeps exact per-unit chances for element stages too."none"records no digest and skips trace construction for minimum execution overhead."summary"saves storage, not time. Compressing the chances can take longer than keeping them all, so"none"is the mode for repeated executions such as a simulation loop.When one universe frame feeds every stage, later stages also record the pools their realization never reached, with chances resolved from the design (
chance_status = "design_resolved"), which gives complete universe denominators without the frame. A stage continuation extends the digest of its input sample, and an input without a valid digest yields none. Replicates share one population structure with their own traces. A replicated multi-stage execution keeps only the stage prefix shared by all replicates, with status"partial", asframe_summary()describes. Replicated multi-phase and replicated-continuation executions do not record a digest yet.A digest is not anonymized. Its selection trace keeps the identifiers of realized units (frame-derived cluster keys or row indices), even under
"summary", so treat the sample and any serialized execution receipt as potentially confidential.
Value
A tbl_sample: a data frame subclass carrying the selected rows,
the design that produced them, and generated columns recording the
selection. Those are .sample_id, .weight, the per-stage .weight_k,
.fpc_k, .draw_k and .certainty_k, .reserve_k at a stage that
sets reserve in draw(), .zone_1 and .pair_1 for a zoned
certainty plan, .replicate or .panel when reps or
panels is used, and .wave for a window of several waves.
sample_columns documents what each one holds.
Details
Multi-stage with a single frame
For hierarchical data where all stages are in one frame, pass that one
frame. It must contain all clustering variables and represent the stage
hierarchy correctly. Lower-stage IDs may repeat across different parents,
because samplyr resolves them using the full ancestry from earlier
stages.
Multi-stage with one frame per stage
When each stage has its own register, pass one frame per stage. The
number of frames schedules the stages: one frame is a shared hierarchy
covering all of them, one frame per stage gives each its own, and any
other count is samplyr_error_frame_count.
Registers are supplied whole. Each is restricted to the units its parent
stage selected, and the variables earlier stages introduced are carried
onto it, so a lower register need not be pre-filtered or duplicate the
upper stages' stratification columns. A register may legitimately omit a
carried stratum, but one whose own copy of it disagrees is an error.
Each earlier stage's measure of size (mos) is carried too, so the sample
keeps what every stage's inclusion probabilities were computed from. A
register holding a column of the same name keeps its own, and a stage
that selects on that name must find it in its own register.
Before any stage draws, every later stage is checked on all the units it
could reach, as validate_frame() checks them, so a defect in a unit the
seed happens to skip is still refused.
This form, the single-hierarchy form, and the stage continuation below
run the same stage transition. Under one shared RNG stream, and with
stages given on every intermediate call, all three draw the same
sample.
Partial execution (operational sampling)
stages executes only the stages named, returning a partial tbl_sample.
Fieldwork then produces the next stage's frame, and passing the partial
sample back as .data continues the same design. frame_input_grammar
states how a continuation reads its frame, when it asks for stages, and
how it differs from starting a new phase on a sample.
Settling a reserve
A stage that sets reserve in draw() lists its take and its reserve,
with .reserve_k giving the release order. The field works the take, the
office releases one reserve unit, in .reserve_k order, for each unit
that fails, and work in a pool stops at its target number of
respondents or when the list runs out. An earlier stop must not depend on
how the pool was going, such as giving up after a run of refusals.
execute(sample, response_status = col) reads the codes, walks each pool in
release order and returns the respondents. Their weight at the stage
estimates the pool's eligible units from the units worked, leaving out
the unit that stopped the list, and divides it among the respondents.
Units released after the stop are dropped, so a pool worked past its
target keeps the weight of the stop rule. A pool stopped early is
settled with the units it worked. How unknowns are coded is the choice
of their eligibility: 3 estimates it from the resolved units of the
pool, 2 counts them as eligible and 4 as ineligible.
A pool whose eligible units include no respondent returns no rows, but
its eligible units are still estimated from the units worked. When every
unit worked is of unknown eligibility, the estimate takes the resolved
rate of the pools that share its strata, or counts every unit as
eligible when none of them resolved one. Both are assumptions about the
pool, and summary() counts the pools that rest on them. The export keeps that weight
in a placeholder row for a nonresponse adjustment (see the "A settled
reserve" section of as_svydesign()).
A sample is settled once. A stage below the reserve is drawn from the
settled sample, execute(settled, listing), and a call that would draw
it from the list is refused (samplyr_error_reserve_unsettled). So is a
new phase drawn from the list.
summary() shows the settlement per pool, and write_design() records
it for replay_design().
Drawing the later stages wave by wave
A master split into periods() at its first stage can have its later
stages drawn period by period, as listing proceeds in the field.
execute(master, listing, wave = t) draws every remaining stage under the
units of period t and returns the master, so the calls are chained, as
in master <- execute(master, listing_3, wave = 3, seed = 103).
The listing needs rows for every unit of period
t. Rows under units of other periods are ignored, so one growing listing file can be passed every time. A unit of periodtwith no row is refused (samplyr_error_frame_missing_parent) unless its stage setson_empty.The listing keys its rows to the master's units by their cluster ids, such as
ea_id, and carries what the later stages select on. Strata and weights come from the master.Each period is drawn once (
samplyr_error_wave_already_drawn), in any order, with its ownseed.stagesmay be given, and must name every remaining stage.Until every period is drawn, the master keeps its first-stage rows and every other verb reads it as the first-stage sample.
print()and summary() say which periods are drawn, and an ordinary continuation is refused (samplyr_error_wave_draws_in_progress).execute(master, wave = t)gives a drawn period's sample with exact weights. That sample is provisional.as_svydesign()andas_svrepdesign()export it by ultimate clusters from its own rows, and the two-phase export, which reads the whole master,stack_waves()andwrite_design()refuse it (samplyr_error_wave_provisional,samplyr_error_serialize_wave_provisional).The call that draws the last period returns the completed sample, as one continuation would, with every stage executed, rows in the master's order of their units and
.sample_idnumbered once. It is the design ofexecute(master, listing), drawn with other random numbers.The completed sample's frame digest holds every period's pools and selections, so
frame_summary()reports each stage as for one call. A listing passed for every period keeps its frame record. Separate listings share one record of the rows the periods drew from, with no fingerprint, since no single frame holds them.write_design()records the master's call and each period's call in the order they were made, andreplay_design()replays them with one frame per call, the master's frame and then each period's listing. A master with some periods drawn is written and replayed the same way.A master with a rotation schedule is drawn the same way, tenure by tenure. The call at wave
tdraws the units of the panels whose tenure opens there, where the schedule'svisitis 1, and the first call also draws the permanent units, which keep one tenure throughout. A wave that opens no tenure is refused (samplyr_error_wave_already_drawn) with the waves that drew its units. When a panel has several tenures, the master never closes: its draws accumulate, andexecute(master, wave = t)reads each panel's current tenure. A new tenure takes the full listing: samplyr leaves out the units earlier tenures drew and weights the rest to the whole listing. Such a master takes noreserveat any stage (samplyr_error_tenure_stages), since it is never complete and a wave exports no reserve. panel_assignment describes tenures.
Multi-phase sampling
execute(new_design, previous_sample) starts a new phase, with the
earlier sample as the frame of a new design rather than .data carrying
unexecuted stages. Weights compound across phases, and as_svydesign()
exports this path through survey::twophase().
Weights
.weight is the product of the per-stage weights and of the phase weights
across phases. sample_columns gives the formulas.
Large frames
A partial execution on one frame keeps every row under the units it
selected, because the continuation draws the next stage from those
rows. On a frame of persons, the stage-1 sample of a two-stage design
holds every person of the selected EAs. Drawing stage 1 from a register
of the EAs, one row per EA, keeps the partial sample to one row per
selected EA, and the person frame is passed when the design continues,
as in execute(partial, persons). It is the same design.
frame_input_grammar states how a continuation reads its frame.
A factor column keeps all of its levels in the sample, as R keeps them
in any subset of a factor. A household id stored as a factor with a
million levels therefore weighs about as much in a sample of a few
thousand rows as in the frame. samplyr leaves the levels as they are,
since they are part of the data. droplevels() on the sample removes
them, and ids stored as character in the frame avoid them.
A materialized wave keeps its master as its first phase, which its
survey export reads. saveRDS() of a wave therefore writes the master
too, again in every file and for every wave saved. Saving the master
alone is enough, since execute(master, wave = t) gives back the same
wave and draws no random numbers.
When a design cannot be realized as written
A pool holding fewer units than the stage asks for is selected whole,
which makes the design non-self-weighting. execute() reports this and
four related outcomes as classed conditions carrying a payload. With the
default digest, the capped column of
frame_summary(sample, detail = "pool") shows capping after the fact.
execution_conditions gives the five classes, their payload fields, and
how to capture one when no digest is kept.
See also
sampling_design() for creating designs,
frame_input_grammar for the frame forms every verb accepts,
sample_columns for what the generated columns hold,
execution_conditions for what execute() signals when a design cannot
be realized as written,
get_design() for extracting metadata
Other execution:
execution_conditions,
rotation_program(),
validate_frame()
Examples
# Basic SRS execution
sample <- sampling_design() |>
draw(n = 100) |>
execute(bfa_eas, seed = 1234)
sample
#> # A tbl_sample: 100 × 18
#> # Sampling: 1 stage | 100/44,570 units
#> # Weights: 445.7 [445.7, 445.7]
#> ea_id region province commune urban_rural population households area_km2
#> * <int> <fct> <fct> <fct> <fct> <int> <int> <dbl>
#> 1 6473 Sahel Soum Koutou… Rural 133 23 19.4
#> 2 6543 Sahel Soum Koutou… Rural 183 32 6.15
#> 3 10735 Sahel Yagha Tankou… Rural 36 5 16.7
#> 4 36151 Centre-Nord Namente… Boulsa Rural 526 75 3.75
#> 5 10510 Nord Loroum Sollé Rural 239 28 5.45
#> 6 23624 Nord Yatenga Senguè… Rural 555 59 8.84
#> 7 33774 Centre-Nord Sanmate… Pissila Rural 857 110 4.94
#> 8 1118 Centre-Nord Namente… Boala Rural 830 137 10.2
#> 9 29691 Centre-Oue… Sissili Bieha Rural 190 28 8.83
#> 10 10559 Boucle du … Kossi Sônô Rural 69 10 8.89
#> # ℹ 90 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> # remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> # .stage <int>, .weight_1 <dbl>, .fpc_1 <int>
# Stratified execution with proportional allocation
sample <- sampling_design() |>
stratify_by(region, alloc = "proportional") |>
draw(n = 300) |>
execute(bfa_eas, seed = 5789)
table(sample$region)
#>
#> Boucle du Mouhoun Cascades Centre Centre-Est
#> 34 17 26 20
#> Centre-Nord Centre-Ouest Centre-Sud Est
#> 23 25 11 37
#> Hauts-Bassins Nord Plateau-Central Sahel
#> 32 20 11 28
#> Sud-Ouest
#> 16
# Two-stage cluster sample execution
zwe_frame <- zwe_eas |>
dplyr::mutate(district_hh = sum(households), .by = district)
sample <- sampling_design() |>
add_stage(label = "Districts") |>
cluster_by(district) |>
draw(n = 20, method = "pps_brewer", mos = district_hh) |>
add_stage(label = "EAs") |>
draw(n = 10) |>
execute(zwe_frame, seed = 3)
#> Stage 1: 1 unit is selected with certainty.
#> ℹ A unit whose share of its pool's size is above 1 / n has chance 1, and the
#> rest of the take is spread over the other units.
#> ℹ Set `certainty_size` or `certainty_prop` in `draw()` to state the rule in the
#> design, or check before drawing with `frame_summary()`.
length(unique(sample$district)) # 20 districts selected
#> [1] 20
# Partial execution: stage 1 only
design <- sampling_design() |>
add_stage(label = "EAs") |>
stratify_by(region) |>
cluster_by(ea_id) |>
draw(n = 5, method = "pps_brewer", mos = households) |>
add_stage(label = "Households") |>
draw(n = 12)
# Execute only stage 1 to get selected EAs
selected_eas <- execute(design, bfa_eas, stages = 1, seed = 2)
nrow(selected_eas) # Number of selected EAs
#> [1] 65
# Continuation: the listing produced by fieldwork becomes the next frame,
# and the partial sample is passed back as `.data`
listing <- selected_eas |>
as.data.frame() |>
dplyr::reframe(hh_id = seq_len(20), .by = ea_id)
sample <- selected_eas |> execute(listing, seed = 43)
nrow(sample) # 12 households in each selected EA
#> [1] 780
## Later stages drawn one period at a time
monthly <- sampling_design() |>
add_stage() |> stratify_by(region) |> cluster_by(ea_id) |>
draw(n = 12, method = "pps_systematic", mos = households) |>
add_stage() |> draw(n = 5) |>
execute(bfa_eas, stages = 1, seed = 1, panels = periods(12))
# The EAs of month 3 go to the listing team
month_3 <- dplyr::filter(as.data.frame(monthly), .panel == 3)
listing_3 <- dplyr::reframe(month_3, hh_id = seq_len(20), .by = ea_id)
monthly <- execute(monthly, listing_3, wave = 3, seed = 103)
monthly # the master, with month 3's households drawn
#> # A tbl_sample: 156 × 20
#> # Stages: 1/2
#> # Sampling: 1 stage | 156 units
#> # Periods: 12 (in .panel)
#> # Drawn: stage 2 in 1 of 12 periods (3)
#> # Weights: 296 [27.15, 2530.67]
#> ea_id region province commune urban_rural population households area_km2
#> * <int> <fct> <fct> <fct> <fct> <int> <int> <dbl>
#> 1 29516 Boucle du … Bale Bana Rural 585 76 1.17
#> 2 8572 Boucle du … Bale Pâ Rural 1740 201 1.78
#> 3 6314 Boucle du … Banwa Kouka Rural 3778 435 3.12
#> 4 23910 Boucle du … Banwa Solenzo Rural 346 46 5.91
#> 5 657 Boucle du … Kossi Barani Rural 80 10 6.22
#> 6 21509 Boucle du … Kossi Doumba… Rural 974 167 1.25
#> 7 20925 Boucle du … Mouhoun Bondok… Rural 723 95 7.13
#> 8 26134 Boucle du … Mouhoun Dédoug… Rural 210 30 0.13
#> 9 43791 Boucle du … Mouhoun Safané Rural 60 9 8.92
#> 10 44729 Boucle du … Nayala Toma Rural 204 33 8.85
#> # ℹ 146 more rows
#> # ℹ 12 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> # remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> # .stage <int>, .weight_1 <dbl>, .fpc_1 <int>, .certainty_1 <lgl>,
#> # .panel <int>
nrow(execute(monthly, wave = 3)) # month 3's sample
#> [1] 65
## One frame per stage
# Frames map to stages by position: districts first, then EAs
districts <- dplyr::distinct(zwe_eas, province, district)
two_stage <- sampling_design() |>
add_stage(label = "Districts") |>
cluster_by(district) |>
draw(n = 8) |>
add_stage(label = "EAs") |>
draw(n = 3)
sample <- two_stage |> execute(districts, zwe_eas, seed = 424)
length(unique(sample$district)) # 8 districts, 3 EAs each
#> [1] 8
# The same call with the frames held as a list
registers <- list(districts, zwe_eas)
same <- two_stage |> execute(registers, seed = 424)
identical(sample$.sample_id, same$.sample_id)
#> [1] TRUE
## Multi-phase
# The previous phase's sample is the new phase's frame
phase1 <- sampling_design() |>
draw(n = 200) |>
execute(bfa_eas, seed = 42)
phase2 <- sampling_design() |>
draw(n = 50) |>
execute(phase1, seed = 123)
nrow(phase2) # weights compound across both phases
#> [1] 50
# Replicated sampling: 5 independent draws
sample <- sampling_design() |>
draw(n = 100) |>
execute(bfa_eas, seed = 42, reps = 5)
table(sample$.replicate) # 100 per replicate
#>
#> 1 2 3 4 5
#> 100 100 100 100 100
# Rotating panel: 4 rotation groups
sample <- sampling_design() |>
draw(n = 200) |>
execute(bfa_eas, seed = 1, panels = 4)
table(sample$.panel) # 50 per panel
#>
#> 1 2 3 4
#> 50 50 50 50