Skip to contents

Overview

TWAS weights are per-variant coefficients that predict a molecular phenotype (gene expression, splicing, protein abundance) from genotype. Once learned, the weights are applied to GWAS summary statistics to infer per-gene TWAS Z-scores (see the TWAS Z-score vignette).

pecotmr supports three weight-learning workflows depending on the data you have:

Data you have Entry point Methods supported
Individual-level genotype + phenotype, single context univariate_analysis_pipeline() (sets twas_weights = TRUE) or twas_weights_pipeline() SuSiE family, mr.ash, elastic net, LASSO, MCP, SCAD, L0Learn, Bayesian alphabet methods
Individual-level data, multiple contexts (e.g. multi-tissue) twas_multivariate_weights_pipeline() mr.mash, mvSuSiE
QTL summary statistics, single context twas_weights_sumstat_pipeline() (replaces OTTERS) lassosum-RSS, PRS-CS, SDPR, SuSiE-RSS family, P+T, MCP-RSS, SCAD-RSS, L0Learn-RSS, mr.ash-RSS
QTL summary statistics, multiple contexts twas_multivariate_weights_sumstat_pipeline() mr.mash-RSS, mvSuSiE-RSS

All three return a TWASWeights S4 object that harmonize_twas() / twas_pipeline() consume directly.

Quick start: individual-level weights

The simplest path for individual-level data is to call univariate_analysis_pipeline() with twas_weights = TRUE — fine-mapping and weight learning happen in one call, sharing the fitted SuSiE models.

data(eqtl_region_example)
X <- eqtl_region_example$X
y <- as.numeric(eqtl_region_example$y_res)
maf <- apply(X, 2, function(g) {
  f <- mean(g, na.rm = TRUE) / 2
  min(f, 1 - f)
})

set.seed(42)
sub <- sort(sample(ncol(X), 300))

fit <- univariate_analysis_pipeline(
  X = X[, sub], Y = y, maf = maf[sub],
  twas_weights = TRUE,
  cv_folds = 3,
  finemapping_extra_opts = list(refine = FALSE),
  region = "chr22:32119000-33000000",
  verbose = 0
)

names(fit$twas_weights_result)
## [1] "susie_weights_intermediate" "empirical_pi"              
## [3] "twas_weights"               "twas_predictions"          
## [5] "twas_cv_result"             "ensemble"                  
## [7] "total_time_elapsed"
getMethodNames(fit$twas_weights_result$twas_weights)
##  [1] "mrash_weights"     "susie_weights"     "susie_inf_weights"
##  [4] "enet_weights"      "lasso_weights"     "mcp_weights"      
##  [7] "scad_weights"      "l0learn_weights"   "bayes_r_weights"  
## [10] "bayes_c_weights"   "ensemble_weights"

The default preset fits ten methods (SuSiE, SuSiE-inf, mr.ash, elastic net, LASSO, MCP, SCAD, L0Learn, BayesR, BayesC) plus an ensemble combination learned via stacked regression. The TWASWeights S4 object holds all per-method weight vectors and (optionally) the underlying fits.

Available weight methods

Methods are selected by passing a character vector to weight_methods on twas_weights_pipeline() or univariate_analysis_pipeline(). Short names map to functions of the form <method>_weights(stat, LD, ...):

Family Methods
SuSiE family susie, susie_inf, susie_ash (see the fine-mapping vignette for what each models)
Mixture priors mrash (mr.ash adaptive shrinkage)
Penalized regression enet, lasso, mcp, scad, l0learn
Bayesian alphabet bayes_r, bayes_l, bayes_a, bayes_b, bayes_c, bayes_n, b_lasso
DPR dpr_vb, dpr_gibbs, dpr_adaptive_gibbs
Multi-context mrmash, mvsusie (use twas_multivariate_weights_pipeline() instead)

Presets

