Skip to content

Bayesian Gaussian Graphical Models

1packages depend
54.2Kdownloads / year
–test coverage
13/13flavors OK

Overview

About

Fit Bayesian Gaussian graphical models. The methods are separated into two Bayesian approaches for inference: hypothesis testing and estimation. There are extensions for confirmatory hypothesis testing, comparing Gaussian graphical models, and node wise predictability. These methods were recently introduced in the Gaussian graphical model literature, including Williams (2019) doi:10.31234/osf.io/x8dpr, Williams and Mulder (2019) doi:10.31234/osf.io/ypxd8, Williams, Rast, Pericchi, and Mulder (2019) doi:10.31234/osf.io/yt386.

Changes in 2.2.0

New features

  • **select.explore() gains a method = "BMA" option**: Bayesian model averaging as an alternative to the hard Bayes factor threshold (method = "BF_cut"). For each edge the posterior is a spike-and-slab mixture with mass P(H0 | Y) at zero and the posterior under the alternative otherwise; the reported network weights (pcor_mat_zero) are the **median of this mixture**, computed **exactly** under a normal approximation of the posterior of the Fisher-z partial correlation (truncated at 0 for one-sided hypotheses). The result is therefore deterministic and does not require stored posterior draws. The new prior.prob.H0 argument (default 0.5) sets the prior probability of the null. All alternatives are supported. For alternative = "exhaustive" the mixture has three states -- a spike at zero (H0), a positive slab (H+), and a negative slab (H-) -- mixed by the posterior hypothesis probabilities; pos_mat/neg_mat/null_mat then classify each edge by the sign of the model-averaged median (so an edge is null when the median is 0, which can happen even when H0 is not the most probable hypothesis). Thanks to Joris Mulder for the suggestion.
Show all changes in 2.2.0Hide the rest of the changes in 2.2.0
  • **select.explore() returns edge inclusion probabilities (incl_prob)**: a matrix of posterior edge inclusion probabilities q * BF / (q * BF + 1 - q) with prior inclusion probability q = 1 - prior.prob.H0 (BF_10 for "two.sided", BF_20 for "greater"/"less", and 1 - P(H0 | Y) for "exhaustive").
  • **prior.prob.H0 now affects the selected graph under method = "BF_cut"**, not only under method = "BMA". An edge is selected when its posterior inclusion probability exceeds BF_cut / (BF_cut + 1), and is called null when the posterior probability of the null hypothesis exceeds that cutoff. With the default prior.prob.H0 = 0.5 this is identical to the previous Bayes factor rule (BF > BF_cut) for "two.sided", "greater" and "less". For alternative = "exhaustive" the null keeps prior.prob.H0 and the two directional hypotheses split the remainder equally (0.5 / 0.25 / 0.25 by default); because BF_1u + BF_2u = 2 the inclusion probability then equals the one of "two.sided", so both alternatives select the same edges, with "exhaustive" labelling each selected edge positive or negative by the larger of the two directional probabilities. alternative = "exhaustive" with method = "BF_cut" now also returns pcor_mat_zero. Previously "exhaustive" used fixed equal 1/3 priors and thresholded each hypothesis separately, which made BF_cut = 3 correspond to a two-sided Bayes factor of 1.5.
  • **truncnorm added to Imports**: required for the truncated-normal draws used in the one-sided BMA alternatives.
  • **explore() no longer samples the prior by default**: the Bayes factors only need the prior sd of the Fisher-z partial correlations, which is now computed analytically (numerical integration of the marginal prior rho ~ 2 * Beta(delta/2, delta/2) - 1, independent of p) and stored as prior_sd_z. Draws from the joint prior (prior_samp) are returned only with the new argument store_prior_draws = TRUE (default FALSE), which halves time and memory use for large networks by default. select.explore(), ggm_compare_explore() and bggm_missing() use prior_sd_z; older explore objects still work in select(). Bayes factors change slightly, because the previously sampled prior sd was affected by the matrix-F approximation (e.g. about 0.69-0.70 instead of 0.684 for prior_sd = 0.5).
  • **explore() gains store_post_draws (default TRUE)**: all samplers used by explore() now keep running posterior summaries of the partial correlations (post_samp$pcor_mat, pcor_sd, z_mean, z_sd). With store_post_draws = FALSE the p x p x iter arrays post_samp$pcors and post_samp$fisher_z are not stored, so memory use no longer grows with the number of iterations. select() (all methods and alternatives) and summary() work from these summaries when the draws are not stored; functions that need the draws (posterior_samples(), convergence(), coef(), pcor_to_cor(), predict(), predictability(), posterior_predict(), constrained_posterior()) stop with an informative error, and bggm_missing() always stores the draws.
  • **explore() gains burnin (default 50) and thin (default 1)**: after burnin iterations, iter post-burn-in iterations are run and every thin-th draw is stored; the running posterior summaries use all post-burn-in iterations. explore() objects no longer store the burn-in draws: post_samp$pcors, fisher_z, beta and thresh now contain only the kept draws (previously iter + 50, including 50 burn-in draws). Downstream functions locate the post-burn-in draws with an internal helper, so objects created with earlier versions keep working. Objects from estimate(), confirm() and the other functions are unchanged.

