pv_compare_methods() lines up the fixed-effect estimates of two or more
fits, for example a stack_direct fit and a per_pv fit of the same
model, and computes how far each fit's estimates are from those of a
reference fit. It also records the status, the kind of interval and the
source labels of each fit, and the time that each fit took if you supply
it. It does not fit any model itself.
Usage
pv_compare_methods(
...,
fits = NULL,
reference_method = NULL,
timings = NULL,
include_fits = FALSE
)Arguments
- ...
Two or more fits (class
pvstackr_fit) frompv_fit()or the method functions, optionally named, or a single list of fits.- fits
A list of fits, as an alternative to
...; defaultNULL. Give the fits either in...or infits, not both.- reference_method
The label or the method of the reference fit, or
NULL(default) to choose it by the rule in Details. It must match exactly one fit, and that fit must not be blocked.- timings
Elapsed times in seconds that you measured for the fits, for example with
system.time(): a numeric vector or list named by fit label or method, with finite values of 0 or more. pvstackr does not time the fits itself. WithNULL(default), and for a fit whose label and method are not among the names, the time isNA.- include_fits
TRUEto keep the compared fits in the elementfitsof the result; defaultFALSE.
Value
A list of class pvstackr_method_comparison. Read it with
get_estimates() and get_diagnostics(); its print() and summary()
methods are described in pvstackr_method_comparison_summary.
get_estimates() returns the estimate table, a data frame with one row
per fit and fixed effect:
method,method_label,termandstatus: the method and the label of the fit, the fixed effect and the status of the fit.estimate,se(repeated asstd.error),df,df_method,df_complete,conf_level,conf_low,conf_high,interval_roleandcoverage_claim_allowed: copied from the estimate table of the fit (pvstackr_object_contracts describes them).psis_source,pareto_k_source,weight_method,psis_producerandpsis_producer_version: how the weights of astack_psisfit were obtained;NAfor the other methods.reference_method,reference_estimateandreference_se: the label of the reference fit and its estimate and standard error.estimate_diff,se_ratio,abs_z_diffandagreement_band: the comparison with the reference fit (see "Reading the agreement").reason_codes: the reason codes of the fit, separated by commas.
get_diagnostics() returns a list:
reference_method: the label of the reference fit.methodsandstatuses: the method and the status of each fit, named by label.blocked_methodsandwarning_methods: the labels of the fits with status"blocked"or"warning".agreement: a data frame with one row per fit that givesmax_abs_z_diffandmax_abs_log_se_ratio(the largestabs_z_diffand the largest absolute log ofse_ratioover its fixed effects),n_terms(the number of fixed effects in the comparison) andn_available(the number of them with an estimate from this fit).method_diagnostics: a data frame with one row per fit. Its columns aremethod,method_label,status,reason_codesandwarning_count(the number of warnings);n_termsandn_available;df_method,interval_role,coverage_claim_allowedandn_descriptive_intervals(the number of rows withcoverage_claim_allowed = FALSE); the source labels and checksumstarget_source,target_hash,pooling_sourceandpooling_hash(see "Source labels" in pvstackr_object_contracts);center("target"for astack_directfit,NAotherwise); the five flags oftarget_overlapfor this fit;psis_status,pareto_k_max, the five weight-source columns of the estimate table,weight_ess_iid_min,weight_ess_fraction_minandmax_normalized_weight_max(the smallest or largest value over the plausible values), which describe astack_psisfit and areNAfor the other methods; andn_fitsandelapsed_seconds. Herecoverage_claim_allowedisTRUEonly when all available rows of the fit haveTRUE,FALSEwhen any hasFALSE, andNAfor a fit without estimates.target_sourceis only a label: astack_psisfit has no target object.timing: a data frame with one row per fit that givesn_fits, the number of models fitted (the number of plausible values forper_pv, 1 forstack_directandstack_psis,NAfor a blockedstack_directfit), andelapsed_seconds, the time fromtimings(NAwithout one).target_overlap: whether fits share a target or a combined result (see "Reading the agreement").
The result also holds this list as diagnostics; the tables as
estimate_table (and table), diagnostic_table (the same as
method_diagnostics), agreement and timing; reference_method,
methods and method_labels; and the compared fits as fits when
include_fits = TRUE (otherwise NULL). Its other elements are
described in "Technical details".
Details
Each fit is known by a label: its argument name, such as per_pv in
pv_compare_methods(stack_direct = fit_a, per_pv = fit_b), or its method
when it has no name. Repeated labels get a suffix, as in "per_pv_1".
The estimate table has one row per fit and fixed effect, for every fixed
effect that appears in any of the fits; a fit without that fixed effect
has NA in the row.
Differences are taken from the reference fit, which reference_method
names. By default it is the first per_pv fit that is not blocked or, if
there is none, the first fit that is not blocked. A blocked fit cannot be
the reference, but it keeps its rows, with NA values and its reason
codes, so that it stays visible in the comparison.
pv_compare_methods() stops with an error if it gets fewer than two fits,
an object that is not a fit or a fit that was changed after it was
created, and when all fits are blocked.
Reading the agreement
estimate_diff is the estimate minus the reference estimate, se_ratio
is the standard error divided by the reference standard error, and
abs_z_diff is the absolute difference divided by
sqrt(se^2 + reference_se^2). agreement_band groups abs_z_diff by
pvstackr's cut-offs: "close" below 0.1, "moderate" from 0.1 to below
0.5, and "different" from 0.5 on. It is "not_available" for a blocked
fit and where either estimate is missing. The rows of the reference fit
itself have a difference of 0 and are "close".
These values describe how far apart the fits are; they are not a
statistical test. The fits usually come from the same data and plausible
values, and a stack_psis fit may reweight the draws of the same stacked
model, so agreement between them is not independent confirmation of a
result. Where fits share their numbers, agreement follows by
construction: a stack_direct fit reports the estimates and standard
errors of its target, so two stack_direct fits calibrated to the same
target have the same estimates and standard errors, whatever their draws.
get_diagnostics(x)$target_overlap records such cases:
shared_target_hashandshared_pooling_hash:TRUEwhen two or more fits have the sametarget_hash(orpooling_hash).shared_external_target:TRUEonly when two or more fits havetarget_source = "external_brr_fay_rubin"and the sametarget_hash, that is, when they arestack_directfits calibrated to the same target frompv_brr_target(). A blockedstack_directfit keeps its target, so it counts as well.shares_reference_targetandshares_reference_pooling:TRUEwhen a fit other than the reference fit has thetarget_hash(orpooling_hash) of the reference fit.shared_target_sources: thetarget_sourcelabels that occur in two or more fits.independence_caveat_required:TRUEwhen any of these flags isTRUEorshared_target_sourcesis not empty.independence_caveat: the text of the line beginning "provenance note:", whichprint()shows for every comparison.
Each row keeps the interval columns of its fit, so an interval is read by
the rule of that fit: only stack_direct rows whose target uses
Barnard-Rubin degrees of freedom have coverage_claim_allowed = TRUE
(pv_fit() gives the rule). print() adds a line beginning
"interval note:" when some or all intervals are descriptive.
Technical details
The result keeps what the comparison uses from each fit
(source_fit_projection), with the fit's checksum
(source_fit_validation) and, for a stack_psis fit, a copy of the fit
without its stacked draws and weights (source_fit_reportability).
validation holds a SHA-256 checksum of the comparison, created_at the
time it was made, schema_version its format version and provenance a
record of how it was made; warnings is empty. The functions that read a
comparison stop with an error if it was changed after it was created or
was saved by pvstackr 0.1.x; make it again from current fits.
See also
pv_fit() to make the fits,
pvstackr_method_comparison_summary for print() and summary(), and
vignette("a4-comparing-methods", package = "pvstackr") for a comparison
of the three methods.
Examples
path <- system.file(
"extdata", "examples", "pisa_tiny_stack_direct.rds", package = "pvstackr"
)
if (nzchar(path)) {
fit_direct <- readRDS(path)$fit # the bundled stack_direct fit
# A per_pv fit made from random draws with the same fixed-effect names
# (b_Intercept, b_x, b_female). It is not fitted to any data, so the
# differences below only show the layout of the output.
set.seed(1)
fe_names <- c("b_Intercept", "b_x", "b_female")
draw_block <- function() {
matrix(rnorm(200 * 3), ncol = 3, dimnames = list(NULL, fe_names))
}
fit_per_pv <- pv_fit_reference(
per_pv_draws = list(PV1READ = draw_block(), PV2READ = draw_block()),
control = pv_control(method = "per_pv")
)
cmp <- pv_compare_methods(stack_direct = fit_direct, per_pv = fit_per_pv)
print(cmp) # reference fit, labels and the two notes
get_estimates(cmp)[, c("method_label", "term", "estimate", "se",
"abs_z_diff", "agreement_band")]
}
#> pvstackr method comparison
#> reference: per_pv
#> methods: stack_direct=stack_direct, per_pv=per_pv
#> fixed effects: 3
#> provenance note: Agreement bands are descriptive; shared target, pooling, or source metadata should not be read as independent corroboration.
#> interval note: intervals are descriptive rather than coverage-claimable.
#> method_label term estimate se abs_z_diff agreement_band
#> 1 stack_direct b_Intercept 457.89408827 1.2873118 278.8090409 different
#> 2 stack_direct b_x 46.88336051 0.3717929 42.4029899 different
#> 3 stack_direct b_female 2.14370179 3.5550309 0.5953395 different
#> 4 per_pv b_Intercept -0.03206137 1.0200128 0.0000000 close
#> 5 per_pv b_x 0.02385441 1.0406796 0.0000000 close
#> 6 per_pv b_female -0.06147476 1.0401232 0.0000000 close