Preset Methods
"fast_default" susie, susie_inf, mrash, enet, lasso, mcp, scad, l0learn
"default" fast_default + bayes_r, bayes_c
# Use a preset
fit <- univariate_analysis_pipeline(
  X = X[, sub], Y = y, maf = maf[sub],
  twas_weights = TRUE,
  weight_methods = "fast_default",   # passed through to twas_weights_pipeline
  cv_folds = 3, verbose = 0
)

# Or a custom subset
fit <- twas_weights_pipeline(
  X = X[, sub], y = y,
  susie_fit = fit$susie_fitted,
  weight_methods = c("susie", "enet", "lasso"),
  cv_folds = 3, verbose = 0
)

When weight_methods = "default" (or "fast_default"), the pipeline also estimates a spike-and-slab sparsity prior from mr.ash and injects it into BayesC / BayesB before fitting them — set estimate_pi = FALSE to skip.

Cross-validation and ensemble weights

cv_folds > 1 runs k-fold CV per method, returning per-fold predictions plus the metrics needed to filter imputable genes (correlation, adjusted R², p-value, RMSE, MAE):

cv <- fit$twas_weights_result$twas_cv_result
str(cv$performance, max.level = 2)  # method -> matrix(metrics x context)
cv$sample_partition                  # data.frame(Sample, Fold)

When ensemble = TRUE (default) and at least two methods pass the ensemble_r2_threshold (default 0.01), an additional ensemble_weights method is added by stacked regression over CV predictions. The default solver is quadprog; alternatives are nnls, lbfgsb, and glmnet (set ensemble_solver). The ensemble row is named ensemble_weights in the returned TWASWeights object.

Sample partitioning

twas_weights_cv() partitions samples randomly into cv_folds. To control the partition (e.g. to keep related samples in the same fold), pass a data.frame with Sample and Fold columns to sample_partition:

sample_partition <- data.frame(
  Sample = rownames(X),
  Fold   = sample(rep(1:5, length.out = nrow(X)))
)
fit <- univariate_analysis_pipeline(
  X = X, Y = y, maf = maf,
  twas_weights = TRUE,
  cv_folds = 5, sample_partition = sample_partition,
  verbose = 0
)

Imputability selection

Downstream TWAS-Z inference (twas_pipeline() and twas_analysis()) treats a gene as imputable when at least one method passes rsq_cutoff (default 0.01) with pval < rsq_pval_cutoff (default 0.05). For each imputable gene the best-performing method’s weights are used. See the TWAS Z-score vignette for the inference layer.

Multi-context weights

For multi-tissue/multi-context QTL data, fit the multivariate analysis first (multivariate_analysis_pipeline() returns the mr.mash and mvSuSiE fits), then pass them through twas_multivariate_weights_pipeline():

# TODO(data): replace with real multi-tissue eQTL X and Y matrices and
# data-driven prior matrices computed via your usual workflow.

X_mt <- "<numeric matrix samples x variants>"
Y_mt <- "<numeric matrix samples x contexts>"
prior_matrices <- "<list of data-driven prior matrices>"

# (Step 1) Fit mr.mash and mvSuSiE
mnm_fit <- multivariate_analysis_pipeline(
  X = X_mt, Y = Y_mt,
  data_driven_prior_matrices = prior_matrices
)

# (Step 2) Extract TWAS weights per condition
mt_weights <- twas_multivariate_weights_pipeline(
  X = X_mt, Y = Y_mt, mnm_fit = mnm_fit,
  cv_folds = 5
)
# Returns a list indexed by context name; each element has its own
# twas_weights and twas_cv_result.

mnm_fit provides the fitted multivariate models; twas_multivariate_weights_pipeline() extracts the per-context weights that match the contract harmonize_twas() expects.

Summary-statistics weights

When you have QTL summary statistics instead of individual-level data, use twas_weights_sumstat_pipeline(). It replaces the standalone OTTERS pipeline with an integrated workflow: RSS QC → (optional) RAISS missing-variant imputation → multi-method weight training.

