The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
This vignette demonstrates Univariable Functional Mendelian Randomization (U-FMR) for estimating the time-varying causal effect of a single longitudinal exposure on a health outcome.
Use univariable estimation (mvfmr_separate() with G2 = NULL) when:
devtools::install_github("NicoleFontana/mvfmr")library(mvfmr)
library(fdapace)
library(ggplot2)set.seed(12345)
# Generate exposure data (we'll only use X1)
sim_data <- getX_multi_exposure(
N = 300,
J = 25,
nSparse = 10
)
cat("Data simulated:\n")
#> Data simulated:
cat(" Sample size:", nrow(sim_data$details$G), "\n")
#> Sample size: 300
cat(" Instruments:", ncol(sim_data$details$G), "\n")
#> Instruments: 25We create an outcome where only X1 has a causal effect:
outcome_data <- getY_multi_exposure(
sim_data,
X1Ymodel = "2", # Linear effect: β(t) = 0.02×t
X2Ymodel = "0", # No effect from X2
X1_effect = TRUE,
X2_effect = FALSE, # X2 does not affect Y
outcome_type = "continuous"
)
cat("Outcome summary:\n")
#> Outcome summary:
summary(outcome_data$Y)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> -101.272 -30.169 -5.085 -2.914 23.769 103.874# FPCA for exposure 1 only
fpca1 <- FPCA(
sim_data$X1$Ly_sim,
sim_data$X1$Lt_sim,
list(dataType = 'Sparse', error = TRUE, verbose = FALSE)
)
cat("FPCA completed:\n")
#> FPCA completed:
cat(" Components selected:", fpca1$selectK, "\n")
#> Components selected: 3
cat(" Variance explained:",
round(sum(fpca1$lambda[1:fpca1$selectK]) / sum(fpca1$lambda) * 100, 1), "%\n")
#> Variance explained: 100 %Estimate the causal effect using mvfmr_separate() with only one exposure:
result <- mvfmr_separate(
G1 = sim_data$details$G, # Instruments for X1
G2 = NULL, # No second exposure
fpca_results = list(fpca1),
Y = outcome_data$Y,
outcome_type = "continuous",
method = "gmm",
max_nPC1 = 4,
max_nPC2 = 4, # Not used when G2 = NULL
n_cores = 1,
true_effects = list(model1 = "2", model2 = "0"),
verbose = FALSE
)
#> [1] "Processing X1"
print(result)
#>
#> Separate Univariable MR Results
#> ================================
#> Exposures: 1
#> Separate instruments: TRUE
#> Outcome: continuous
#> Method: gmm
#>
#> Exposure 1:
#> Components: 2
#> MSE: 0.001915
#> Coverage: 0.804plot(result)The solid colored lines show the estimated time-varying causal effects, with shaded bands representing 95% confidence intervals. The dashed red lines (when present) indicate the true time-varying effects used in the simulation.
# Coefficients for basis functions
cat("Estimated coefficients:\n")
#> Estimated coefficients:
print(round(coef(result, exposure = 1), 4))
#> [1] -3.8088 1.5315
# Time-varying effect curve
cat("\nFirst 10 time points of β(t):\n")
#>
#> First 10 time points of β(t):
head(result$exposure1$effect, 10)
#> [1] 0.02639840 0.03866777 0.05175991 0.06578036 0.08081493 0.09688697
#> [7] 0.11391916 0.13170830 0.14992295 0.16813235cat("Performance:\n")
#> Performance:
cat(" MISE:", round(result$exposure1$performance$MISE, 6), "\n")
#> MISE: 0.001915
cat(" Coverage:", round(result$exposure1$performance$Coverage, 3), "\n")
#> Coverage: 0.804
cat(" Components used:", result$exposure1$nPC_used, "\n")
#> Components used: 2U-FMR also works with binary outcomes:
# Generate binary outcome
outcome_binary <- getY_multi_exposure(
sim_data,
X1Ymodel = "2",
X2Ymodel = "0",
X1_effect = TRUE,
X2_effect = FALSE,
outcome_type = "binary"
)
# Estimate with control function
result_binary <- mvfmr_separate(
G1 = sim_data$details$G,
G2 = NULL,
fpca_results = list(fpca1),
Y = outcome_binary$Y,
outcome_type = "binary",
method = "cf", # Control function for binary
max_nPC1 = 3,
n_cores = 1,
verbose = FALSE
)
print(result_binary)
cat("Cases:", sum(outcome_binary$Y == 1), "\n")
cat("Controls:", sum(outcome_binary$Y == 0), "\n")The package includes 10 pre-defined time-varying effect shapes:
"0": No effect (null)"1": Constant (β = 0.1)"2": Linear increasing"3": Linear decreasing"4": Early life effect"5": Late life effect"6": Early decreasing"7": Late increasing"8": Quadratic (U-shape)"9": Cubic# Get robust confidence intervals via bootstrap
result_boot <- mvfmr_separate(
G1 = sim_data$details$G,
G2 = NULL,
fpca_results = list(fpca1),
Y = outcome_data$Y,
outcome_type = "continuous",
bootstrap = TRUE,
n_bootstrap = 100,
max_nPC1 = 4,
verbose = FALSE
)
# Bootstrap CIs are stored in result_boot$exposure1$...If you have GWAS summary statistics instead of individual-level outcome data:
# Simulate GWAS summary statistics
by_outcome <- rnorm(25, 0.02, 0.01)
sy_outcome <- runif(25, 0.005, 0.015)
result_2sample <- fmvmr_separate_twosample(
G1_exposure = sim_data$details$G,
G2_exposure = NULL,
fpca_results = list(fpca1),
by_outcome1 = by_outcome,
by_outcome2 = NULL,
sy_outcome1 = sy_outcome,
sy_outcome2 = NULL,
ny_outcome = 50000,
max_nPC1 = 3,
verbose = FALSE
)
print(result_2sample)vignette("multivariable-fmr") for joint estimationinst/examples/test_U-FMR.R for all scenariosIf you use this package, please cite:
Fontana, N., Ieva, F., Zuccolo, L., Di Angelantonio, E., & Secchi, P. (2025). Unraveling time-varying causal effects of multiple exposures: integrating Functional Data Analysis with Multivariable Mendelian Randomization. arXiv preprint arXiv:2512.19064.
sessionInfo()
#> R version 4.3.0 (2023-04-21)
#> Platform: aarch64-apple-darwin20 (64-bit)
#> Running under: macOS Ventura 13.6
#>
#> Matrix products: default
#> BLAS: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
#>
#> locale:
#> [1] C/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#>
#> time zone: Europe/Rome
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] ggplot2_3.5.2 fdapace_0.5.9 mvfmr_0.1.0
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 shape_1.4.6 xfun_0.41
#> [4] bslib_0.6.1 htmlwidgets_1.6.4 lattice_0.21-8
#> [7] numDeriv_2016.8-1.1 vctrs_0.6.5 tools_4.3.0
#> [10] generics_0.1.3 parallel_4.3.0 tibble_3.2.1
#> [13] fansi_1.0.6 highr_0.10 cluster_2.1.4
#> [16] pkgconfig_2.0.3 Matrix_1.6-4 data.table_1.14.10
#> [19] checkmate_2.3.1 lifecycle_1.0.4 farver_2.1.1
#> [22] compiler_4.3.0 stringr_1.5.1 progress_1.2.3
#> [25] munsell_0.5.0 codetools_0.2-19 htmltools_0.5.7
#> [28] sass_0.4.8 yaml_2.3.8 glmnet_4.1-8
#> [31] htmlTable_2.4.2 Formula_1.2-5 pracma_2.4.4
#> [34] pillar_1.9.0 crayon_1.5.3 jquerylib_0.1.4
#> [37] MASS_7.3-58.4 cachem_1.0.8 Hmisc_5.1-1
#> [40] iterators_1.0.14 rpart_4.1.19 foreach_1.5.2
#> [43] tidyselect_1.2.0 digest_0.6.33 stringi_1.8.3
#> [46] dplyr_1.1.4 labeling_0.4.3 splines_4.3.0
#> [49] fastmap_1.1.1 grid_4.3.0 colorspace_2.1-0
#> [52] cli_3.6.2 magrittr_2.0.3 base64enc_0.1-3
#> [55] survival_3.5-7 utf8_1.2.4 withr_2.5.2
#> [58] foreign_0.8-84 prettyunits_1.2.0 scales_1.3.0
#> [61] backports_1.4.1 rmarkdown_2.25 nnet_7.3-18
#> [64] gridExtra_2.3 hms_1.1.3 evaluate_0.23
#> [67] knitr_1.45 doParallel_1.0.17 rlang_1.1.6
#> [70] Rcpp_1.0.11 glue_1.6.2 pROC_1.18.5
#> [73] rstudioapi_0.15.0 jsonlite_1.8.8 R6_2.5.1
#> [76] plyr_1.8.9These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.