The two readings of a result, defined for the class new_ipw() constructs
and for the pooled results pool_ipw() returns.
as_marginal()returns the result reporting the causal contrast estimates.as_conditional()returns the result presenting the outcome model's coefficient surface.
Value
x presenting the reading asked for. The methods on ipw change the
effects field and nothing else, so every other field comes back as it
went in, the covariance attached to estimates included. The methods on
ipw_pooled exchange estimates, pooling, and the recorded mode with the
reading stored under alternate, so the reading that was presented is what
the returned result stores there, and the components shared by both readings
come back as they went in. A pooled result that does not carry the reading
asked for raises an error rather than returning one.
Details
Both surfaces exist on every ipw result, so on one of those these generics
record which one the result presents rather than computing anything. They set
the effects field of the new_ipw() contract and read nothing else, which
makes them the supported way to move a result between the two readings: a
caller writes as_conditional(res) rather than assigning to the field.
The methods on ipw are total. Every such result has one of the two modes,
so asking for either is always answerable: they never error, asking twice
says what asking once said, and a result that goes out to the other reading
and back is the result that went in. A result built before the field existed
carries six fields rather than seven and reads as marginal, which is the mode
every method produced then.
The generics live here for the reason print() does. Two packages each
registering as_conditional.ipw() would collide in the shared S3 method
table, and a caller writing against a result would then get whichever package
was installed last rather than the contract. There is no marginal or
conditional reading of an object that is not an IPW result, so the default
method signals an error rather than inventing one.
The readings a pooled result carries
pool_ipw() pools both readings of one set of results whenever it can
compute both, and stores the one the call did not name whole, under the
alternate component. The methods on ipw_pooled therefore swap which
reading the result presents rather than setting a field: the pooled
estimates, the pooling diagnostics, and the recorded mode move together, and
the components that describe the pooled analyses rather than a reading of
them stay where they are.
Where both readings were pooled, the properties above hold. Asking a pooled
result for the reading it already presents gives that result back, and a
result taken out to the other reading and back is the result that went in.
Totality is what these methods cannot keep. A reading the pooling could not
compute is recorded as unavailable rather than computed, and asking for it
raises an error of class causalgenerics_pool_missing_surface_marginal or
causalgenerics_pool_missing_surface_conditional, and of the general class
causalgenerics_pool_missing_surface. That condition carries the reading
under effects and, under reason, the refusal that reading raised when it
was pooled, which is the same wording the caller would have seen from
pool_ipw() had they asked for it there.
A result pooled before both readings were kept records no alternate at all.
Asking such a result for the other reading is refused with the same two
classes and a reason of NULL, and the message says that pooling the
results again gives a result carrying both.
See also
new_ipw() for the result class and the field these generics set,
and pool_ipw() for the pooled result and the reading it stores beside the
one it presents.
Examples
dat <- data.frame(
x = rep(c(-1.5, -0.5, 0.5, 1.5), each = 5),
z = rep(c(0, 1), 10),
y = rep(c(0, 1, 1, 0, 1), 4)
)
# Written out literally, in the shape the `ipw()` return contract documents.
estimates <- data.frame(
effect = "rd",
estimate = 0.199882,
std.err = 0.092425,
z = 2.1626,
ci.lower = 0.018732,
ci.upper = 0.381032,
conf.level = 0.95,
p.value = 0.030570
)
res <- new_ipw(
estimand = "ate",
wt_mod = glm(z ~ x, family = binomial(), data = dat),
outcome_mod = glm(y ~ z, family = quasibinomial(), data = dat),
estimates = estimates,
se_method = "linearization",
fit = NULL
)
# A method that names no mode reports marginal effects.
res$effects
#> [1] "marginal"
as_conditional(res)$effects
#> [1] "conditional"
# Asking for the reading a result already reports gives the result back, and
# the two readings round-trip.
identical(as_marginal(res), res)
#> [1] TRUE
identical(as_marginal(as_conditional(res)), res)
#> [1] TRUE
# Neither reading exists for an object that is not an IPW result.
try(as_marginal(1:3))
#> Error in as_marginal.default(1:3) :
#> No `as_marginal()` method for an object of class <integer>.