psw objects are numeric vectors that carry metadata about propensity score
weights, including the target estimand and whether the underlying propensity
scores were trimmed, truncated, or calibrated.
Most users will encounter psw objects as return values from wt_ate() and
related weight functions. These constructor and helper functions are useful
for inspecting weight objects or for package developers extending propensity.
Usage
new_psw(
x = double(),
estimand = NULL,
stabilized = FALSE,
trimmed = FALSE,
truncated = FALSE,
calibrated = FALSE,
stabilization_score = NULL,
...
)
psw(
x = double(),
estimand = NULL,
stabilized = FALSE,
trimmed = FALSE,
truncated = FALSE,
calibrated = FALSE,
stabilization_score = NULL
)
is_psw(x)
is_stabilized(wt)
stabilization_score(wt)
as_psw(x, estimand = NULL)Arguments
- x
For
psw()andnew_psw(): a numeric vector of weights (default:double()). Foris_psw()andas_psw(): an object to test or coerce.- estimand
A character string identifying the target estimand (e.g.,
"ate","att","ato"). Defaults toNULL.- stabilized
Logical. Were the weights stabilized? Defaults to
FALSE.- trimmed
Logical. Were the weights derived from trimmed propensity scores? Defaults to
FALSE.- truncated
Logical. Were the weights derived from truncated propensity scores? Defaults to
FALSE.- calibrated
Logical. Were the weights derived from calibrated propensity scores? Defaults to
FALSE.- stabilization_score
Optional numeric stabilization score to record on the object, either a single value or one value per observation. Every value must be positive and finite. Defaults to
NULL, meaning no fixed score was supplied.- ...
Additional attributes stored on the object (developer use only).
- wt
A
psworcausal_wtsobject.
Value
new_psw(),psw(),as_psw(): Apswvector.is_psw(),is_stabilized(): A single logical value.stabilization_score(): A numeric value or vector, orNULLif none was recorded or a per-observation score was dropped.
Details
Constructors
psw()is the user-facing constructor. It coercesxto double and validates inputs before creating the object.new_psw()is the low-level constructor intended for developers. It assumesxis already a double vector and performs minimal validation.as_psw()coerces an existing numeric vector to apswobject.
Queries
is_psw()tests whether an object is apswvector.is_stabilized()returnsTRUEif the weights are stabilized.stabilization_score()returns the user-supplied stabilization score, orNULLwhen none was recorded or when a per-observation score was dropped because an operation changed the length of the weights.
The stabilization score
A stabilization_score is the multiplier the weights were stabilized on. It
holds either a single value, which scales every weight, or one value per
observation, which scales each weight by its own. Both forms are checked
where the score is recorded: a score must be numeric, positive, and finite,
and hold a length the weights can use, and one that does not is refused with
an error of class propensity_stabilization_score_error. A score is recorded
as a plain double vector, with its storage type normalized and any names
dropped, so a score written 1L and one written 1 are the same score and
combine without conflict.
A zero-length psw is a prototype: it records what a result built from it
will carry rather than describing observations of its own, so a
per-observation score on one is recorded as given and checked for length when
the observations arrive. A cast whose data arrives at a length the score does
not match drops the score rather than refusing the cast, since the score
describes the prototype's observations and says nothing about the data being
cast. A cast to no observations keeps it, having brought no observations for
it to contradict.
psw objects also inherit the broader causal_wts class. The accessors that
class carries, causalgenerics::is_causal_wt(),
causalgenerics::estimand(), and estimand<-, are re-exported by propensity
and documented at causalgenerics::estimand().
Arithmetic and combining
Arithmetic operations on psw objects preserve the class and attributes,
so operations like normalization (weights / sum(weights)) retain metadata.
An operation between two psw objects merges what each of them records. Two
different estimands are pasted together, and an estimand only one operand
names stands for the result; the result is stabilized only when both operands
are, and it is marked as trimmed, truncated, or calibrated when either
operand is. The remaining attributes, the stabilization_score, the records
left by a modified propensity score, and the attributes describing a
categorical exposure, are carried by agreement: one only a single operand
records carries, and one both record with the same value carries. One they
record differently is dropped, since neither value describes the result, and
a warning of class propensity_metadata_conflict_warning names it, once for
each attribute dropped that way and whatever order the inputs were given in.
The rule is applied per operation, so an attribute one operation drops for a
disagreement can be carried again by a later operation whose operands agree.
A stabilization_score is carried only when the result is stabilized, which
takes both operands. A result that is not stabilized drops the score without
comment.
Combining psw objects with c() preserves the class only when all
metadata matches; mismatched metadata produces a warning and falls back to a
plain numeric vector. Concatenation appends one set of observations to
another, so the positions a modification record names would describe units
from the other input; those records are dropped from the result whether or
not the inputs agree on them. The categorical attributes name exposure levels
rather than positions and carry when the inputs agree.
Subsetting with [ preserves class and attributes for vector subscripts.
Two kinds of attribute hold one value per observation and so cannot be
re-indexed for a subset: a stabilization_score with more than one value,
and the records left by a modified propensity score (ps_trim_meta,
ps_trunc_meta, and ps_calib_meta). Where an operation goes through
vctrs, these are carried when the result comes back at the length they were
recorded on and dropped when it does not. Any same-length operation keeps
them, a reordering or a subscript with duplicates included, so the positions
a record names can end up describing different observations than they did.
Dropping the stabilization_score warns, because the score was supplied by
the user and the weights can be recomputed on the subset. Dropping a
modification record is silent, because these records also travel by routes
vctrs does not see, and a warning on the one route it controls would be
neither complete nor about anything the user wrote. Subassignment that grows
the vector carries a record across the length change, since [<- casts the
replacement and then leaves base R to preserve the attributes; and
model.frame() drops the NA-weighted rows from a weights column in C and
re-attaches the original variable's attributes to the shortened result, so
weights built on trimmed propensity scores come back out of every outcome
model fit on them still carrying a record written for rows that are no
longer there.
Honesty therefore lives at query time. is_unit_trimmed() and
is_unit_truncated() answer by position, so each checks that the record
covers the vector it is given and raises an error of class
propensity_missing_meta_error when it does not, or when weights marked as
modified carry no record at all, rather than name modified units at stale
positions. is_refit() reads a single flag rather than a position, so it
answers from any record present and refuses only when the record is absent
entirely.
The result of any of these operations stays a psw and keeps every other
attribute, including its stabilized, trimmed, truncated, and calibrated
status, and the attributes describing a categorical exposure, which name the
exposure levels rather than the units and so mean the same thing at any
length.
Matrix or array subscripts intentionally drop the psw class and return
a plain numeric vector via base R linear indexing; this is required so
glm.fit()-style internal indexing works on psw-weighted GLMs.
Summary functions (sum(), mean(), etc.) return plain numeric values.
See also
wt_ate(), wt_att(), wt_atu(), wt_atm(), wt_ato() for
calculating propensity score weights (which return psw objects).
ps_trim(), ps_trunc(), and ps_calibrate() for modifying propensity
scores before weight calculation.
Examples
# Create psw objects directly
w <- psw(c(1.2, 0.8, 1.5), estimand = "ate")
w
#> <psw{estimand = ate}[3]>
#> [1] 1.2 0.8 1.5
# Query metadata
is_psw(w)
#> [1] TRUE
estimand(w)
#> [1] "ate"
is_stabilized(w)
#> [1] FALSE
# Coerce a plain numeric vector
as_psw(c(1.0, 2.0), estimand = "att")
#> <psw{estimand = att}[2]>
#> [1] 1 2
# Arithmetic preserves the psw class
w / sum(w)
#> <psw{estimand = ate}[3]>
#> [1] 0.3428571 0.2285714 0.4285714
# Combining: compatible metadata is preserved
x <- psw(c(1.2, 0.8), estimand = "ate")
y <- psw(c(1.1, 0.9), estimand = "ate")
c(x, y)
#> <psw{estimand = ate}[4]>
#> [1] 1.2 0.8 1.1 0.9
# Combining: incompatible metadata warns and returns numeric
x <- psw(c(1.2, 0.8), estimand = "ate")
y <- psw(c(1.1, 0.9), estimand = "att")
c(x, y)
#> Warning: Converting psw to numeric: incompatible estimands 'ate' and 'att'
#> ℹ Metadata cannot be preserved when combining incompatible objects
#> ℹ Use identical objects or explicitly cast to numeric to avoid this warning
#> [1] 1.2 0.8 1.1 0.9
