Skip to content

Commit aa23526

Browse files
committed
Merge branch 'main' into copilot/create-trace-plot-functions
2 parents ea726fb + 1e39054 commit aa23526

File tree

9 files changed

+306
-9
lines changed

9 files changed

+306
-9
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
.Ruserdata
55
parameter_trace
66
*.Rcheck
7-
*.tar.gz
7+
*.tar.gz
8+
README.html

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
S3method(plot,BayesMallowsSMC2)
44
S3method(print,BayesMallowsSMC2)
5+
S3method(print,summary.BayesMallowsSMC2)
6+
S3method(summary,BayesMallowsSMC2)
57
export(compute_sequentially)
68
export(precompute_topological_sorts)
79
export(set_hyperparameters)

R/print.R

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,123 @@ print.BayesMallowsSMC2 <- function(x, ...) {
7676

7777
invisible(x)
7878
}
79+
80+
#' Summary Method for BayesMallowsSMC2 Objects
81+
#'
82+
#' Creates a summary of a BayesMallowsSMC2 object returned by
83+
#' [compute_sequentially()].
84+
#'
85+
#' @param object An object of class \code{BayesMallowsSMC2}.
86+
#' @param ... Additional arguments (currently unused).
87+
#'
88+
#' @return An object of class \code{summary.BayesMallowsSMC2}, which is a list
89+
#' containing summary information about the model.
90+
#'
91+
#' @details
92+
#' The summary method creates a summary object that includes:
93+
#' \itemize{
94+
#' \item Number of particles
95+
#' \item Number of timepoints
96+
#' \item Number of items
97+
#' \item Number of clusters
98+
#' \item Log marginal likelihood
99+
#' \item Final effective sample size (ESS)
100+
#' \item Number of resampling events
101+
#' \item Posterior mean of alpha for each cluster
102+
#' \item Posterior standard deviation of alpha for each cluster
103+
#' }
104+
#'
105+
#' @export
106+
#'
107+
#' @examples
108+
#' # Fit a model with complete rankings
109+
#' set.seed(123)
110+
#' mod <- compute_sequentially(
111+
#' complete_rankings,
112+
#' hyperparameters = set_hyperparameters(n_items = 5),
113+
#' smc_options = set_smc_options(n_particles = 100, n_particle_filters = 1)
114+
#' )
115+
#'
116+
#' # Create summary
117+
#' summary(mod)
118+
#'
119+
summary.BayesMallowsSMC2 <- function(object, ...) {
120+
# Basic validation
121+
if (!inherits(object, "BayesMallowsSMC2")) {
122+
stop("object must be an object of class 'BayesMallowsSMC2'")
123+
}
124+
125+
required_fields <- c("alpha", "rho", "ESS", "resampling", "log_marginal_likelihood")
126+
missing_fields <- setdiff(required_fields, names(object))
127+
if (length(missing_fields) > 0) {
128+
stop("Object is missing required fields: ", paste(missing_fields, collapse = ", "))
129+
}
130+
131+
# Extract dimensions
132+
n_particles <- ncol(object$alpha)
133+
n_timepoints <- length(object$ESS)
134+
n_items <- dim(object$rho)[1]
135+
n_clusters <- nrow(object$alpha)
136+
137+
# Count resampling events
138+
n_resampling_events <- sum(object$resampling)
139+
140+
# Compute posterior mean and standard deviation of alpha
141+
# alpha is a matrix where rows are clusters and columns are particles
142+
alpha_mean <- rowMeans(object$alpha)
143+
alpha_sd <- apply(object$alpha, 1, sd)
144+
145+
# Create summary object
146+
summary_obj <- list(
147+
n_particles = n_particles,
148+
n_timepoints = n_timepoints,
149+
n_items = n_items,
150+
n_clusters = n_clusters,
151+
log_marginal_likelihood = object$log_marginal_likelihood,
152+
final_ess = object$ESS[n_timepoints],
153+
n_resampling_events = n_resampling_events,
154+
alpha_mean = alpha_mean,
155+
alpha_sd = alpha_sd
156+
)
157+
158+
class(summary_obj) <- "summary.BayesMallowsSMC2"
159+
summary_obj
160+
}
161+
162+
#' Print Method for summary.BayesMallowsSMC2 Objects
163+
#'
164+
#' Prints a summary of a BayesMallowsSMC2 model.
165+
#'
166+
#' @param x An object of class \code{summary.BayesMallowsSMC2}.
167+
#' @param ... Additional arguments (currently unused).
168+
#'
169+
#' @return Invisibly returns the input object \code{x}.
170+
#'
171+
#' @export
172+
#'
173+
print.summary.BayesMallowsSMC2 <- function(x, ...) {
174+
# Create header
175+
cat("BayesMallowsSMC2 Model Summary\n")
176+
cat(strrep("=", nchar("BayesMallowsSMC2 Model Summary")), "\n\n", sep = "")
177+
178+
# Display basic information
179+
cat(sprintf("%-25s %s\n", "Number of particles:", x$n_particles))
180+
cat(sprintf("%-25s %s\n", "Number of timepoints:", x$n_timepoints))
181+
cat(sprintf("%-25s %s\n", "Number of items:", x$n_items))
182+
cat(sprintf("%-25s %s\n\n", "Number of clusters:", x$n_clusters))
183+
184+
# Display model fit information
185+
cat(sprintf("%-25s %.2f\n", "Log marginal likelihood:", x$log_marginal_likelihood))
186+
cat(sprintf("%-25s %.2f\n", "Final ESS:", x$final_ess))
187+
cat(sprintf("%-25s %d/%d\n\n", "Resampling events:", x$n_resampling_events, x$n_timepoints))
188+
189+
# Display posterior statistics for alpha
190+
cat("Posterior Statistics for Alpha:\n")
191+
cat(strrep("-", nchar("Posterior Statistics for Alpha:")), "\n", sep = "")
192+
for (i in seq_along(x$alpha_mean)) {
193+
cat(sprintf("Cluster %d: Mean = %.4f, SD = %.4f\n",
194+
i, x$alpha_mean[i], x$alpha_sd[i]))
195+
}
196+
197+
invisible(x)
198+
}

README.Rmd

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
output: github_document
3+
bibliography: inst/REFERENCES.bib
34
---
45

56
<!-- README.md is generated from README.Rmd. Please edit that file -->
@@ -19,7 +20,7 @@ knitr::opts_chunk$set(
1920
[![R-CMD-check](https://github.com/osorensen/BayesMallowsSMC2/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/osorensen/BayesMallowsSMC2/actions/workflows/R-CMD-check.yaml)
2021
<!-- badges: end -->
2122

22-
BayesMallowsSMC2 provides functions for performing sequential inference in the Bayesian Mallows model using the SMC2 algorithm.
23+
BayesMallowsSMC2 provides functions for performing sequential inference in the Bayesian Mallows model using the SMC2 algorithm [@10.1214/25-BA1564].
2324

2425
## Installation
2526

@@ -30,8 +31,38 @@ You can install the development version of BayesMallowsSMC2 from [GitHub](https:
3031
devtools::install_github("osorensen/BayesMallowsSMC2")
3132
```
3233

33-
## Usage
34+
## Example
3435

35-
This package is under development, and is not yet well documented. For examples on how to use it, see the code in the OSF repository https://osf.io/pquk4/.
36+
Here is a basic example using the included `complete_rankings` dataset:
3637

38+
```{r example}
39+
library(BayesMallowsSMC2)
40+
41+
# Fit the model with complete rankings
42+
set.seed(123)
43+
mod <- compute_sequentially(
44+
complete_rankings,
45+
hyperparameters = set_hyperparameters(n_items = 5),
46+
smc_options = set_smc_options(n_particles = 100, n_particle_filters = 1)
47+
)
48+
49+
# Show model info
50+
mod
51+
```
52+
53+
### Posterior Summaries
54+
55+
We can visualize the posterior distributions of the parameters:
56+
57+
```{r posterior-alpha}
58+
# Posterior distribution of alpha (dispersion parameter)
59+
plot(mod, parameter = "alpha")
60+
```
61+
62+
```{r posterior-rho}
63+
# Posterior distribution of rho (ranking positions)
64+
plot(mod, parameter = "rho", items = c(1, 2, 3))
65+
```
66+
67+
## References
3768

README.md

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<!-- badges: end -->
1010

1111
BayesMallowsSMC2 provides functions for performing sequential inference
12-
in the Bayesian Mallows model using the SMC2 algorithm.
12+
in the Bayesian Mallows model using the SMC2 algorithm (Sørensen et al.
13+
2025).
1314

1415
## Installation
1516

@@ -21,8 +22,66 @@ You can install the development version of BayesMallowsSMC2 from
2122
devtools::install_github("osorensen/BayesMallowsSMC2")
2223
```
2324

24-
## Usage
25+
## Example
2526

26-
This package is under development, and is not yet well documented. For
27-
examples on how to use it, see the code in the OSF repository
28-
<https://osf.io/pquk4/>.
27+
Here is a basic example using the included `complete_rankings` dataset:
28+
29+
``` r
30+
library(BayesMallowsSMC2)
31+
32+
# Fit the model with complete rankings
33+
set.seed(123)
34+
mod <- compute_sequentially(
35+
complete_rankings,
36+
hyperparameters = set_hyperparameters(n_items = 5),
37+
smc_options = set_smc_options(n_particles = 100, n_particle_filters = 1)
38+
)
39+
40+
# Show model info
41+
mod
42+
#> BayesMallowsSMC2 Model
43+
#> ======================
44+
#>
45+
#> Number of particles: 100
46+
#> Number of timepoints: 100
47+
#> Number of items: 5
48+
#> Number of clusters: 1
49+
#>
50+
#> Log marginal likelihood: -472.34
51+
#> Final ESS: 63.55
52+
#> Resampling events: 5/100
53+
```
54+
55+
### Posterior Summaries
56+
57+
We can visualize the posterior distributions of the parameters:
58+
59+
``` r
60+
# Posterior distribution of alpha (dispersion parameter)
61+
plot(mod, parameter = "alpha")
62+
```
63+
64+
<img src="man/figures/README-posterior-alpha-1.png" alt="" width="100%" />
65+
66+
``` r
67+
# Posterior distribution of rho (ranking positions)
68+
plot(mod, parameter = "rho", items = c(1, 2, 3))
69+
```
70+
71+
<img src="man/figures/README-posterior-rho-1.png" alt="" width="100%" />
72+
73+
## References
74+
75+
<div id="refs" class="references csl-bib-body hanging-indent"
76+
entry-spacing="0">
77+
78+
<div id="ref-10.1214/25-BA1564" class="csl-entry">
79+
80+
Sørensen, Øystein, Anja Stein, Waldir Leoncio Netto, and David S.
81+
Leslie. 2025. “<span class="nocase">Sequential Rank and Preference
82+
Learning with the Bayesian Mallows Model</span>.” *Bayesian Analysis*,
83+
1–26. <https://doi.org/10.1214/25-BA1564>.
84+
85+
</div>
86+
87+
</div>

inst/REFERENCES.bib

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@article{10.1214/25-BA1564,
2+
author = {{\O}ystein S{\o}rensen and Anja Stein and Waldir Leoncio Netto and David S. Leslie},
3+
title = {{Sequential Rank and Preference Learning with the Bayesian Mallows Model}},
4+
journal = {Bayesian Analysis},
5+
publisher = {International Society for Bayesian Analysis},
6+
pages = {1 -- 26},
7+
keywords = {Mallows mixtures, partial rankings, particle filter, preference learning, SMC2},
8+
year = {2025},
9+
doi = {10.1214/25-BA1564},
10+
URL = {https://doi.org/10.1214/25-BA1564}
11+
}
16.8 KB
Loading
21.6 KB
Loading

tests/testthat/test-print.R

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,76 @@ test_that("print method works with partial rankings", {
3939
output <- capture.output(print(mod))
4040
expect_true(any(grepl("BayesMallowsSMC2 Model", output)))
4141
})
42+
43+
test_that("summary method works for BayesMallowsSMC2 objects", {
44+
set.seed(123)
45+
mod <- compute_sequentially(
46+
complete_rankings,
47+
hyperparameters = set_hyperparameters(n_items = 5),
48+
smc_options = set_smc_options(n_particles = 100, n_particle_filters = 1)
49+
)
50+
51+
# Test that summary method runs without error
52+
expect_error(summary(mod), NA)
53+
54+
# Test that summary returns an object of the correct class
55+
summ <- summary(mod)
56+
expect_s3_class(summ, "summary.BayesMallowsSMC2")
57+
58+
# Test that summary object contains expected fields
59+
expect_true("n_particles" %in% names(summ))
60+
expect_true("n_timepoints" %in% names(summ))
61+
expect_true("n_items" %in% names(summ))
62+
expect_true("n_clusters" %in% names(summ))
63+
expect_true("log_marginal_likelihood" %in% names(summ))
64+
expect_true("final_ess" %in% names(summ))
65+
expect_true("n_resampling_events" %in% names(summ))
66+
expect_true("alpha_mean" %in% names(summ))
67+
expect_true("alpha_sd" %in% names(summ))
68+
69+
# Test that alpha statistics are numeric
70+
expect_type(summ$alpha_mean, "double")
71+
expect_type(summ$alpha_sd, "double")
72+
73+
# Test that alpha statistics have correct length (equal to number of clusters)
74+
expect_equal(length(summ$alpha_mean), summ$n_clusters)
75+
expect_equal(length(summ$alpha_sd), summ$n_clusters)
76+
77+
# Test that print method for summary works
78+
expect_error(print(summ), NA)
79+
80+
# Capture output and verify it contains expected content
81+
output <- capture.output(print(summ))
82+
expect_true(any(grepl("BayesMallowsSMC2 Model Summary", output)))
83+
expect_true(any(grepl("Number of particles:", output)))
84+
expect_true(any(grepl("Number of timepoints:", output)))
85+
expect_true(any(grepl("Number of items:", output)))
86+
expect_true(any(grepl("Number of clusters:", output)))
87+
expect_true(any(grepl("Log marginal likelihood:", output)))
88+
expect_true(any(grepl("Final ESS:", output)))
89+
expect_true(any(grepl("Resampling events:", output)))
90+
expect_true(any(grepl("Posterior Statistics for Alpha:", output)))
91+
expect_true(any(grepl("Mean =", output)))
92+
expect_true(any(grepl("SD =", output)))
93+
})
94+
95+
test_that("summary method works with partial rankings", {
96+
set.seed(456)
97+
mod <- compute_sequentially(
98+
partial_rankings,
99+
hyperparameters = set_hyperparameters(n_items = 5),
100+
smc_options = set_smc_options(n_particles = 50, n_particle_filters = 1)
101+
)
102+
103+
# Test that summary method runs without error
104+
expect_error(summary(mod), NA)
105+
106+
# Test summary object has correct structure
107+
summ <- summary(mod)
108+
expect_s3_class(summ, "summary.BayesMallowsSMC2")
109+
110+
# Capture output and verify it contains expected content
111+
output <- capture.output(print(summ))
112+
expect_true(any(grepl("BayesMallowsSMC2 Model Summary", output)))
113+
expect_true(any(grepl("Posterior Statistics for Alpha:", output)))
114+
})

0 commit comments

Comments
 (0)