Bug fixes

  • **explore(iter = ) is now the number of post-burn-in ITERATIONS**, not the number of draws kept after thinning. Previously explore(iter = i, thin = t) ran burnin + i * t iterations and stored i draws, so raising thin silently multiplied the run time by t; it now runs burnin + i iterations and stores ceiling(i / thin) of them, returned in the new n_draws element. iter in the fitted object is the iteration count and n_draws the stored-draw count. With the default thin = 1 nothing changes.
  • **seed = NULL no longer re-seeds the RNG**: explore(), confirm(), ggm_compare_confirm(), ggm_search() and var_estimate() called set.seed(seed) unconditionally before the guarded if (!is.null(seed)) set.seed(seed). With the default seed = NULL the first call was set.seed(NULL), which re-initialises the RNG from the current time and process ID, discarding any seed the user had set and making repeated calls on the same data irreproducible even inside set.seed(). The unguarded call has been removed, so with seed = NULL these functions now use the ambient RNG stream and are reproducible under set.seed(), as estimate() already was. Results of existing scripts that relied on the implicit re-seeding will change.
  • **Corrected the exhaustive posterior hypothesis probabilities**: for alternative = "exhaustive", the positive/negative Bayes factors were referenced to the null model H0 instead of the unrestricted model Hu, so each carried an extra factor of the two-sided Bayes factor and double-counted the two-sided evidence. All three Bayes factors are now referenced to Hu per Eq. 9 of Williams & Mulder (2019). Affects post_prob and the derived null_mat/pos_mat/neg_mat under both method = "BF_cut" and method = "BMA".
  • **Corrected the prior sd in the "greater", "less" and "exhaustive" selection branches of select.explore()**: the "greater" branch averaged a hardcoded 3x3 prior mask (upper.tri(diag(3))), giving wrong Bayes factors whenever the number of variables was not 3, and the "less"/"exhaustive" branches averaged the (near-zero) matrix diagonal into the prior standard deviation. All branches now use the off-diagonal (edge) prior sd, matching the "two.sided" branch.
  • **Fixed a crash in summary() for select.explore() with alternative = "less"**: the "less" summary branch produced an empty Relation column (mat_names[upper.tri(mat_names)] on an already-flattened vector), causing a "differing number of rows" error. The greater/less summaries now share one correct branch.
  • **select.explore() now uses all post-burn-in draws** for the posterior mean/sd (previously the last 50 stored draws were dropped), and no longer returns NA on the diagonal of the exhaustive null_mat/pos_mat/neg_mat (where the posterior sd is 0).
  • **Fixed bggm_missing() dropping the wrong column with mice >= 3.17.0** (#2): bggm_missing() removed the .id column from mice::complete(action = "long") by position (column 2), which was correct only before mice 3.17.0. Since mice 3.17.0 places .imp/.id in the last two columns, this stripped a real data column and let .id leak into the model, corrupting the data passed to estimate()/ explore(). The column is now removed by name, which is robust to mice's column order. Reported by \@LilyTeesson.
  • **bggm_missing() now pools the posterior draws of the imputed data sets correctly**: it stacked all draws of each fit, including their 50 burn-in draws, and set iter to iter * m + 50, so the methods that use draws 51:(iter + 50) included the burn-in draws of imputations 2 to m and indexed beyond the stored draws; summaries came from the first imputation only. The pooled object now contains the 50 burn-in draws of the first fit followed by the post-burn-in draws of all fits, with iter = iter * m. beta and thresh are pooled whenever present, and pcor_mat (and, for explore, the posterior summaries) are recomputed from the pooled draws. Also works for m = 1.
  • **explore() for large or n < p networks**: the starting value is regularized (solve(cov(Y) + 0.1 I)), and the matrix-F prior now uses epsilon = min(0.01, 1 / (10 p)) instead of a fixed 0.01, so that nu = 1 / epsilon stays well above p - 1 (required for a proper prior, Williams & Mulder, 2020). Results change slightly for p > 10.
  • **C++ samplers no longer truncate the matrix-F degrees of freedom** to integers (non-integer delta from prior_sd).
  • **Fixed rref_ei not found error**: Added simple_rref() function in helpers.R to replace commented-out pracma::rref() call. This fixes a crash in create_matrices() when validating constraint matrices for hypothesis testing with multiple groups.
  • **Fixed ggm_search() crash**: The C++ search function now handles edge cases where the adjacency matrix becomes all zeros or all ones, preventing "sample more elements than in x" errors.
  • **Fixed qplot() deprecation warning**: Replaced deprecated qplot() with ggplot() + geom_density() in plot_prior().
  • **Fixed ggm_search() proposal-set shadowing bug and BIC creep**: The C++ search() function had a variable-shadowing bug where zeros and nonzeros (pools of candidate edges) were re-declared instead of re-assigned after accepting a move, freezing them at the starting graph's configuration for the entire run. This caused systematic BIC drift under probabilistic acceptance and made reversing bad moves impossible. ggm_search() now implements a proper Metropolis-Hastings sampler with a birth-death Hastings correction as the default (probabilistic = TRUE); the greedy deterministic hill-climb is still available via probabilistic = FALSE. The burn_in parameter is restored and now actually applied to discard pre-burn-in samples before computing the Bayesian Model Averaging (BMA) solution (probabilistic search only). Note: the greedy hill-climb was found to be nearly non-functional on realistic test cases, typically accepting only a single edge flip out of thousands of attempts.

Performance

  • **Removed unused posterior arrays from the C++ samplers used by explore()** (also used by estimate(), confirm() and the ggm_compare_*() functions) and by var_estimate(): Theta_mcmc, cors_mcmc and Sigma_mcmc (each p x p x iter) were allocated but never filled or returned in Theta_continuous, sample_prior, mv_continuous, mv_binary, mv_ordinal_albert, copula and var; copula also allocated an unused n x p x iter array of latent data. This reduces memory use substantially for large networks (e.g. mv_continuous, used with formula, allocated five p x p x iter arrays and now two).
  • **missing_copula (mixed data with impute = TRUE) no longer returns post_samp$Y_collect**: this n x p x iter array was never filled (all zeros) and was not used anywhere in BGGM.

Maintenance

  • Added rlang to Imports for proper use of .data pronoun in ggplot2 aesthetics.
  • Added unit tests for multiple functions.
  • **Refactored bggm_fast.cpp for clarity and efficiency**: Removed two functions unreachable from R (mv_ordinal_cowles, trunc_mvn; ~390 lines). Extracted cov_to_cor() and conditional_normal_params() helper functions, eliminating 17 duplicated blocks and a matrix inversion that was being computed twice per variable per MCMC iteration across 9 sampler functions. Removed dead commented-out debug code. No behavior change; file reduced from 3199 to ~2850 lines.
  • **Fixed the ggm_search() test suite and added regression tests**: Corrected tests that were silently exercising non-existent parameters (bma = TRUE instead of bma_mean, a start = argument that doesn't exist, gamma = instead of prior_prob, prior_sd = which isn't a parameter at all) and a plot.ggm_search() test that could never fail since no such method exists. Rewrote with correct parameter names and assertions on the returned object's fields, and added regression tests tied directly to the bugs above (probabilistic search must accept a healthy fraction of proposals; bma_posterior() must not error on the new default's output). Added tests/testthat/test-search_cpp.R exercising the C++ search()/bic_fast()/hft_algorithm() functions directly, including a check for systematic BIC drift across a long run.

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 10.3 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OK2026-08-05
  • NOTE12 OK, 1 NOTE2026-08-01
  • OK13 OK2026-07-29
  • ERROR12 OK, 1 ERROR2026-07-27
  • OK13 OK2026-06-09
