Learning TWAS Weights from Individual-Level Data and Summary Statistics
pecotmr authors
2026-06-11
Source:vignettes/twas-weights.Rmd
twas-weights.RmdOverview
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:
- Run per-context QC (
summary_stats_qc()with optional SLALOM / DENTIST + RAISS re-imputation). - Optionally RAISS-impute per-context z-scores for LD-reference variants missing from a context.
-
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). - Build the
variants × conditionsBhat,Shat, andZmatrices. - Estimate data-driven prior matrices from the cross-context
Bhatusingcompute_cov_flash()(withcompute_cov_diag()as fallback) — the same prior-construction helpers used by the individual-levelmrmash_wrapper()via the sharedbuild_mrmash_prior_matrices(). - 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