R Under development (unstable) (2026-10-28 r90783 ucrt) -- "Unsuffered Consequences" Copyright (C) 2026 The R Foundation for Statistical Computing Platform: x86_64-w64-mingw32/x64 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > library(BATTS) > # predict()/fitted()/density_ratio() agree with eval_balance_weight() exactly. > set.seed(31) > x <- matrix(c(rnorm(40), rnorm(40, 0.6)), ncol = 1); g <- rep(0:1, each = 40) > nd <- x[1:5, , drop = FALSE] > > set.seed(7); fb <- boots(x, g, num_trees_max = 8, K_CV = 3, quiet = TRUE) Warning message: boots() is deprecated; use batts_boost() instead (see ?`BATTS-deprecated`). boots() still works and gives the same result. This warning is shown once per session. > set.seed(8); fs <- batts(x, g, num_trees = 4, size_burnin = 5, size_backfitting = 13, + output_BART_ensembles = TRUE, quiet = TRUE) Warning message: batts() is deprecated; use batts_bart() instead (see ?`BATTS-deprecated`). batts() still works and gives the same result. This warning is shown once per session. > > # 1. type = "weight" is bit identical to the legacy entry point. > legacy_b <- as.numeric(eval_balance_weight(fb, nd)$balancing_weight_boosting) Warning message: eval_balance_weight() is deprecated; use predict() instead (see ?`BATTS-deprecated`). eval_balance_weight() still works and gives the same result. This warning is shown once per session. > stopifnot(identical(predict(fb, nd, type = "weight"), legacy_b)) > > legacy_s <- eval_balance_weight(fs, nd, is_Bayes = TRUE)$balancing_weight_BART > stopifnot(identical(predict(fs, nd, type = "weight", summary = "none"), legacy_s)) > > # 2. The default is the log-density ratio, not the weight. > stopifnot(identical(predict(fb, nd), 2 * log(legacy_b)), + !identical(predict(fb, nd), legacy_b)) > > # 3. Transformations are exact. > w <- predict(fb, nd, type = "weight") > stopifnot(identical(predict(fb, nd, type = "ratio"), w^2), + identical(predict(fb, nd, type = "log_ratio"), 2 * log(w)), + identical(density_ratio(fb, nd), w^2)) > > # 4. Each draw is transformed before summarizing, not the other way round. > d <- predict(fs, nd, type = "weight", summary = "none") > stopifnot(identical(predict(fs, nd, type = "ratio"), rowMeans(d^2)), + identical(predict(fs, nd), rowMeans(2 * log(d))), + !isTRUE(all.equal(rowMeans(d^2), rowMeans(d)^2))) > > # 5. The median summary is invariant to the monotone transform only when the > # number of draws is odd, because median() averages the two middle values. > stopifnot(ncol(d) == 13L, ncol(d) %% 2L == 1L) > stopifnot(isTRUE(all.equal(predict(fs, nd, type = "ratio", summary = "median"), + apply(d, 1, median)^2, tolerance = 1e-12))) > > # 6. fitted() matches prediction at the training points. > stopifnot(identical(fitted(fb, type = "weight"), + as.numeric(fb$balance_weight_boosting_data)), + isTRUE(all.equal(fitted(fb), predict(fb, x), tolerance = 1e-10)), + identical(fitted(fs, type = "weight", summary = "none"), + fs$balance_weight_BART_data)) > > # 7. Omitting newdata uses the training observations. > stopifnot(identical(predict(fb), fitted(fb)), + identical(predict(fs), fitted(fs)), + identical(density_ratio(fb), fitted(fb, type = "ratio"))) > > # 8. Intervals. > iv <- predict(fs, nd, interval = TRUE, level = 0.8) > stopifnot(identical(dim(iv), c(5L, 3L)), + identical(colnames(iv), c("fit", "lower", "upper")), + all(iv[, "lower"] <= iv[, "fit"]), all(iv[, "fit"] <= iv[, "upper"]), + all(is.finite(iv))) > > # 9. Invalid arguments are rejected. > bad <- function(expr) tryCatch({expr; NA_character_}, error = conditionMessage) > stopifnot(grepl("should be one of", bad(predict(fb, nd, type = "nope"))), + grepl("level must be", bad(predict(fs, nd, level = 1)), fixed = TRUE), + grepl("interval must be", bad(predict(fs, nd, interval = NA)), fixed = TRUE), + grepl("outside the fitted domain", bad(predict(fb, x + 1e6)), fixed = TRUE), + grepl("outside of the sample space", bad(eval_balance_weight(fb, x + 1e6)), fixed = TRUE)) > > # 10. A boosting fit rejects posterior-only arguments instead of ignoring them. > stopifnot(grepl("no posterior draws", bad(predict(fb, nd, summary = "none")), fixed = TRUE), + grepl("summary", bad(predict(fb, nd, summary = "none")), fixed = TRUE), + grepl("no posterior draws", bad(fitted(fb, interval = TRUE)), fixed = TRUE)) > > # 11. Prediction consumes no random numbers. > rng <- .Random.seed > invisible(predict(fb, nd)); invisible(predict(fs, nd)) > invisible(density_ratio(fb, nd)); invisible(density_ratio(fs, nd)) > invisible(fitted(fb)); invisible(fitted(fs)) > invisible(predict(fs, nd, interval = TRUE)) > stopifnot(identical(rng, .Random.seed)) > > cat('predict()/fitted()/density_ratio() checks passed.\n') predict()/fitted()/density_ratio() checks passed. > > proc.time() user system elapsed 0.17 0.14 0.29