Show 9 earlier changesHide 9 earlier changes
  • ERROR12 OK, 1 ERROR2026-06-08
  • OK12 OK2026-04-25
  • NOTE11 OK, 3 NOTE2026-04-22
  • ERROR10 OK, 3 NOTE, 1 ERROR2026-04-18
  • NOTE11 OK, 3 NOTE2026-04-10
  • ERROR10 OK, 3 NOTE, 1 ERROR2026-04-09
  • NOTE11 OK, 3 NOTE2026-04-08
  • ERROR10 OK, 3 NOTE, 1 ERROR2026-04-07
  • NOTE11 OK, 3 NOTE2026-03-10
Advisories

none known

Documentation

In release 2.2.0
README· In the repository, left out of the releaseVignettesYes · 10 · dynamicNEWSYes · 100% structured · mentions 2.2.0Citation fileYes · cites a publicationWebsiteYes · pkgdown
Help pages
84 (1 internal)includes a package overview page
Examples that run
28%21 run in a plain check · 54 only when donttest examples are enabled (R CMD check --as-cran)
Exported functions with examples
97%
Documented parameters
100%
Return-value docs
100%
Help pages citing references
39% with a bibliography file

Downloads

54.2K
CRAN downloads in the past year
Rank #3,719 · ~148/day · ~4.5K/mo
Daily download trend is not available in this view yet.
1.1K30 days
2.6K90 days
54.2K1 year
Compare downloads with other packages →
Also on587 r2u62 autocran151 c2d4u

