pv_fit_direct() runs the "stack_direct" method of pv_fit(). It fits
one model to the stacked data (one copy of data per plausible value),
checks the sampler diagnostics of that fit, and then applies the Cholesky
calibration correction (CCC): the fixed-effect draws are transformed so
that their mean and covariance equal the estimates and the covariance
(T_MI) of target. The reported estimates, standard errors and degrees
of freedom are those of target.
Usage
pv_fit_direct(
data,
formula,
target,
control = pv_control(method = "stack_direct"),
family = NULL,
prior = NULL,
fit_function = NULL,
draws_function = NULL,
param_map = NULL,
diagnose_function = NULL,
log_lik_function = NULL,
extract_log_lik = FALSE,
cache_dir = "cache",
cache_stem = "pvstackr-stack-direct",
additional_args = list()
)Arguments
- data
The data frame used to build
target: the same rows in the same order, with the same plausible values, weights and covariates. Otherwisepv_fit_direct()stops with an error.- formula
The formula used to build
target, with the placeholderOUTCOMEon the left-hand side, such asOUTCOME ~ x + female(seepv_fit()). Random-effect terms such as(1 | school)stop with an error.- target
The
pvstackr_brr_targetobject returned bypv_brr_target()fordataandformula.- control
A
pv_control()object withmethod = "stack_direct". The default ispv_control(method = "stack_direct"), andNULLgives the same. Itscentermust be"target".- family
NULL(default),"gaussian", or a family object or list with elementsfamilyandlink, such asgaussian(). Only the Gaussian family with the identity link is accepted; any other family or link stops with an error. The fitting function always receivesstats::gaussian()made by pvstackr, not the object you pass.- prior
NULL(default) or a prior table: a data frame with character columnsclassandcoef, such as the result of the brms functionset_prior(). Only priors of class"b"or"sigma"with an emptycoefare accepted; a prior on the intercept, on one coefficient or of another class stops with an error. A"b"prior is given to the slopes only, as in the original formula, so the intercept keeps the default prior. Any explicit prior, even a flat one, gives the fit the status"warning"(explicit_prior_warning).- fit_function
NULL(default) or your function that fits the stacked model.NULLselects the bundled brms engine whencontrol$backendis"brms"and stops with an error otherwise. The function is called with the argumentsformula,data,family,prior,chains,iter,warmup,cores,seed,backend,fileandfile_refit(the stacked formula and data, the settings fromcontroland the cache file; see Details andcache_dir), plus the elements ofadditional_args. There is noweightsargument: the weights are informulaand in the column.pvstackr_weightofdata, and a function that ignores them fits an unweighted model. It may return any object thatdraws_functionanddiagnose_functionaccept.- draws_function
Your function that takes the object returned by the fitting function and returns its draws: a numeric matrix or data frame with one row per draw (at least two), finite values and unique column names. It may be
NULL(default) only with the bundled engine. The fixed-effect columns must be named as intarget$fe_names(such asb_Intercept) or after the columns of the stacked formula (b_pvstackrMM001,b_pvstackrMM002, ...); otherwise giveparam_mapand list all fixed effects in the order oftarget$fe_names.- param_map
NULL(default) or a named list that says which columns of the draws are the fixed effects. WithNULL, columns whose names start withb_are the fixed effects;sigmaandsd_*columns are other model parameters, which are not reported, and all other columns, such aslp__, are dropped. Give a list withfe_names(names) orfe_idx(positions) when the fixed-effect columns have other names or when other columns start withb_, such as distributional parameters namedb_sigma_*. Its optional elementsvc_namesandvc_idxselect the other model parameters and change nothing that is reported.- diagnose_function
Your function that takes the object returned by the fitting function and returns its sampler diagnostics as a named list with the elements
rhat_max(the largest R-hat),ess_bulk_minandess_tail_min(the smallest bulk and tail effective sample sizes, totals over all chains),divergences(the number of divergent transitions),chainsandpost_warmup_draws_per_chain; the list may also sit in an elementsampler. For the per-chain check, pvstackr divides each effective sample size bychains; a returnedess_bulk_per_chain_minoress_tail_per_chain_minmust equal that ratio. If the function is missing or fails, or a value is missing or invalid, the fit is blocked (sampler_diagnostics_incomplete), anddiagnostic_reason_codesinget_diagnostics(fit)$samplersays why. The bundled engine ignores this argument: it takes R-hat and the effective sample sizes over all variables of the fit from the posterior package and the number of divergent transitions from the brms sampler record.- log_lik_function
NULL(default) or your function that takes the object returned by the fitting function and returns the pointwise log-likelihood: a finite numeric matrix with one row per draw and one column per row of the stacked data. It is called only whenextract_log_lik = TRUE; the bundled engine does not supply one.- extract_log_lik
Whether to call
log_lik_function, which is then required:TRUEorFALSE(default). The matrix is kept in the fit'sstack_fitonly withpv_control(keep_log_lik = TRUE), for your own use: no pvstackr function uses it.keep_log_lik = TRUEstops with an error unlessextract_log_lik = TRUE.- cache_dir, cache_stem
The folder and the file name (without extension) for a cached stacked fit; defaults
"cache"and"pvstackr-stack-direct".cache_stemmust be a plain file name, without a path separator. For the bundled brms engine, pvstackr creates the folder, verifies that it is writable, and uses brmsfile_refit = "on_change". Setcache_dir = NULLto disable file caching. Your ownfit_functionreceivesfile = file.path(path.expand(cache_dir), cache_stem)andfile_refit = "on_change", orfile = NULLandfile_refit = "never"whencache_dir = NULL; pvstackr does not create the folder for it.brms refits a cached model only when its Stan code or data change, not when
chains,iter,warmuporseedchange. The sampler check then blocks a cached fit whose number of chains or of draws per chain differs fromcontrol, and a changed seed returns the cached draws without a warning. Usecache_dir = NULLor a newcache_stemwhen you vary these settings, as in a seed-stability check.- additional_args
A named list of further arguments for the fitting function,
list()by default. They are passed to yourfit_functionor, with the bundled engine, to the brms functionbrm(), for examplelist(control = list(adapt_delta = 0.95)). They may not repeat the arguments that pvstackr sets (seefit_function).
Value
A pvstackr_fit object with method = "stack_direct". Read it
with get_estimates(), get_target(), get_draws() and
get_diagnostics(); pv_fit() explains the status and the estimate
table, and pvstackr_object_contracts describes every part of the
object. The estimate table has one row per fixed effect, with the
estimates, standard errors and degrees of freedom of target.
get_draws() returns the calibrated fixed-effect draws (one row per
draw of the stacked fit, one column per fixed effect) when
control$return_draws is TRUE, the default. get_diagnostics()
returns preflight (the check that data, formula and target
match), sampler and sampler_gate (the sampler diagnostics and their
check), stack_fit, stack_fit_warnings (notes from the stacked fit,
such as dropped draw columns) and ccc (the calibration diagnostics).
For a blocked fit it returns only preflight, sampler,
sampler_gate, redaction (what was removed) and, when the
calibration check blocked the fit, ccc, with its values grouped as
center, conditioning, residual and prior (for example
get_diagnostics(fit)$ccc$center$delta_c_max).
Details
The stacked fit
The stacked data hold one copy of data for each plausible value, with
that plausible value as the outcome. Each row is weighted by the final
survey weight named in target, divided by its mean and by the number of
plausible values, and the model is a Gaussian linear model with the
identity link. pvstackr adds the columns of the design matrix of
formula, the intercept included, to the stacked data as ordinary
covariates, so the fitting function receives the formula
.pvstackr_y | weights(.pvstackr_weight) ~ 0 + pvstackrMM001 + ..., in
which the weights enter through weights(). With the bundled brms engine
and prior = NULL, brms therefore gives every fixed effect, the intercept
included, its default flat prior. The residual standard deviation sigma
is estimated but neither calibrated nor reported.
What is reported
Only the fixed effects are reported. By pvstackr's reporting rule, the
intervals of a stack_direct fit can be read as confidence intervals with
nominal coverage only when target uses Barnard-Rubin degrees of freedom; pv_fit() gives the full
rule.
pv_fit_direct() requires control$center = "target" (the default of
pv_control()), so the estimate table holds the numbers of the target:
estimate is the target estimate, se is sqrt(diag(target$T_MI)), and
df, df_method, df_complete, interval_role and
coverage_claim_allowed are copied from target: the degrees of freedom
follow the rule chosen in pv_brr_target() and are
not residual degrees of freedom estimated from the stacked fit. The
stacked fit supplies the draws that are calibrated and the diagnostics
described below. The other value, center = "posterior", would keep the
mean of the stacked draws and calibrate only their covariance; it is
accepted by pv_control(), but pv_fit_direct() stops with an error when
it is set.
Fitting engine
With pv_control(backend = "brms") and fit_function = NULL, the brms
engine bundled with pvstackr fits the stacked model. It needs the brms and
posterior packages, and pv_backend_brms_fit_function() describes how it
chooses the Stan backend. A draws_function that you pass replaces its
draws step, but a diagnose_function is ignored: the bundled engine
computes the sampler diagnostics itself. Otherwise, as with the default
backend = "none", pass all three functions. A fit_function that you
pass is used whatever the backend value, which is only passed on to it.
There is no argument for draws computed elsewhere.
Checks and status
Before the model is fitted, pv_fit_direct() stops with an error when
data or formula differ from those used to build target, when
formula has a random-effect term such as (1 | school), when family
is not Gaussian with the identity link, or when prior is not accepted.
After the stacked fit, pvstackr's checks give the fit the status "ok",
"warning" or "blocked":
Sampler diagnostics, checked first. The six values listed under
diagnose_function, from the bundled engine or from your function, must all be available, andchainsandpost_warmup_draws_per_chainmust equalchainsanditer - warmupincontrol. The largest R-hat and the smallest bulk and tail effective sample sizes can give a warning or a block, and any divergent transition blocks the fit. A fit blocked here is not calibrated.Calibration.
delta_c_max, the largest difference between a target estimate and the mean of the stacked draws in target standard errors, andkappa_A, the condition number of the calibration matrix, can each give a warning or a block.Priors. Any explicit
priorgives a warning.
The thresholds are listed under "Status and checks" in
pvstackr_object_contracts. The status is "ok" when no check gave a
warning or a block; it does not show that the sampler converged. A fit
with status "warning" has estimates, and reason_codes and warnings
name the checks. A blocked fit has an empty estimate table and no draws;
it keeps the target and the diagnostics that explain the block.
References
Rubin, D. B. (1987). Multiple Imputation for Nonresponse in Surveys. Wiley.
Barnard, J., & Rubin, D. B. (1999). Small-sample degrees of freedom with multiple imputation. Biometrika, 86(4), 948-955.
See also
pv_brr_target() to build the target,
pv_backend_brms_fit_function() for the bundled brms engine, and
pvstackr_object_contracts for the parts of a fit and the thresholds of
the checks.
Other pvstackr-fitting:
pv_control(),
pv_fit(),
pv_fit_reference(),
pv_fit_stack_psis()
Examples
pisa_tiny <- read.csv(
system.file("extdata", "pisa_tiny.csv", package = "pvstackr")
)
# Declare the columns and build the BRR-Fay target from the bundled
# synthetic data.
design <- pv_design(
pisa_tiny, formula = OUTCOME ~ x + female,
pv_suffix = "READ", expected_M = 2L, expected_R = 4L, id_cols = "CNTSTUID"
)
target <- pv_brr_target(
pisa_tiny, formula = OUTCOME ~ x + female,
pv_cols = design$pv_cols, weight_col = design$weight_col,
rep_weight_cols = design$rep_weight_cols, fay_k = design$fay_k,
id_cols = design$id_cols
)
# A live fit samples with Stan, so it is not run here. With
# backend = "brms" and no fit_function, the bundled brms engine is used.
if (FALSE) { # \dontrun{
fit <- pv_fit_direct(
data = pisa_tiny, formula = OUTCOME ~ x + female, target = target,
control = pv_control(method = "stack_direct", backend = "brms")
)
# With the default backend = "none", fit_function and draws_function are
# required, and without diagnose_function the fit is blocked.
fit <- pv_fit_direct(
data = pisa_tiny, formula = OUTCOME ~ x + female, target = target,
fit_function = my_fit_function, draws_function = my_draws_function,
diagnose_function = my_diagnose_function, cache_dir = NULL
)
} # }
# Read the example fit that ships with pvstackr. It was made from the same
# data with fitting functions that return draws around the target, not
# with a sampler.
path <- system.file(
"extdata", "examples", "pisa_tiny_stack_direct.rds", package = "pvstackr"
)
if (nzchar(path)) {
fit <- readRDS(path)$fit # a stack_direct fit (class pvstackr_fit)
head(get_estimates(fit)) # the target's estimates, se and df
}
#> term estimate se std.error df df_method df_complete
#> 1 b_Intercept 457.894088 1.2873118 1.2873118 1.021194 classic NA
#> 2 b_x 46.883361 0.3717929 0.3717929 1.402308 classic NA
#> 3 b_female 2.143702 3.5550309 3.5550309 1.013730 classic NA
#> conf_level conf_low conf_high conf.low conf.high interval_role
#> 1 0.95 442.31804 473.47013 442.31804 473.47013 descriptive_classic_rubin
#> 2 0.95 44.41457 49.35215 44.41457 49.35215 descriptive_classic_rubin
#> 3 0.95 -41.60687 45.89428 -41.60687 45.89428 descriptive_classic_rubin
#> coverage_claim_allowed parameter_scope target_source
#> 1 FALSE fixed_effect external_brr_fay_rubin
#> 2 FALSE fixed_effect external_brr_fay_rubin
#> 3 FALSE fixed_effect external_brr_fay_rubin
#> target_hash
#> 1 sha256:f173650e9120742a1a6fc6406bfe3ab130e454b17f28e4822cb99e25c108bfaa
#> 2 sha256:f173650e9120742a1a6fc6406bfe3ab130e454b17f28e4822cb99e25c108bfaa
#> 3 sha256:f173650e9120742a1a6fc6406bfe3ab130e454b17f28e4822cb99e25c108bfaa