| Title: | Functional Propensity Score for Causal Inference |
|---|---|
| Description: | Implements functional propensity score (FPS) weighting for causal inference with functional treatments. The method estimates weights that balance observed confounders by removing their dependence on the functional treatment and uses a dual formulation of the weighting problem for efficient unconstrained optimization. The framework supports scalar, binary, and functional outcomes, as well as functional covariates, and can be used to estimate marginal causal effects in settings with time-varying exposures. The methodology follows Ciardulli, S., Fontana, N., Vantini, S., and Ieva, F. (2026) "Generalized propensity score weighting for functional causal inference framework" <doi:10.48550/arXiv.2608.03200>. |
| Authors: | Nicole Fontana [aut, cre], Simone Ciardulli [aut], Simone Vantini [ths], Francesca Ieva [ths] |
| Maintainer: | Nicole Fontana <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1 |
| Built: | 2026-09-22 08:59:27 UTC |
| Source: | https://github.com/cran/FPScausal |
Given the FPS weights produced by fps_weighting, estimates the
causal effect function (scalar/binary outcome) or the
causal effect surface (functional outcome) via weighted
least squares. Optional bootstrap inference is available.
fps_effect_estimation( outcome, fps_object, outcome_t_grid = NULL, outcome_domain = NULL, outcome_domain_name = "t", outcome_nbasis = NULL, outcome_pve = 0.95, treatment_pve = NULL, bootstrap = FALSE, B = 1000, alpha = 0.05, true_beta = NULL, seed = NULL )fps_effect_estimation( outcome, fps_object, outcome_t_grid = NULL, outcome_domain = NULL, outcome_domain_name = "t", outcome_nbasis = NULL, outcome_pve = 0.95, treatment_pve = NULL, bootstrap = FALSE, B = 1000, alpha = 0.05, true_beta = NULL, seed = NULL )
outcome |
Numeric vector (scalar/binary, length n) or n x T matrix (functional outcome). |
fps_object |
Object of class |
outcome_t_grid |
Numeric vector. Observation grid for functional
outcome. Required when |
outcome_domain |
Numeric |
outcome_domain_name |
Character. Name of the outcome domain (default
|
outcome_nbasis |
Integer or |
outcome_pve |
Numeric in (0, 1]. PVE threshold for outcome FPCA (default 0.95). |
treatment_pve |
Numeric or |
bootstrap |
Logical. If |
B |
Integer. Number of bootstrap resamples (default 1000). |
alpha |
Numeric. Significance level for bootstrap CIs (default 0.05). |
true_beta |
Optional. Numeric vector (scalar/binary) or matrix
(functional) containing the true causal effect, used for visual comparison
in plots and error metrics in |
seed |
Integer or |
Scalar and binary outcomes.
The treatment FPC scores are regressed on the outcome using
lm (scalar or binary, linear probability model) with the FPS
weights. The estimated effect function is then reconstructed as
.
Functional outcome.
For each outcome FPC component , the regression
is solved with the FPS weights. The causal surface
is reconstructed as
where collects the regression coefficients.
Bootstrap CIs. Scalar/binary: residual bootstrap, B resamples. Functional: pairs bootstrap, B resamples. Pointwise reflected-percentile confidence intervals are returned.
An object of class "fps_effect_estimation", a named list with:
Character: "scalar", "binary", or
"functional".
Estimated causal effect, evaluated on t_grid
(numeric vector for scalar/binary) or on the
t_grid x outcome_t_grid grid (matrix for functional).
Same as beta but from unweighted regression.
FPCA of the treatment used in estimation.
NULL for scalar/binary; FPCA list for
functional outcome.
NULL if bootstrap = FALSE;
otherwise lower and upper bootstrap CI bounds (same shape as
beta).
Significance level used.
Treatment domain grid.
NULL for scalar/binary; outcome grid for
functional.
Treatment domain name.
Outcome domain name.
Passed through unchanged.
The input fps_weighting object.
The matched call.
fps_weighting, simulate_fps_data
dat <- simulate_fps_data(n = 2000, setting = "LL", seed = 1) w <- fps_weighting(dat$X, dat$t_grid, c(0, 1), covariates = dat$C) # Scalar outcome, no bootstrap eff <- fps_effect_estimation(dat$Y, w, true_beta = dat$true_beta) plot(eff, type = "effect") plot(eff, type = "comparison") # With bootstrap (small B for illustration) eff_boot <- fps_effect_estimation(dat$Y, w, bootstrap = TRUE, B = 100, true_beta = dat$true_beta, seed = 42) plot(eff_boot, type = "significance")dat <- simulate_fps_data(n = 2000, setting = "LL", seed = 1) w <- fps_weighting(dat$X, dat$t_grid, c(0, 1), covariates = dat$C) # Scalar outcome, no bootstrap eff <- fps_effect_estimation(dat$Y, w, true_beta = dat$true_beta) plot(eff, type = "effect") plot(eff, type = "comparison") # With bootstrap (small B for illustration) eff_boot <- fps_effect_estimation(dat$Y, w, bootstrap = TRUE, B = 100, true_beta = dat$true_beta, seed = 42) plot(eff_boot, type = "significance")
Computes covariate-balancing weights for a functional treatment using the empirical-likelihood balancing framework of Ciardulli, S. and Fontana, N. (2026). Treatment is represented via FPCA (Karhunen–Loeve expansion); The treatment is first represented via Functional Principal Component Analysis (FPCA) through its Karhunen–Loeve expansion truncated at rank L; the resulting FPC scores and observed confounders are balanced by solving the dual of the empirical-likelihood problem via the BFGS quasi-Newton algorithm. Functional covariates enter the balancing step through their own FPC scores.
fps_weighting( treatment, treat_grid = NULL, treat_domain = NULL, domain_name = "s", nbasis = NULL, pve = 0.95, covariates, cov_grids = NULL, cov_domains = NULL, cov_nbasis = NULL, cov_pve = 0.95, normalize = TRUE, tol = 1e-08, maxit = 1000 )fps_weighting( treatment, treat_grid = NULL, treat_domain = NULL, domain_name = "s", nbasis = NULL, pve = 0.95, covariates, cov_grids = NULL, cov_domains = NULL, cov_nbasis = NULL, cov_pve = 0.95, normalize = TRUE, tol = 1e-08, maxit = 1000 )
treatment |
n x T numeric matrix of observed treatment trajectories, or
an |
treat_grid |
Numeric vector of length T giving the observation grid
of the treatment. Required when |
treat_domain |
Numeric vector |
domain_name |
Character string naming the domain variable (default
|
nbasis |
Integer. Number of B-spline basis functions used for the
treatment FPCA. If |
pve |
Numeric in (0, 1]. Proportion of variance explained threshold for the treatment FPCA (default 0.95). |
covariates |
Either (a) an n x p numeric matrix of scalar covariates,
or (b) a named list with elements |
cov_grids |
A list of numeric vectors (one per functional covariate)
giving the observation grids. Required if |
cov_domains |
A list of numeric vectors |
cov_nbasis |
A list of integers (or |
cov_pve |
Numeric in (0, 1]. PVE threshold for functional covariate FPCA (default 0.95). |
normalize |
Logical. If |
tol |
Relative convergence tolerance for the BFGS optimiser (default 1e-8). |
maxit |
Maximum number of BFGS iterations (default 1000). |
An object of class "fps_weighting", which is a named list
with the following components:
Numeric vector of length n. Positive weights summing to 1.
List returned by the internal FPCA routine,
containing FPC scores (scr), eigenfunctions (efn), mean
function (mean), eigenvalues (eval), variance proportions
(varprop), cumulative PVE (perc), raw pca.fd
object (pca_fd), number of components retained (L), and
the t_grid and domain used.
List of FPCA results for functional covariates, or
NULL if none were supplied.
The n x p scalar covariate matrix used.
Full augmented confounder matrix fed to the optimiser (scalar covariates column-bound with FPC scores of functional covariates).
Convergence code from optim
(0 = success).
The domain name passed via domain_name.
The matched call.
fps_effect_estimation, simulate_fps_data
dat <- simulate_fps_data(n = 2000, setting = "LL", seed = 1) # Scalar covariates only (treat_domain inferred from treat_grid) w <- fps_weighting( treatment = dat$X, treat_grid = dat$t_grid, covariates = dat$C ) print(w) plot(w, type = "balance") # Include one functional covariate w2 <- fps_weighting( treatment = dat$X, treat_grid = dat$t_grid, treat_domain = c(0, 1), covariates = list(scalar = dat$C, functional = list(dat$D)), cov_grids = list(dat$t_grid) ) plot(w2, type = "balance")dat <- simulate_fps_data(n = 2000, setting = "LL", seed = 1) # Scalar covariates only (treat_domain inferred from treat_grid) w <- fps_weighting( treatment = dat$X, treat_grid = dat$t_grid, covariates = dat$C ) print(w) plot(w, type = "balance") # Include one functional covariate w2 <- fps_weighting( treatment = dat$X, treat_grid = dat$t_grid, treat_domain = c(0, 1), covariates = list(scalar = dat$C, functional = list(dat$D)), cov_grids = list(dat$t_grid) ) plot(w2, type = "balance")
Plot diagnostics for fps_effect_estimation objects
## S3 method for class 'fps_effect_estimation' plot( x, type = "effect", point = NULL, which_domain = "treatment", alpha = NULL, max_efn = 4, ... )## S3 method for class 'fps_effect_estimation' plot( x, type = "effect", point = NULL, which_domain = "treatment", alpha = NULL, max_efn = 4, ... )
x |
An object of class |
type |
Character. One of:
|
point |
Numeric scalar or vector. Time point(s) at which to slice the
effect surface (for |
which_domain |
Character. Either |
alpha |
Numeric. Significance level; defaults to |
max_efn |
Integer. Maximum eigenfunctions shown in FPCA panels. |
... |
Ignored. |
A ggplot2 object.
Plot diagnostics for fps_weighting objects
## S3 method for class 'fps_weighting' plot(x, type = "balance", max_efn = 4, ...)## S3 method for class 'fps_weighting' plot(x, type = "balance", max_efn = 4, ...)
x |
An object of class |
type |
Character. One of:
|
max_efn |
Integer. Maximum number of eigenfunctions to show in FPCA panels (default 4). |
... |
Ignored. |
A ggplot2 object (or a list of them for
type = "fpca_covariates").
Print method for fps_effect_estimation objects
## S3 method for class 'fps_effect_estimation' print(x, ...)## S3 method for class 'fps_effect_estimation' print(x, ...)
x |
An object of class |
... |
Ignored. |
Invisibly returns x.
Print method for fps_weighting objects
## S3 method for class 'fps_weighting' print(x, ...)## S3 method for class 'fps_weighting' print(x, ...)
x |
An object of class |
... |
Ignored. |
Invisibly returns x.
Generates a synthetic dataset for testing and illustrating the FPScausal workflow.
simulate_fps_data( n = 200, setting = c("LL", "LN", "NL", "NN"), outcome_type = c("scalar", "functional"), p_scalar = 3, include_functional_cov = TRUE, domain = c(0, 1), seed = NULL )simulate_fps_data( n = 200, setting = c("LL", "LN", "NL", "NN"), outcome_type = c("scalar", "functional"), p_scalar = 3, include_functional_cov = TRUE, domain = c(0, 1), seed = NULL )
n |
Integer. Number of subjects (default 200). |
setting |
Character. One of '"LL"', '"LN"', '"NL"', '"NN"', where the first letter controls the treatment-confounder relationship and the second controls the confounder-outcome relationship. Default '"LL"'. |
outcome_type |
Character. Either '"scalar"' or '"functional"'. Default '"scalar"'. |
p_scalar |
Integer. Number of scalar confounders. Default 3. |
include_functional_cov |
Logical. If 'TRUE' (default), include one functional covariate D(t) in the returned list. |
domain |
Numeric vector |
seed |
Integer or NULL. Random seed for reproducibility. |
**Treatment** X_i(t) is built from 6 Fourier eigenfunctions with eigenvalues (16, 12, 8, 4, 1, 0.5). **Scalar confounders** C_i are 3-dimensional vectors whose relationship to X's FPC scores is either linear or quadratic. An optional **functional covariate** D_i(t) is generated from 4 Fourier components. The **scalar outcome** is Y_i = 1 + integral(beta(t) * X_i(t)) + g(C_i) + N(0,25), and the **functional outcome** is Y_i(t) = mu0(t) + integral(mu(s,t) * X_i(s) ds) + h(D_i) + GP_error.
The four settings ("LL", "LN", "NL", "NN") vary whether the treatment-confounder ("L"inear / "N"onlinear) and confounder-outcome ("L"inear / "N"onlinear) relationships are linear or quadratic.
A named list with:
n x 51 matrix. Observed treatment trajectories on [0,1].
If 'outcome_type = "scalar"': numeric vector of length n. If 'outcome_type = "functional"': n x 51 matrix.
n x p_scalar matrix. Scalar confounders.
n x 51 matrix. Functional covariate (if 'include_functional_cov = TRUE', else 'NULL').
Numeric vector of 51 equally-spaced points on [0,1].
True causal effect. For scalar outcome: numeric vector of length 51. For functional outcome: 51 x 51 matrix mu(s,t).
The 'setting' argument used.
The 'outcome_type' argument used.
dat <- simulate_fps_data(n = 100, setting = "LL", outcome_type = "scalar", seed = 42) str(dat)dat <- simulate_fps_data(n = 100, setting = "LL", outcome_type = "scalar", seed = 42) str(dat)
Summary method for fps_effect_estimation objects
## S3 method for class 'fps_effect_estimation' summary(object, ...)## S3 method for class 'fps_effect_estimation' summary(object, ...)
object |
An object of class |
... |
Ignored. |
Invisibly returns object.
Summary method for fps_weighting objects
## S3 method for class 'fps_weighting' summary(object, ...)## S3 method for class 'fps_weighting' summary(object, ...)
object |
An object of class |
... |
Ignored. |
Invisibly returns object.