Repository

4Stars
2Forks
1Open issues
0Open PRs
0Releases
1,212Commits
6Commit identities
License file reads as GPL-2.0 · 1,212 commits · Last activity 2026-09-24 · 0% stars, 30d
Responsiveness
How these are sampled
PRs merged (all time)
100%
Median days to close, 50 most recently updated closed issues
22
Median days to close, 50 most recently updated closed PRs
0

Stars over time

2026-03-26 · 12026-08-23 · 4
PracticesBeta

12 development-tooling and community-health practices detected across 8 families in the upstream repository

Checks run against github.com/rast-lab/bggm on 2026-10-11.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows

Docs source (4)
README.Rmdpkgdown

GitHub Pages site last deployed 2026-09-24 · The repository has a site deploy workflow

pkgdown site last built 2026-09-24

Coverage (1)
Coverage reporting
Reproducibility and dev environment (1)
data-raw/
Show all practicesHide 4 practices
CRAN release process (1)
cran-comments.md
Research and citation (1)
JOSS paper
Lint, format, editor (1)
RStudio project
Git structural (1)
.gitattributes
How this is detected·Detection ruleset v3 (2026-09-26)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • Claude Codefirst seen 2026-01-15
    Seen in the repository: .claude, .claude/agents
    Named in .Rbuildignore: .claude
    Commits: at least 33 crediting it in the message
Models named in its commits
  • Claude Opus 519 commits · Sep 2026
  • Claude Sonnet 512 commits · Jul 2026
  • Claude Opus 4.51 commit · Jan 2026
  • Claude Opus 4.81 commit · Sep 2026
