pv_fit_stack_psis() runs the "stack_psis" method of pv_fit(). It
takes one set of posterior draws from a model fitted to the stacked data
(one copy of the data per plausible value) and, for each plausible value,
importance weights for these draws and a Pareto k-hat value, computed
outside pvstackr, for example by Pareto smoothed importance sampling
(PSIS) with the loo package. It reweights the draws toward the
posterior of each plausible value and combines the weighted results with
Rubin's rules. pvstackr checks the weights and the k-hat values but does
not compute them.
Usage
pv_fit_stack_psis(
data = NULL,
formula = NULL,
pv_cols = NULL,
control = pv_control(method = "stack_psis"),
family = NULL,
prior = NULL,
fit_function = NULL,
draws_function = NULL,
stack_fit = NULL,
stacked_draws = NULL,
param_map = NULL,
psis_weights = NULL,
pareto_k = NULL,
log_ratios = NULL,
psis_function = NULL,
psis_producer = NULL,
psis_producer_version = NULL,
fallback = c("block", "warn"),
weight_col = NULL,
rep_weight_cols = NULL,
fay_k = 0.5,
id_cols = NULL,
df_method = c("classic", "barnard_rubin"),
df_complete = NULL,
allow_m1 = FALSE,
cache_dir = "cache",
cache_stem = "pvstackr-stack-psis",
additional_args = list()
)Arguments
- data
A data frame, or
NULL(default). Required withfit_function, which receives the stacked data (seefit_function). Otherwise it is optional: given together withformula, it is used only to record the design (the fit'sdesign), and the plausible-value names must then be columns ofdata.- formula
A two-sided formula with the placeholder
OUTCOMEon the left-hand side, such asOUTCOME ~ x + female(seepv_fit()), orNULL(default). Required withfit_function. A random-effect term such as(1 | school)or aweights()term stops the function with an error, also when the formula only serves to record the design.- pv_cols
A character vector with the names of the plausible values, at least two, or
NULL(default). Required withfit_function: the plausible-value columns ofdata. Otherwise it is optional and names the columns of the weights; if the weights have column names, they must be the same. Withoutpv_cols, the column names of the weights are used, orPV1,PV2, ... when they have none.- control
A
pv_control()object withmethod = "stack_psis". The default ispv_control(method = "stack_psis"), andNULLgives the same. Itspsis_k_thresholdsets the k-hat cut-off, and its sampler settings andbackendare only passed on tofit_function.- family, prior
Passed unchanged to
fit_function; pvstackr does not check them. DefaultNULL.- fit_function
Your function that fits the model to the stacked data, or
NULL(default). pvstackr stacksdata(one copy per plausible value, with the plausible value in the column.pvstackr_y) and calls the function once 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; seecache_dir), plus the elements ofadditional_args. The formula has the right-hand side offormula, for example.pvstackr_y | weights(.pvstackr_weight) ~ x + femaleforOUTCOME ~ x + female. The row weight.pvstackr_weightisweight_coldivided by its mean and by the number of plausible values, or 1/M withoutweight_col; a function that ignores it fits an unweighted model. There is no bundled engine for this method, also withpv_control(backend = "brms").- draws_function
Your function that takes the object returned by
fit_functionand returns its draws: a numeric matrix or data frame with one row per draw (at least two), finite values and unique column names. Required withfit_function.- stack_fit
A stacked-fit object of class
pvstackr_stack_fitthat holds its stacked draws, orNULL(default). Thestack_fitcomponent of a fit returned by pvstackr keeps no stacked draws and stops the function with an error, so in practice givestacked_drawsorfit_functioninstead.- stacked_draws
Posterior draws of a model fitted to the stacked data, computed elsewhere, or
NULL(default): a numeric matrix or data frame with one row per draw (at least two), finite values and unique column names.- param_map
NULL(default) or a named list that says which columns of the stacked draws are the fixed effects, by name (fe_names) or by position (fe_idx), as forpv_fit_direct(). WithNULL, the columns whose names start withb_are the fixed effects; withstack_fit, the selection recorded instack_fitis used. Only the fixed effects are used, and their column names become the terms of the estimate table, so they must start withb_. Give a list to leave out other columns that start withb_, such as distributional parameters namedb_sigma_*. Withfit_functionorstack_fit, give the columns by name (fe_names), because positions can point to other columns there.- psis_weights
A numeric matrix of importance weights, one row per stacked draw and one column per plausible value, or
NULL(default). The values must be finite and not negative, and every column must have a positive sum; pvstackr divides each column by its sum. Give it withpareto_k.- pareto_k
The Pareto k-hat values, one per plausible value: a numeric vector named by plausible value, or in the order of the weight columns. Required with
psis_weights, and withlog_ratioswhen there is nopsis_function; leave itNULL(default) withpsis_function, which returns it.- log_ratios
A numeric matrix of log importance ratios for reweighting the stacked draws toward the posterior of each plausible value, with one row per stacked draw, one column per plausible value and finite values; or
NULL(default). Withpsis_function, pvstackr passes it to that function. Withpareto_kalone, pvstackr turns the ratios into normalized weights without smoothing and the fit is blocked (psis_smoothing_not_applied), so this gives only the diagnostics inget_diagnostics(fit)$psis.- psis_function
Your function that takes
log_ratiosand returns a list withweights(a matrix of the same dimensions, with the columns in the same order) andpareto_k, orNULL(default). For example, a function that applies the functionpsis()of the loo package to each column.- psis_producer, psis_producer_version
The name and the version of the program that produced the weights and the k-hat values, such as
"loo"andas.character(packageVersion("loo")): single strings of at most 128 and 64 bytes, without leading or trailing spaces or control characters. Give both or neither; without them the fit is blocked (psis_weight_provenance_incomplete). pvstackr records them in the estimate table and inget_diagnostics(fit)$psisas your statement of how the weights were made, but it does not check them. They cannot be given with weights that pvstackr makes fromlog_ratioswithoutpsis_function.- fallback
"block"(default) or"warn". Both block a fit that fails the check (see Details)."warn"is kept so that older code still runs: it gives a deprecation warning and is only recorded, asfallback_requestedinget_diagnostics(fit)$psis.- weight_col, rep_weight_cols, fay_k, id_cols
The final weight column, the replicate-weight columns, the Fay coefficient and the row-identifier columns, as in
pv_design().weight_colsets the row weights forfit_function(see there). Withdataandformula, all four are checked and recorded in the fit'sdesign; the replicate weights andfay_kare not used in the calculation. DefaultsNULL,NULL,0.5andNULL.- df_method
The rule for the degrees of freedom:
"classic"(default) or"barnard_rubin", which needsdf_complete. Both rules are defined inpv_brr_target(). With either rule the intervals are descriptive.- df_complete
For
df_method = "barnard_rubin", the complete-data degrees of freedom, which you state: one positive number for all fixed effects, or one value per fixed effect, preferably named by the fixed-effect columns (such asb_Intercept); an unnamed vector is taken in the order of the fixed-effect columns. Leave itNULL(default) with"classic": a value there changes nothing but thedf_completecolumn of the estimate table.- allow_m1
Has no effect: a
stack_psisfit needs weights and k-hat values for at least two plausible values. DefaultFALSE.- cache_dir, cache_stem
The folder and the file name that are passed to
fit_function; defaults"cache"and"pvstackr-stack-psis". It receivesfile = 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.- additional_args
A named list of further arguments passed to
fit_function,list()by default. They may not repeat the arguments that pvstackr sets (seefit_function).
Value
A pvstackr_fit object with method = "stack_psis". Read it
with get_estimates() and get_diagnostics(); get_target() and
get_draws() return NULL for this method, and
pvstackr_object_contracts describes every part of the object. The
estimate table has one row per fixed effect with the combined estimate,
its standard error and its degrees of freedom; besides the columns of
every method, it has pooling_source, pooling_hash and the columns
psis_status, pareto_k_max, psis_k_threshold, psis_source,
pareto_k_source, weight_method, psis_producer and
psis_producer_version. get_diagnostics() returns psis (the k-hat
values and their check, the sources of the weights and the
weight-concentration values), pooling (the Rubin's-rules combination,
such as U_bar, B and T_MI) and weighted (the weighted estimate
and covariance of each plausible value and, with
control$return_draws = TRUE, the fixed-effect draws and the normalized
weights). For a blocked fit the estimate table is empty, and
get_diagnostics() returns only psis and redaction, which lists what
was removed.
Details
Inputs
The stacked draws come from exactly one of stacked_draws,
fit_function with draws_function, or stack_fit. The weights come
from psis_weights with pareto_k, or from your psis_function, which
pvstackr calls on log_ratios and which returns both. The weights have
one row per stacked draw and one column per plausible value. Name the
program that produced them with psis_producer and
psis_producer_version: the numbers alone cannot show that the weights
were Pareto-smoothed.
PSIS stabilizes importance weights with a generalized Pareto distribution fitted to the upper tail of the importance ratios; the Pareto k-hat, the estimated shape parameter of that distribution, shows how reliable the reweighted estimates are (Vehtari et al. 2024). pvstackr itself does not run Pareto smoothing or any other part of PSIS: it fits no Pareto distribution and estimates no k-hat.
Calculation
For each plausible value \(m\), pvstackr divides the weights by their
sum and computes the weighted mean \(\hat\beta_m\) and the
weighted covariance matrix \(U_m\) of the fixed-effect draws (see
param_map), with the covariance divided by
\(1 - \sum w^2\). Rubin's rules then combine the \(M\)
results as in pv_brr_target(): the total covariance is
\(T_{\mathrm{MI}} = \bar U + (1 + 1/M) B\),
the standard errors are the square roots of its diagonal, and the degrees
of freedom follow df_method.
Checks and status
By pvstackr's rule, the fit is blocked (status "blocked", with no
estimates, weights or draws) unless every plausible value has a finite
k-hat strictly below control$psis_k_threshold (default 0.7, the largest
value that pv_control() accepts) and the weights come with
psis_producer and psis_producer_version. The reason code says which
part failed: psis_k_not_evaluated (a k-hat is missing or not finite),
psis_k_too_high, psis_weight_provenance_incomplete (no program named)
or psis_smoothing_not_applied (weights that pvstackr made from
log_ratios without smoothing). Otherwise the status is "ok"; a
stack_psis fit never has status "warning", and pvstackr does not check
the sampler diagnostics of the stacked fit.
Vehtari et al. (2024) recommend the cut-off
\(\min(1 - 1/\log_{10} S, 0.7)\) for
\(S\) draws, for example 0.67 for 1000 draws; to use it, set
psis_k_threshold in pv_control().
What is reported
As for every method, only the fixed effects are reported (pv_fit()
gives the scope and the full rule for the intervals). The variance within
each plausible value comes from the weighted posterior draws, not from
replicate weights, so every row of the estimate table has
interval_role = "psis_classic_rubin" or "psis_barnard_rubin" and
coverage_claim_allowed = FALSE. A k-hat below the cut-off lets pvstackr
report the estimates, but the intervals remain descriptive. pvstackr
provides stack_psis as a check on a stacked fit, not as a replacement
for stack_direct.
get_diagnostics(fit)$psis also records, for a blocked fit too, how
concentrated the normalized weights are, and weight_diagnostic_authority
says whether the weights were kept ("retained_weights_recomputed", for a
fit with estimates and control$return_draws = TRUE) or removed
("owned_stamp_bounded_projection"). These values do not change the
status; pvstackr_object_contracts explains them.
References
Vehtari, A., Simpson, D., Gelman, A., Yao, Y., & Gabry, J. (2024). Pareto smoothed importance sampling. Journal of Machine Learning Research, 25(72), 1-58.
Rubin, D. B. (1987). Multiple Imputation for Nonresponse in Surveys. Wiley.
See also
pv_compare_methods() to compare fits,
pv_migrate_legacy_psis_fit() for stack_psis fits saved by earlier
versions of pvstackr, and pvstackr_object_contracts for the parts of a
fit.
Other pvstackr-fitting:
pv_control(),
pv_fit(),
pv_fit_direct(),
pv_fit_reference()
Examples
set.seed(1)
# Simulated stacked draws with the fixed-effect columns b_Intercept and
# b_x, equal placeholder weights with one column per plausible value, and
# k-hat values below the 0.7 cut-off. These weights were not made by
# PSIS, so no program is named, and pvstackr blocks the fit.
M <- 2L
stacked_draws <- matrix(
rnorm(400 * 2), ncol = 2,
dimnames = list(NULL, c("b_Intercept", "b_x"))
)
psis_weights <- matrix(1 / 400, nrow = 400, ncol = M) # equal weights
pareto_k <- rep(0.2, M) # below 0.7
fit_psis <- pv_fit_stack_psis(
stacked_draws = stacked_draws,
pv_cols = paste0("PV", seq_len(M)),
psis_weights = psis_weights,
pareto_k = pareto_k,
control = pv_control(method = "stack_psis")
)
# Status "blocked", reason code psis_weight_provenance_incomplete:
fit_psis
#> pvstackr fit
#> method: stack_psis
#> status: blocked
#> fixed effects: 0
#> target: none
#> draws: not retained
#> diagnostics: psis, redaction
#> reason codes: psis_weight_provenance_incomplete
#> warnings: 1
# The PSIS check has status "provenance_incomplete", and weight_method is
# "unspecified_external" because no program was named:
get_diagnostics(fit_psis)$psis[c("status", "weight_method")]
#> $status
#> [1] "provenance_incomplete"
#>
#> $weight_method
#> [1] "unspecified_external"
#>