Point estimate, confidence interval, and one-sided p-value for the
personalization effect – the expected outcome difference between the
best personalized policy and the best single treatment applied to
everyone. Implements Algorithm 1 of Li & Brunskill (2026), layered on
the kpe2 shared-nuisance cross-fit pass in
.single_split_kpe, which fits every nuisance (reward model,
contextual policy, best single arm, and – when is_rct = FALSE –
the propensity) on a shared set of n_nuisance_folds folds and
evaluates the AIPW influence on the held-out block. The default is
leave-one-fold-out: with n_folds = 6, every nuisance is fit on 5/6
of the data and evaluated on the held-out 1/6, rotated six times.
Usage
kpe(
X,
A,
Y,
propensity = NULL,
n_shuffles = 100L,
n_folds = 6L,
n_nuisance_folds = NULL,
is_rct = TRUE,
contextual_policy = "policy_tree",
best_arm = "ips",
reward_model = "random_forest",
propensity_model = "logistic",
policy_features = NULL,
n_cores = 1L,
seed = NULL,
verbose = FALSE
)Arguments
- X
Numeric matrix or data frame of covariates, shape (n, d).
- A
Integer vector of observed treatments, values in \(\{0, \ldots, K-1\}\). Factors are auto-coerced with a message.
- Y
Numeric vector of observed outcomes.
- propensity
Scalar, length-n vector, or (n, K) matrix. A scalar broadcasts; a vector is read as \(p(A_i \mid X_i)\) for the observed action only. Required when
is_rct = TRUE(the default); ignored whenis_rct = FALSE, where the propensity is fit on the nuisance folds andpropensitymay be leftNULL.- n_shuffles
Number of Algorithm-1 repetitions (each with a different seed). Defaults to 100.
- n_folds
Number of folds \(K\) the data is partitioned into per shuffle. Must be at least 2. Defaults to 6.
- n_nuisance_folds
Number of folds \(m\) used to fit all nuisances. Defaults to
n_folds - 1. The evaluation block size is \(b = n\_folds - m\) and must dividen_folds(non-overlapping blocks), so each sample is evaluated exactly once per shuffle. The default gives leave-one-fold-out.- is_rct
Logical. If
TRUE(default),propensityis the known design propensity and nothing is fit for it. IfFALSE, an estimated \(\hat p(a \mid x)\) is fit on the nuisance folds (viapropensity_model) and used in both the AIPW evaluation and the best-arm IPS.- contextual_policy
One of
"policy_tree"or"linear", or a list withfitandpredictfunctions for a BYO contextual policy.- best_arm
One of
"ips"or"simple", or a BYOlist(fit, predict).- reward_model
One of
"random_forest"or"linear", or a BYOlist(fit, predict).- propensity_model
One of
"logistic"or"random_forest", or a BYOlist(fit, predict). Used only whenis_rct = FALSE.- policy_features
Optional integer vector of 1-based column indices passed to the contextual policy. Defaults to all columns.
- n_cores
Number of parallel workers for the shuffle loop. Defaults to 1 (sequential).
- seed
Base random seed. Shuffle s uses
seed + s.- verbose
If
TRUE, emits progress messages.
Value
An object of class "kpe" (an S3 list). See
print.kpe and summary.kpe.
References
Li Z., Brunskill E. (2026) *A Statistical Test for the Benefits of Personalizing Interventions*.
Examples
set.seed(0)
n <- 200
X <- matrix(runif(n * 3, -1, 1), ncol = 3)
A <- rbinom(n, 1, 0.5)
Y <- ifelse(X[, 1] >= 0, A, 0.5 * (1 - A)) + rnorm(n, sd = 0.3)
fit <- kpe(X, A, Y, propensity = 0.5,
n_shuffles = 4, n_folds = 6,
contextual_policy = "linear",
best_arm = "simple",
reward_model = "linear",
seed = 0)
print(fit)
#> K-Fold Personalization Estimator (kpe)
#> n_samples = 200
#> n_shuffles = 4, n_folds = 6
#> psi = 0.2073 (SE 0.03445)
#> 95% CI = [0.1397, 0.2748]
#> p-value = 4.199e-09 (one-sided)
#> policy stability = 0.97