Default methods

Out of the box the pipeline trains five methods on each region:

Method Origin Defaults
lassosum-RSS Mak et al. 2017 grid over s = c(0.2, 0.5, 0.9, 1.0), lambda
PRS-CS Ge et al. 2019 phi = 1e-4, n_iter = 1000, burnin 500, thin 5
SDPR Zhou et al. 2023 iter = 1000, burn = 200, thin 1
SuSiE-RSS Wang et al. 2020 normal IBSS
SuSiE-inf-RSS Cui et al. 2024 unmappable_effects = "inf", refine = FALSE

The SuSiE-RSS and SuSiE-inf-RSS methods share a single two-stage fit (SuSiE-inf-RSS initialises SuSiE-RSS), so adding both costs little beyond fitting either alone. See the fine-mapping vignette for the SuSiE-family comparison.

P+T (pruning and thresholding) weights are also produced for any p_thresholds you pass (default c(0.001, 0.05)); set p_thresholds = NULL to skip P+T.

All available SS-TWAS methods

In addition to the five defaults above, the following are available through the methods argument:

Method short name Function Family / origin
lassosum_rss lassosum_rss_weights() L1-penalized regression on summary stats (Mak et al. 2017)
prs_cs prs_cs_weights() Continuous shrinkage Bayesian prior (Ge et al. 2019)
sdpr sdpr_weights() Dirichlet process mixture (Zhou et al. 2023)
susie_rss susie_rss_weights() SuSiE-RSS, sparse single effects
susie_inf_rss susie_inf_rss_weights() SuSiE with infinitesimal background (unmappable_effects = "inf")
susie_ash_rss susie_ash_rss_weights() SuSiE with adaptive shrinkage mixture (unmappable_effects = "ash")
mr_ash_rss mr_ash_rss_weights() mr.ash adaptive shrinkage on summary stats
mcp_rss mcp_rss_weights() Minimax concave penalty on summary stats
scad_rss scad_rss_weights() Smoothly clipped absolute deviation penalty
l0learn_rss l0learn_rss_weights() L0Learn best-subset selection on summary stats
P+T (built-in) n/a Marginal-effect thresholding at user-supplied p_thresholds

All *_rss_weights functions follow the same contract <method>_weights(stat, LD, ...): the pipeline computes stat = list(b = z / sqrt(n), cor = z / sqrt(n), z = z, n = rep(n, p)) from the QC’d sumstats and passes the QC’d LD_mat to each method. Any function following that convention can be dropped into methods without code changes — including user-supplied custom methods, as long as the function returns a per-variant numeric weight vector.

Quick start

# TODO(data): replace with real QTL sumstats and LD reference paths
qtl_sumstat_path <- "<path/to/qtl_nominal.tsv.gz>"
qtl_column_map   <- "<path/to/qtl_column_map.yml>"
ld_meta_path     <- "<path/to/ld_meta.tsv>"
region           <- "<chr:start-end>"
gene_id          <- "<ENSG...>"

rss_input <- load_rss_data(
  sumstat_path = qtl_sumstat_path,
  column_file_path = qtl_column_map,
  region = region, extract_region_name = gene_id, region_name_col = 4L
)
ld_data <- load_LD_matrix(ld_meta_path, region = region)

ss_weights <- twas_weights_sumstat_pipeline(
  sumstats = rss_input$sumstats,
  LD_data  = ld_data,
  n        = rss_input$n,
  qc_method = "slalom",       # SLALOM/DENTIST QC; see rss-qc.html
  impute    = TRUE,           # re-impute QC outliers via RAISS
  impute_missing = FALSE      # see next section for missing-variant imputation
)
str(ss_weights, max.level = 2)

Customising methods

To swap in a different method set, pass a methods named list. Method names must end in _weights and refer to a function with the contract <method>_weights(stat, LD, ...):

