{"id":21872541,"url":"https://github.com/crsh/jab","last_synced_at":"2025-03-21T22:41:41.041Z","repository":{"id":155148886,"uuid":"632450980","full_name":"crsh/jab","owner":"crsh","description":"R package to automagically compute Jeffrey's Approximate Bayes factors","archived":false,"fork":false,"pushed_at":"2025-02-14T08:33:56.000Z","size":918,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-14T09:37:02.391Z","etag":null,"topics":["bayes-factor","bayesian-inference","r","statistics"],"latest_commit_sha":null,"homepage":"","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crsh.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-25T12:40:10.000Z","updated_at":"2025-02-14T08:34:01.000Z","dependencies_parsed_at":"2024-06-27T10:00:25.661Z","dependency_job_id":null,"html_url":"https://github.com/crsh/jab","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crsh%2Fjab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crsh%2Fjab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crsh%2Fjab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crsh%2Fjab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crsh","download_url":"https://codeload.github.com/crsh/jab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880548,"owners_count":20525510,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bayes-factor","bayesian-inference","r","statistics"],"created_at":"2024-11-28T06:21:26.563Z","updated_at":"2025-03-21T22:41:41.034Z","avatar_url":"https://github.com/crsh.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\nreferences: \"inst/references.bib\"\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n\n# jab: Automagic computation of Jeffrey's approxiamte Bayes factors\n\n\u003c!-- badges: start --\u003e\n[![CRAN status](https://www.r-pkg.org/badges/version/jab)](https://CRAN.R-project.org/package=jab)\n[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)\n\u003c!-- badges: end --\u003e\n\nThe goal of **jab** is to conveniently calculate Jeffrey's approximate Bayes factor (JAB; [Wagenmakers, 2022](https://psyarxiv.com/egydq)) for a wide variety of statistical analyses.\n\n\n## Installation\n\nYou can install the development version of **jab** like so:\n\n``` r\nremotes::install_github(\"crsh/jab\")\n```\n\n## Example\n\n**jab** automatically supports calculation of JAB for any analysis that outputs a [Wald test](https://en.wikipedia.org/wiki/Wald_test) and for which [**broom**](https://github.com/tidymodels/broom/) returns an estimate and a standard error.\nThe user additionally needs to specify a prior distribution for estimate in the scale used to calculate the Wald statistic.\n\nTake the example of standard linear regression.\nJAB can be easily calculated for all regression coefficients.\nWe simply submit the results from the orthodox frequentist analysis to `jab()` and specify a prior distribution---let's use a scaled central Cauchy distribution.\nNote that JAB gives evidence for the null hypothesis relative to the alternative.\n\n```{r lm-example}\nlibrary(\"jab\")\nlibrary(\"ggplot2\")\n\n# Fit regression model\ndata(attitude)\nattitude_z \u003c- data.frame(scale(attitude))\nattitude_lm \u003c- lm(rating ~ 0 + ., data = attitude_z)\nattitude_tidy_lm \u003c- broom::tidy(attitude_lm)\n\nattitude_tidy_lm\n\n# Specify prior distribution and approximate Bayes factor\nattitude_jab \u003c- jab(\n  attitude_lm\n  , prior = dcauchy\n  , location = 0\n  , scale = sqrt(2) / 4\n)\n\nattitude_jab\n```\n\nNow compare this with the Jeffreys-Zellner-Siow (JZS) Bayes factor from `BayesFactor::regressionBF()` with the same prior distribution.\n\n```{r lm-example-jzs}\n# Calculate JZS-Bayes factor\nattitude_jzs \u003c- BayesFactor::regressionBF(\n  rating ~ .\n  , data = attitude\n  , rscaleCont = sqrt(2) / 4\n  , whichModels = \"top\"\n  , progress = FALSE\n)\n\n# Compare results\ntibble::tibble(\n  predictor = attitude_tidy_lm$term\n  \n  # Frequentist p-values\n  , p = attitude_tidy_lm$p.value\n  \n  # Bayes factors in favor of the null hypothesis\n  , jab = attitude_jab\n  , jzs = rev(as.vector(attitude_jzs))\n  \n  # Naive posterior probabilities\n  , jab_pp = jab / (jab + 1)\n  , jzs_pp = jzs / (jzs + 1)\n)\n```\n\nPretty close!\n\n### Varying prior distributions\n\nTo vary the scale of the prior distribution, simply pass a vector of scaling parameters, one scale for each coefficient.\n\n```{r lm-example-vary-priors}\njab(\n  attitude_lm\n  , prior = dcauchy\n  , location = 0\n  , scale = c(rep(0.5, 3), rep(sqrt(2) / 4, 3))\n)\n```\n\n### Prior sensitivity\n\nSimilarly, performing a prior sensitivity analysis is straight forward and fast.\n\n```{r lm-example-prior-sensitivity}\n# Specify design\njab_sensitivity \u003c- expand.grid(\n  coef = names(coef(attitude_lm))\n  , r = seq(0.2, 1.5, length.out = 50)\n) |\u003e\n  # Calculate Bayes factors for each prior setting\n  dplyr::group_by(r) |\u003e\n  dplyr::mutate(\n    jab = jab(\n      attitude_lm\n      , prior = dcauchy\n      , location = 0\n      , scale = r\n    )\n  )\n\n# Plot results\nggplot(jab_sensitivity) +\n  aes(x = r, y = jab / (1 + jab), color = coef) +\n  geom_hline(\n    yintercept = 0.5\n    , linetype = \"22\"\n    , color = grey(0.7)\n  ) +\n  geom_line(linewidth = 1.5) +\n  scale_color_viridis_d() +\n  lims(y = c(0, 1)) +\n  labs(\n    x = bquote(italic(r))\n    , y = \"Naive posterior probability\"\n    , color = \"Coefficient\"\n  ) +\n  papaja::theme_apa(box = TRUE)\n```\n\n\n### Sequential analyses\n\nSequential analyses are also a breeze.\n\n```{r lm-example-sequential-analysis}\n# Specify design\nsequential_jab \u003c- expand.grid(\n  coef = names(coef(attitude_lm))\n  , n = 10:nrow(attitude_z)\n) |\u003e\n  # Calculate Bayes factors for each subsample\n  dplyr::group_by(n) |\u003e\n  dplyr::mutate(\n    jab = jab(\n      update(attitude_lm, data = attitude_z[1:unique(n), ])\n      , dcauchy\n      , location = 0\n      , scale = sqrt(2) / 4\n    )\n    , jab_pp = jab / (jab + 1)\n  )\n\n# Plot results\nggplot(sequential_jab) +\n  aes(x = n, y = jab_pp, color = coef) +\n  geom_line(linewidth = 1.5) +\n  scale_color_viridis_d() +\n  lims(y = c(0, 1)) +\n  labs(\n    x = bquote(italic(n))\n    , y = \"Naive posterior probability\"\n    , color = \"Coefficient\"\n  ) +\n  papaja::theme_apa(box = TRUE)\n```\n\n\n## What's in a p-value?\n\nBy calculating JAB from p-values, we can explore approximately how much evidence a p-value provides for the alternative (or null) hypothesis for a given sample size.\nHere I use the precise piecewise approximation suggested by [Wagenmakers (2022)](https://psyarxiv.com/egydq), Eq. 9.\nNote that both axes are on a log-scale.\n\n```{r evidence-in-p}\nlibrary(\"geomtextpath\")\n\np_boundaries \u003c- c(0.0001, 0.001, 0.01, 0.05, 0.1, 1)\n\ndat \u003c- expand.grid(\n  p = exp(seq(log(0.00005), log(1), length.out = 100))\n  , n = exp(seq(log(3), log(10000), length.out = 100))\n) |\u003e\n  transform(jab_p = 1 / jab::jab_p(p, n))\n\nevidence_labels \u003c- data.frame(\n  n = c(17, 50, 75, 150, 350, 800, 2000, 4800)\n  , p = c(0.0002, 0.0009, 0.00225, 0.005, 0.019, 0.065, 0.175, 0.45)\n  , label = c(\"Extreme\", \"Very strong\", \"Strong\", \"Moderate\", \"Anecdotal\", \"Moderate\", \"Strong\", \"Very strong\")\n  , angle = -c(17, 17, 17, 17, 17, 18, 21, 24) + 3\n)\n\nplot_settings \u003c- list(\n  scale_x_continuous(\n    expand = expansion(0, 0)\n    , breaks = c(5, 10, 20, 50, 100, 250, 500, 1000, 2500, 5000, 10000)\n    , trans = \"log\"\n    , name = bquote(\"Sample size\" ~ italic(n))\n  )\n  , scale_y_continuous(\n    expand = expansion(0, 0)\n    , breaks = p_boundaries\n    , labels = format(p_boundaries, scientific = FALSE, drop0trailing = TRUE)\n    , trans = \"log\"\n    , name = bquote(italic(p)*\"-value\")\n  )\n  , scale_fill_viridis_c(guide = \"none\")\n  , theme_minimal(base_size = 16)\n  , theme(\n    axis.ticks.length = unit(5, \"pt\")\n    , axis.ticks.x = element_line()\n    , axis.ticks.y = element_line()\n    , plot.margin = margin(0.5, 0.5, 0.5, 0.5, \"cm\")\n    , axis.title.x = element_text(margin = margin(t = 0.1, unit = \"cm\"))\n    , axis.title.y = element_text(margin = margin(r = -0, unit = \"cm\"))\n    , axis.text.x = element_text(angle = 30, hjust = 1)\n  )\n)\n\nto_reciprocal \u003c- function(x) {\n  ifelse(\n    x \u003e 1\n    , as.character(round(x))\n    , paste0(\"1/\", round(1/x))\n  )\n}\n \nggplot(dat) +\n  aes(x = n, y = p) +\n  geom_raster(aes(fill = log(jab_p)), interpolate = TRUE) +\n  # geom_hline(yintercept = p_boundaries, color = \"white\", alpha = 0.2) +\n  geom_textcontour(\n    aes(z = jab_p, label = to_reciprocal(after_stat(level)))\n    , color = \"white\"\n    , breaks = c(1/30, 1/10, 1/3, 3, 10, 30, 100)\n  ) +\n  geom_text(\n    aes(x = n, y = p, label = label, angle = angle)\n    , data = evidence_labels\n    , color = \"white\"\n    , fontface = \"bold\"\n    , size = 5\n  ) +\n  plot_settings\n\n```\n\n\u003c!-- ## Package dependencies --\u003e\n\n```{r dep-plot, echo = FALSE, fig.width = 7, fig.height = 7, message = FALSE, warning = FALSE, eval = FALSE}\ndepgraph::plot_dependency_graph()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrsh%2Fjab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrsh%2Fjab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrsh%2Fjab/lists"}