Skip to contents

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.

Usage

as_marginal(x, ...)

as_conditional(x, ...)

Arguments

x

An ipw or ipw_pooled object. These generics dispatch on this argument.

...

Arguments passed to methods.

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>.