Skip to content

Commit 0f5a026

Browse files
authored
properly compute BF_M for non uniform priors (#438)
1 parent 3a3af6f commit 0f5a026

File tree

7 files changed

+450
-423
lines changed

7 files changed

+450
-423
lines changed

R/commonAnovaBayesian.R

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -782,26 +782,36 @@ BANOVAcomputMatchedInclusion <- function(effectNames, effects.matrix, interactio
782782
# no errors, proceed normally and complete the table
783783

784784
logsumbfs <- logSumExp(logbfs + logprior)
785-
internalTable[["P(M|data)"]] <- exp(logbfs + logprior - logsumbfs)
785+
logPostProbModel <- logbfs + logprior - logsumbfs
786+
internalTable[["P(M|data)"]] <- exp(logPostProbModel)
786787

787-
nmodels <- nrow(internalTable)
788-
for (i in seq_len(nmodels)) {
789-
internalTable[i, "BFM"] <- logbfs[i] - logSumExp(logbfs[-i]) + log(nmodels - 1L)
790-
}
788+
logNumPostOdds <- logPostProbModel
789+
logDenPostOdds <- log1mexp(logNumPostOdds)
790+
logNumPriorOdds <- logprior
791+
logDenPriorOdds <- log1mexp(logNumPriorOdds)
792+
internalTable[["BFM"]] <- logNumPostOdds - logDenPostOdds + logDenPriorOdds - logNumPriorOdds
791793

792794
} else {
793795
# create table excluding failed models
794796

795797
idxGood <- !is.na(logbfs)
796798
widxGood <- which(idxGood)
797-
logsumbfs <- logSumExp(logbfs[idxGood])
798-
internalTable[["P(M|data)"]] <- exp(logbfs - logsumbfs)
799799

800-
nmodels <- sum(idxGood)
800+
# normalize the prior w.r.t the non-failed models
801+
logpriorSubset <- logprior[idxGood]
802+
logpriorSubset <- logpriorSubset - logSumExp(logpriorSubset)
803+
804+
logsumbfs <- logSumExp(logbfs[idxGood] + logpriorSubset)
805+
logPostProbModel <- logbfs[idxGood] + logpriorSubset - logsumbfs
806+
internalTable[widxGood, "P(M|data)"] <- exp(logPostProbModel)
807+
808+
logNumPostOdds <- logPostProbModel
809+
logDenPostOdds <- log1mexp(logNumPostOdds)
810+
logNumPriorOdds <- logpriorSubset
811+
logDenPriorOdds <- log1mexp(logNumPriorOdds)
812+
internalTable[widxGood, "BFM"] <- logNumPostOdds - logDenPostOdds + logDenPriorOdds - logNumPriorOdds
813+
801814
widxBad <- which(!idxGood)
802-
for (i in widxGood) {
803-
internalTable[["BFM"]][i] <- logbfs[i] - logSumExp(logbfs[-c(i, widxBad)]) + log(nmodels - 1L)
804-
}
805815

806816
internalTable[widxBad, "P(M|data)"] <- NaN
807817
internalTable[widxBad, "BFM"] <- NaN
@@ -2832,6 +2842,17 @@ BANOVAcomputMatchedInclusion <- function(effectNames, effects.matrix, interactio
28322842
return(interactions.matrix)
28332843
}
28342844

2845+
#' Accurately compute log(1 - exp(x))
2846+
#'
2847+
#' @param x numeric value or vector
2848+
#'
2849+
#' @details See https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf
2850+
#'
2851+
log1mexp <- function(x) {
2852+
a0 <- -0.69314718055994528623 # log(1 / 2)
2853+
ifelse(x < a0, log1p(-exp(x)), log(-expm1(x)))
2854+
}
2855+
28352856
# Model prior ----
28362857
.BANOVAcomputePriorModelProbs <- function(models, nuisance, options) {
28372858

tests/testthat/BANOVA_modelPriors.rds

223 Bytes
Binary file not shown.

tests/testthat/_snaps/anova/raincloud-plots-horizontal.svg

Lines changed: 68 additions & 68 deletions
Loading

tests/testthat/_snaps/anova/raincloud-plots-vertical.svg

Lines changed: 68 additions & 68 deletions
Loading

tests/testthat/_snaps/anovarepeatedmeasures/raincloud-plots-between-subjects.svg

Lines changed: 104 additions & 104 deletions
Loading

tests/testthat/_snaps/anovarepeatedmeasures/raincloud-plots.svg

Lines changed: 172 additions & 172 deletions
Loading

tests/testthat/test-anovabayesian.R

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ test_that("Model prior changes posterior model probabilities", {
223223
} else {
224224
jaspTools::expect_equal_tables(tableModelComparison, reference[[modelPrior]][["modelComparison"]])
225225
jaspTools::expect_equal_tables(tableEffects, reference[[modelPrior]][["posteriorSummary"]])
226+
227+
# internal consistency check
228+
BFM <- vapply(tableModelComparison, `[[`, "BFM", FUN.VALUE = numeric(1))
229+
prior_model_prob <- vapply(tableModelComparison, `[[`, "P(M)", FUN.VALUE = numeric(1))
230+
post_model_prob <- vapply(tableModelComparison, `[[`, "P(M|data)", FUN.VALUE = numeric(1))
231+
testthat::expect_equal(BFM, post_model_prob / (1 - post_model_prob) * (1 - prior_model_prob) / prior_model_prob)
226232
}
227233
}
228234
if (createReference) saveRDS(reference, referencePath)

0 commit comments

Comments
 (0)