ss_weights <- twas_weights_sumstat_pipeline(
  sumstats = rss_input$sumstats, LD_data = ld_data, n = rss_input$n,
  methods = list(
    lassosum_rss     = list(),
    susie_rss        = list(),
    mr_ash_rss       = list(           # add mr.ash.rss
      var_y = 1, sigma2_e = 0.5,
      s0 = c(0, 0.001, 0.01, 0.1, 0.5),
      w0 = rep(0.2, 5)
    )
  ),
  p_thresholds = c(0.05)
)

Runnable demo on shipped data

For demonstration we feed the shipped GWAS-style sumstats and the matching genotype reference into the pipeline (a real workflow would use QTL sumstats and a separate LD panel).

data(gwas_sumstats_example)
data(eqtl_region_example)

# Build an LDData object from the shipped genotype panel (in real
# workflows this comes from load_LD_matrix())
X_ref <- eqtl_region_example$X
R <- compute_LD(X_ref, method = "sample")
ref_panel <- parse_variant_id(colnames(X_ref))
ref_panel$variant_id <- colnames(X_ref)
variants_gr <- GenomicRanges::GRanges(
  seqnames = ref_panel$chrom,
  ranges = IRanges::IRanges(start = ref_panel$pos, width = 1L)
)
S4Vectors::mcols(variants_gr) <- S4Vectors::DataFrame(
  variant_id = ref_panel$variant_id, A1 = ref_panel$A1, A2 = ref_panel$A2
)
block_meta <- data.frame(
  block_id = 1L, chrom = ref_panel$chrom[1],
  block_start = min(ref_panel$pos), block_end = max(ref_panel$pos),
  size = ncol(X_ref), start_idx = 1L, end_idx = ncol(X_ref)
)
ld_data <- LDData(correlation = R, variants = variants_gr,
                  block_metadata = block_meta, n_ref = nrow(X_ref))

ss_weights <- twas_weights_sumstat_pipeline(
  sumstats = gwas_sumstats_example,
  LD_data  = ld_data,
  n        = nrow(X_ref),
  methods  = list(susie_rss = list(max_iter = 50)),
  p_thresholds = c(0.05),
  check_ld_method = NULL,
  verbose  = 0
)
getMethodNames(ss_weights$twas_weights)
length(getVariantIds(ss_weights$twas_weights))

Multi-context summary-statistics weights

When you have per-context QTL sumstats (one set per tissue / cell type) but no individual-level data, use twas_multivariate_weights_sumstat_pipeline(). It mirrors twas_multivariate_weights_pipeline() (individual-level) but works from sumstats:

  1. Run per-context QC (summary_stats_qc() with optional SLALOM / DENTIST + RAISS re-imputation).
  2. Optionally RAISS-impute per-context z-scores for LD-reference variants missing from a context.
  3. Align variants across contexts and LD by intersecting on variant_id (this is where the alignment happens — passed sumstats need only be per-context QC’d; cross-context alignment is automatic).
  4. Build the variants × conditions Bhat, Shat, and Z matrices.
  5. Estimate data-driven prior matrices from the cross-context Bhat using compute_cov_flash() (with compute_cov_diag() as fallback) — the same prior-construction helpers used by the individual-level mrmash_wrapper() via the shared build_mrmash_prior_matrices().
  6. Fit the requested methods (mr.mash-RSS, mvSuSiE-RSS) on the aligned matrices.

Default methods

The pipeline trains two methods by default:

Method Function Underlying call
mr.mash-RSS mrmash_rss_weights() mr.mashr::mr.mash.rss(), sharing prior construction with mrmash_wrapper()
mvSuSiE-RSS mvsusie_rss_weights() mvsusieR::mvsusie_rss(), with create_mixture_prior() default

Both follow the same <method>_weights(stat, LD, ...) contract as the univariate RSS methods, with stat$z a variants × conditions matrix and stat$n per-context.