Counts are commits, not lines of code. Commits by a tool's accounts count once across all of its accounts. Commits crediting it are the largest count among its credit lines, a minimum.How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
24 external dependencies (excludes base and recommended)

Installing BGGM adds 123 packages (64 with compiled code, 99 MB of source tarballs). Heaviest: BH 14 MB, stringi 11 MB, ggplot2 6.0 MB.

Depends (1)
R >= 4.0.0
Enhances (0)
none
Reverse dependencies
1direct
0indirect
Imports 1
Depends, Imports or LinkingTo, most downloaded first

Datasets

People & History

People (3)
Author, Maintainer since 2.1.1 (2024) · added in 2.1.1

Previously maintained by Donald Williams (1.0.0 to 2.0.4).

Releases (13)

Pick two releases to compare their code metrics.

  • 2.2.0Latest
    record
    2026-09-24 · current release · diff ↗
  • R
    R 4.6.0 released · 2026-04-24
  • 2.1.6
    record
    2025-12-02 · diff ↗
  • R
    R 4.5.0 released · 2025-04-11
  • 2.1.5
    record
    2024-12-22 · diff ↗
  • 2.1.4
    record
    2024-12-13 · diff ↗
  • 2.1.3
    record
    2024-07-05 · diff ↗
  • 2.1.2
    record
    2024-06-22 · diff ↗
  • R
    R 4.4.0 released · 2024-04-24
  • unarchivedReturned to CRAN
    2024-02-23
  • 2.1.1
    record
    2024-02-23 · diff ↗ ·
    added 3 exports
    gen_net, prior_belief_ggm, prior_belief_var
  • archivedRemoved from CRAN
    2023-10-13
    requires archived package 'BFpack'
  • R
    R 4.3.0 released · 2023-04-21
  • R
    R 4.2.0 released · 2022-04-22
  • unarchivedReturned to CRAN
    2021-08-20
  • 2.0.4
    record
    2021-08-20 · diff ↗ ·
    removed 3 exports
    bma_posterior, ggm_search, mvn_imputation
    added 3 exports
    impute_data, posterior_predict, predicted_probability
Show 9 earlier eventsHide 9 earlier events
  • archivedRemoved from CRAN
    2021-07-06
    check issues were not corrected in time donttest check
  • R
    R 4.1.0 released · 2021-05-18
  • 2.0.3
    record
    2020-12-03 · diff ↗ ·
    added 4 exports
    bma_posterior, constrained_posterior, ggm_search, precision
  • 2.0.2
    record
    2020-07-24 · diff ↗
  • 2.0.1
    record
    2020-07-23 · diff ↗ ·
    added 2 exports
    mvn_imputation, var_estimate
  • 2.0.0
    record
    2020-05-31 · diff ↗ ·
    removed 14 exports
    assess_predictability, bayes_R2, diagnostics, fisher_r2z, fisher_z2r, ggm_compare_bf, mae, mape, mse, plot_adjacency, posterior_predict, pp_check, rmse, shiny_bggm
    added 16 exports
    bggm_missing, fisher_r_to_z, fisher_z_to_r, gen_ordinal, ggm_compare_confirm, ggm_compare_explore, pcor_mat, pcor_sum, pcor_to_cor, plot_prior, posterior_samples, predictability, regression_summary, roll_your_own, weighted_adj_mat, zero_order_cors
  • R
    R 4.0.0 released · 2020-04-24
  • 1.0.0
    record
    2020-02-06
  • R
    R 3.6.0 released · 2019-04-26

Package metadata

First published
2020-02-06
Total releases
13 / 6 yrs
License
GPL-2 OSI
Minimum R
≥ 4.0.0
Bundled data
245 KB / 19 files
Download size
3.0 MB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("BGGM")

The package provides a citation file that builds its entry when R runs it. Run citation() to see it.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for BGGM version 2.2.0 [Data set]. HJJB, LLC. Data release v2026-10-18. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy