Checks if a data frame contains all required variables for a sampling design and reports any issues.
Usage
validate_frame(
design,
frame,
...,
stages = NULL,
fingerprint = c("inform", "warn", "ignore")
)Arguments
- design
A
sampling_designobject, or atbl_sample. A fully executed sample validates its stored design and compares its frame digest (when present) againstframe. A partial sample validates the frame that would continue it, against the units it selected.- frame
A data frame to validate, or an ordered list of stage frames: one per stage, in the order
execute()would receive them. Each entry may itself be hierarchical. A data frame and a one-element list are the same input, as they are inexecute(), and every check here is oneexecute()runs before it samples: a frame this accepts is a frame execution accepts.- ...
These dots are for future extensions and must be empty.
stagesand the arguments after it follow..., so each must be named exactly: the singularstageis reported rather than prefix-matched.- stages
Which stage(s) to validate against. Defaults to all stages, and for a partial
tbl_sampleto every remaining stage, matchingexecute(). Where one frame cannot say whether it is the next stage's register or a hierarchy covering the rest,stagesis required, again as inexecute().- fingerprint
How to report differences between
frameand what was recorded earlier: the frame fingerprint stored in a design file (designs restored withread_design()when saved withframe =) and the frame digest recorded at execution (whendesignis atbl_sample, or a restored design whose receipt carries one). One of"inform"(default, emits a message),"warn", or"ignore". Both comparisons are informational and never fail validation, because a design remains executable on any frame that passes the variable checks.
Details
Validation checks include:
Presence of required stratification variables
Presence of required clustering variables
Presence of measure of size (MOS) variables for PPS sampling
Non-empty frame
Positive values for MOS variables
For designs restored with read_design(), if the design file carries a
frame fingerprint, validate_frame() also compares it against frame
and reports what changed (rows, columns, column types, or content).
When a frame digest is available (an executed tbl_sample, or a
design file written from one), the structural comparison goes
further: the role-scoped fingerprint (analysis columns added later
do not trigger it), the frame size, and per-pool population sizes
recomputed from frame at every stage the digest can anchor
(stage 1 over the universe and later stages under the recorded
parents). The report says where the frame drifted, not merely that
it did.
Ordered stage frames
A data frame means one hierarchy. A list means separately supplied
stage frames, and validate_frame() then checks everything
execute() checks before it draws: the frame count, the columns
each stage selects on, cluster-level variables that must be constant
within a unit, ancestry types that must be joinable, and ancestry
values that name no parent.
It also checks candidate coverage, and is stricter there than
execution: a unit reachable at one stage with no rows in the
register the next stage samples from is
samplyr_error_frame_incomplete_register. execute() only warns,
because the sample it happens to draw may never need that unit. The
two agree on realized parents, which fail in both.
Continuing a partial sample
When design is a tbl_sample with stages left to run,
validate_frame() checks the supplied frames against the units that
sample actually selected, through the same transition the
continuation would use: complete ancestry, joinable key types, no
missing parent identifiers, and a row for every selected parent. It
accepts the same shapes execute() does, so one register per
remaining stage works here as it does there. The recorded fingerprint
and frame digest are not compared, because they describe the frame
the executed stages drew from rather than the register the next stage
needs.
Preparing a second phase
When frame is itself a tbl_sample (that is, the design is being
prepared as phase 2 of a two-phase sample), validate_frame() also
pre-flights the two-phase export requirements. The phases declare
their sampling units independently, so the link is the compound of
every identifier either phase declares with cluster_by() that both
samples carry, which is the bridge as_svydesign() builds. It warns
when neither phase declares an identifier the phase-1 sample carries,
and when the identifiers together do not uniquely identify phase-1
rows. Problems are reported as warnings rather than errors, because
selection and weighting work without linkage. Only as_svydesign()
needs it.
A previous-phase sample also carries identifiers that later stages
must keep. One that varies inside a sampling unit cannot be carried,
and is refused here for the same reason execute() refuses it: a
clustered stage keeps one representative row, so by the time anything
downstream looks, the disagreement is gone.
See also
Other execution:
execute(),
execution-conditions,
rotation_program()
Examples
# Create a design requiring region stratification and PPS by household count
design <- sampling_design() |>
stratify_by(region) |>
cluster_by(ea_id) |>
draw(n = 10, method = "pps_brewer", mos = households)
# Validate against bfa_eas (should pass)
validate_frame(design, bfa_eas)
# Create a frame missing required variables (will fail)
bad_frame <- data.frame(id = 1:100, value = rnorm(100))
try(validate_frame(design, bad_frame))
#> Error in validate_frame(design, bad_frame) :
#> frame 1, used for stage 1, is missing region, ea_id, and households.
#> ✖ region is the stratification variable.
#> ✖ ea_id is the cluster variable.
#> ✖ households is the MOS variable.
#> ℹ stage 1 selects on region, ea_id, and households.
# Validate only specific stages of a multi-stage design
zwe_frame <- zwe_eas |>
dplyr::mutate(district_hh = sum(households), .by = district)
multi_design <- 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)
# Validate stage 1 only
validate_frame(multi_design, zwe_frame, stages = 1)
# One register per stage: a list, in the order execute() receives them
districts <- zwe_frame |>
dplyr::distinct(district, district_hh)
validate_frame(multi_design, list(districts, zwe_eas))
# A partial sample validates the register that would continue it
stage1 <- execute(multi_design, districts, stages = 1, seed = 5)
validate_frame(stage1, zwe_eas)
# Designs restored from a file also check the stored frame fingerprint
path <- tempfile(fileext = ".json")
write_design(design, path, frame = bfa_eas)
restored <- read_design(path)
# Same frame, no message
validate_frame(restored, bfa_eas)
# A modified frame passes validation with an informational message
validate_frame(restored, bfa_eas[-1, ])
#> Frame differs from what was recorded when the design was saved:
#> • 44569 rows instead of the 44570 recorded
#> ℹ This is informational. The design remains executable on any frame that passes
#> the variable checks.
unlink(path)