Quick start

# TODO(data): replace with real per-context QTL paths
qtl_paths   <- list(
  brain  = "<path/to/brain_qtl.tsv.gz>",
  blood  = "<path/to/blood_qtl.tsv.gz>",
  muscle = "<path/to/muscle_qtl.tsv.gz>"
)
column_map  <- "<path/to/qtl_column_map.yml>"   # shared schema, one file
ld_meta     <- "<path/to/ld_meta.tsv>"
region      <- "<chr:start-end>"
gene_id     <- "<ENSG...>"
n_per_ctx   <- c(brain = 1200, blood = 900, muscle = 500)

# 1. Load per-context sumstats (each tabix-extracted on the same region)
sumstats_list <- lapply(qtl_paths, function(p) {
  rss <- load_rss_data(
    sumstat_path = p, column_file_path = column_map,
    region = region, extract_region_name = gene_id, region_name_col = 4L
  )
  rss$sumstats
})

# 2. Load a shared LD reference for the region
ld_data <- load_LD_matrix(ld_meta, region = region)

# 3. Fit both multivariate RSS methods
mt_ss <- twas_multivariate_weights_sumstat_pipeline(
  sumstats_list = sumstats_list,
  LD_data       = ld_data,
  n             = n_per_ctx,
  methods       = list(
    mrmash_rss  = list(max_iter = 200, verbose = FALSE),
    mvsusie_rss = list(L = 10)
  ),
  qc_method      = "slalom",
  impute         = TRUE,    # QC re-imputation of LD-mismatch outliers
  impute_missing = TRUE     # RAISS imputation of LD variants absent per context
)

# `mt_ss$twas_weights` is a TWASWeights S4 object whose weight matrices are
# (variants x conditions). `mt_ss$qc_summary` reports per-context survivor
# counts and the cross-context intersection size.
str(mt_ss$qc_summary)

Data-driven prior construction

By default, the pipeline estimates the mr.mash data-driven covariance component from the aligned Bhat matrix via compute_cov_flash(Bhat) — the same FLASH-based covariance estimator the individual-level mrmash_wrapper() uses. If FLASH fails (e.g. with sparse contexts), it falls back to compute_cov_diag(Bhat). Pass data_driven_prior_matrices = list(U = ...) to supply your own precomputed components, or canonical_prior_matrices = FALSE to disable the canonical mixture.

Manual prior construction

If you have already built priors elsewhere (e.g. via a separate FLASH or PCA pass on a training set of effect-size estimates), pass them directly:

# Precomputed prior covariance matrices from a training run
prior_U <- list(
  flash_factor_1 = matrix(...),   # K x K
  flash_factor_2 = matrix(...),
  identity       = diag(K)
)

mt_ss <- twas_multivariate_weights_sumstat_pipeline(
  sumstats_list = sumstats_list, LD_data = ld_data, n = n_per_ctx,
  data_driven_prior_matrices    = list(U = prior_U),
  canonical_prior_matrices      = TRUE,
  estimate_priors_from_sumstats = FALSE,  # bypass the in-pipeline FLASH
  methods = list(mrmash_rss = list())
)

Where alignment happens

Cross-context alignment is inside the pipeline at step 3, after per-context QC. Each input sumstats_list[[k]] may have a different variant set; the pipeline runs summary_stats_qc() per context, then intersects survivors across contexts and the LD reference to define the common variant axis used downstream. To widen the intersection, enable impute_missing = TRUE: per-context RAISS imputes z-scores for LD variants missing from that context’s sumstats before the intersection.

Missing-variant imputation for SS-TWAS

When the QTL sumstats panel is narrower than the LD reference — common for nominal eQTL output that filters on per-cohort imputation quality — weight learners only see variants present in both. Setting impute_missing = TRUE calls RAISS to impute z-scores for LD-reference variants absent from the QTL sumstats before the weight learners fit, so they see a fuller variant set:

ss_weights_wide <- twas_weights_sumstat_pipeline(
  sumstats = rss_input$sumstats,
  LD_data  = ld_data,
  n        = rss_input$n,
  methods  = list(susie_rss = list(), lassosum_rss = list()),
  qc_method = "slalom",
  impute = TRUE,                                # QC re-imputation (existing)
  impute_missing = TRUE,                        # missing-variant imputation (new)
  impute_opts = list(rcond = 0.01, R2_threshold = 0.6,
                     minimum_ld = 5, lamb = 0.01)
)

impute_missing is independent of impute (the QC re-imputation option). RAISS imputes summary statistics only — never the weights themselves. Imputed variants with R² < R2_threshold are dropped by RAISS’s internal filter. See the RSS QC vignette for the RAISS internals and the TWAS Z-score vignette for the parallel impute_missing option that fills GWAS variants missing from the LD sketch at TWAS Z-score inference.

Summary

Function Use it when
univariate_analysis_pipeline(twas_weights = TRUE) Individual-level, single context. Fine-mapping + weight learning in one call.
twas_weights_pipeline() Lower-level individual-level entry. Same internals but takes pre-fitted SuSiE models.
twas_weights_cv() Standalone k-fold CV for any subset of methods.
twas_multivariate_weights_pipeline() Multi-context individual-level. Wraps mr.mash and mvSuSiE fits.
twas_weights_sumstat_pipeline() Single-context sumstats. Replaces standalone OTTERS. Defaults to lassosum-RSS, PRS-CS, SDPR, SuSiE-RSS, SuSiE-inf-RSS.
twas_multivariate_weights_sumstat_pipeline() Multi-context sumstats. Per-context QC + cross-context alignment + mr.mash-RSS / mvSuSiE-RSS.
ensemble_weights() Stack two or more methods via stacked regression. Called automatically by twas_weights_pipeline() when ensemble = TRUE.
build_mrmash_prior_matrices() Shared prior-matrix builder used by both mrmash_wrapper() (individual-level) and mrmash_rss_weights() (sumstats).

All five return a TWASWeights S4 object. The TWAS Z-score vignette shows how to apply these weights to GWAS summary statistics to compute per-gene TWAS Z-scores.

## R version 4.5.3 (2026-03-11)
## Platform: x86_64-conda-linux-gnu
## Running under: Ubuntu 24.04.4 LTS
## 
## Matrix products: default
## BLAS/LAPACK: /home/runner/work/pecotmr/pecotmr/.pixi/envs/default/lib/libopenblasp-r0.3.33.so;  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
##  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
##  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
## [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
## 
## time zone: Etc/UTC
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] pecotmr_0.5.3
## 
## loaded via a namespace (and not attached):
##   [1] RColorBrewer_1.1-3          jsonlite_2.0.0             
##   [3] shape_1.4.6.1               magrittr_2.0.5             
##   [5] GenomicFeatures_1.62.0      farver_2.1.2               
##   [7] rmarkdown_2.31              MCMCpack_1.7-1             
##   [9] fs_2.1.0                    BiocIO_1.20.0              
##  [11] ragg_1.5.2                  vctrs_0.7.3                
##  [13] memoise_2.0.1               Rsamtools_2.26.0           
##  [15] RCurl_1.98-1.19             mixsqp_0.3-54              
##  [17] htmltools_0.5.9             S4Arrays_1.10.1            
##  [19] curl_7.1.0                  tictoc_1.2.1               
##  [21] SparseArray_1.10.8          sass_0.4.10                
##  [23] bslib_0.11.0                htmlwidgets_1.6.4          
##  [25] desc_1.4.3                  plyr_1.8.9                 
##  [27] cachem_1.1.0                ieugwasr_1.1.0             
##  [29] GenomicAlignments_1.46.0    lifecycle_1.0.5            
##  [31] iterators_1.0.14            pkgconfig_2.0.3            
##  [33] Matrix_1.7-5                R6_2.6.1                   
##  [35] fastmap_1.2.0               MatrixGenerics_1.22.0      
##  [37] digest_0.6.39               reshape_0.8.10             
##  [39] AnnotationDbi_1.72.0        S4Vectors_0.48.0           
##  [41] irlba_2.3.7                 textshaping_1.0.5          
##  [43] GenomicRanges_1.62.1        RSQLite_3.53.1             
##  [45] ncvreg_3.16.0               httr_1.4.8                 
##  [47] abind_1.4-8                 compiler_4.5.3             
##  [49] bit64_4.8.2                 S7_0.2.2                   
##  [51] BiocParallel_1.44.0         viridis_0.6.5              
##  [53] DBI_1.3.0                   R.utils_2.13.0             
##  [55] quantreg_6.1                MASS_7.3-65                
##  [57] DelayedArray_0.36.0         corpcor_1.6.10             
##  [59] rjson_0.2.23                tools_4.5.3                
##  [61] otel_0.2.0                  R.oo_1.27.1                
##  [63] glue_1.8.1                  quadprog_1.5-8             
##  [65] restfulr_0.0.16             grid_4.5.3                 
##  [67] reshape2_1.4.5              generics_0.1.4             
##  [69] gtable_0.3.6                BSgenome_1.78.0            
##  [71] tzdb_0.5.0                  susieR_0.16.4              
##  [73] R.methodsS3_1.8.2           tidyr_1.3.2                
##  [75] data.table_1.17.8           hms_1.1.4                  
##  [77] XVector_0.50.0              colocboost_1.0.9           
##  [79] BiocGenerics_0.56.0         foreach_1.5.2              
##  [81] pillar_1.11.1               stringr_1.6.0              
##  [83] vroom_1.7.1                 splines_4.5.3              
##  [85] dplyr_1.2.1                 lattice_0.22-9             
##  [87] survival_3.8-6              rtracklayer_1.70.1         
##  [89] bit_4.6.0                   SparseM_1.84-2             
##  [91] MungeSumstats_1.18.1        tidyselect_1.2.1           
##  [93] Biostrings_2.78.0           coloc_5.2.3                
##  [95] knitr_1.51                  gridExtra_2.3              
##  [97] IRanges_2.44.0              Seqinfo_1.0.0              
##  [99] SummarizedExperiment_1.40.0 mcmc_0.9-8                 
## [101] stats4_4.5.3                xfun_0.57                  
## [103] Biobase_2.70.0              statmod_1.5.2              
## [105] matrixStats_1.5.0           L0Learn_2.1.0              
## [107] stringi_1.8.7               UCSC.utils_1.6.1           
## [109] yaml_2.3.12                 evaluate_1.0.5             
## [111] codetools_0.2-20            cigarillo_1.0.0            
## [113] tibble_3.3.1                cli_3.6.6                  
## [115] RcppParallel_5.1.11-2       systemfonts_1.3.2          
## [117] jquerylib_0.1.4             Rcpp_1.1.1-1.1             
## [119] GenomeInfoDb_1.46.2         zigg_0.0.2                 
## [121] coda_0.19-4.1               png_0.1-9                  
## [123] XML_3.99-0.22               parallel_4.5.3             
## [125] Rfast_2.1.5.2               MatrixModels_0.5-4         
## [127] pkgdown_2.2.0               ggplot2_4.0.3              
## [129] readr_2.2.0                 blob_1.3.0                 
## [131] bitops_1.0-9                glmnet_5.0                 
## [133] qgg_1.1.6                   viridisLite_0.4.3          
## [135] VariantAnnotation_1.56.0    scales_1.4.0               
## [137] purrr_1.2.2                 crayon_1.5.3               
## [139] rlang_1.2.0                 KEGGREST_1.50.0