Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 74 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ A work-in-progress Shiny interface lives in the
a separate package that depends on `singlehit`; installing `singlehit` does not
install or require it.

## Prerequisites

Check that your data can be fitted before you start. `singlehit` needs:

- **at least 3 distinct doses**, each greater than zero;
- **more than 1 positive response in total**, summed across all doses; and
- **counts of positive and negative subjects** for every dose, not just a
response proportion. Every dose group must contain at least one subject.

Data that fail these checks are rejected with an explanatory error. See
[Input data format](#input-data-format) for column names and the full rules.

## Installation

<!--
Expand Down Expand Up @@ -214,6 +226,65 @@ Check that hosts, dose units, and endpoints match before testing poolability;
the current pooling functions do not enforce those checks. Recording matching
metadata does not by itself establish that experiments should be pooled.

## Bootstrapping and run time

The bootstrap refits each model to thousands of resampled datasets to put
uncertainty bounds on the results. The exact beta-Poisson fit and large
bootstraps (thousands of replicates) can take minutes to hours, depending on
your computer. Start with a small number of replicates (for example
`bootstrap_times = 200`) to check your pipeline, then scale up.

### Parallel bootstraps (mirai)

[mirai](https://mirai.r-lib.org/) runs the bootstrap refits on background R
processes, so the run finishes sooner on a multi-core machine and the R console
can stay free while it works. It is optional: with the default settings,
bootstraps above 1,000 replicates use it when it is installed, and otherwise run
one after another in your current R session. Using mirai can reduce the wait.

Mirai also works after `devtools::load_all()`: local workers load the same
checkout before starting the bootstrap.

Bootstrap runs above 1,000 replicates automatically use mirai when it is
installed and show completion progress while results are collected. If no
daemons are already configured, the package starts a temporary
pool using 75% of the machine's detected physical cores and removes that pool
after collecting the result. Supply `workers` to override that default:

```r
analysis <- analyze_dose_response(
ward,
bootstrap_times = 10000,
seed = 2026,
workers = 12
)
```

Existing mirai daemons are reused and remain under caller control. Use
`backend = "sequential"` to disable automatic parallelization, or configure a
pool explicitly:

```r
mirai::daemons(4)
analysis <- analyze_dose_response(ward, bootstrap_times = 10000)
mirai::daemons(0)
```

Bootstrap samples are generated before parallel dispatch, so the same `seed`
produces identical results with `backend = "sequential"` and
`backend = "mirai"`. Only the model refits are sent to workers.

For a non-blocking bootstrap, start a job and collect it when the result is
needed:

```r
fit <- fit_dose_response(ward, "beta_poisson")
job <- bootstrap_dose_response_async(fit, times = 10000, seed = 2026)

# The R console is available while daemons fit the bootstrap samples.
result <- collect_bootstrap(job)
```

## Example

```r
Expand Down Expand Up @@ -255,7 +326,9 @@ parameterized in `alpha`/`beta`) is available as a deliberate opt-in via the
assessment, consensus, and plotting. Because it is roughly an order of magnitude
slower to fit, its bootstrap replicate count is controlled separately
(`exact_bootstrap_times`, default 10000; set to zero to fit and compare it
without bootstrapping):
without bootstrapping). The exact fit and its bootstrap are the slowest
part of the workflow, so see [Bootstrapping and run time](#bootstrapping-and-run-time)
before running large replicate counts:

```r
analysis <- analyze_dose_response(
Expand Down Expand Up @@ -358,51 +431,6 @@ All fits converge, and exhaustive grouping puts A and B together with C separate
A and B are candidates for a shared fit; keep C separate. This pooling decision
does not establish adequate absolute model fit or create a pooled analysis.

### Parallel bootstraps (mirai)

Mirai also works after `devtools::load_all()`: local workers load the same
checkout before starting the bootstrap.

Bootstrap runs above 1,000 replicates automatically use mirai when it is
installed and show completion progress while results are collected. If no
daemons are already configured, the package starts a temporary
pool using 75% of the machine's detected physical cores and removes that pool
after collecting the result. Supply `workers` to override that default:

```r
analysis <- analyze_dose_response(
ward,
bootstrap_times = 10000,
seed = 2026,
workers = 12
)
```

Existing mirai daemons are reused and remain under caller control. Use
`backend = "sequential"` to disable automatic parallelization, or configure a
pool explicitly:

```r
mirai::daemons(4)
analysis <- analyze_dose_response(ward, bootstrap_times = 10000)
mirai::daemons(0)
```

Bootstrap samples are generated before parallel dispatch, so the same `seed`
produces identical results with `backend = "sequential"` and
`backend = "mirai"`. Only the model refits are sent to workers.

For a non-blocking bootstrap, start a job and collect it when the result is
needed:

```r
fit <- fit_dose_response(ward, "beta_poisson")
job <- bootstrap_dose_response_async(fit, times = 10000, seed = 2026)

# The R console is available while daemons fit the bootstrap samples.
result <- collect_bootstrap(job)
```

## Development

Development notes and owner-requested workflow follow-ups live in [TODO.md](TODO.md).
Expand Down
16 changes: 16 additions & 0 deletions vignettes/getting-started.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ This vignette walks the Ward rotavirus human-challenge data from raw counts to a
library(singlehit)
```

## Prerequisites

Check that your data can be fitted before you start. `singlehit` needs:

- **at least 3 distinct doses**, each greater than zero;
- **more than 1 positive response in total**, summed across all doses; and
- **counts of positive and negative subjects** for every dose, not just a response proportion. Every dose group must contain at least one subject.

Data that fail these checks are rejected with an explanatory error.

## Load

The analysis needs **three columns, one row per dose group**: the administered `dose`, and the numbers of subjects who did (`positive`) and did not (`negative`) respond. The package ships this exact shape as `ward_rotavirus`:
Expand Down Expand Up @@ -132,6 +142,12 @@ Additional metadata columns are preserved. Duplicate doses are combined only
when their metadata agrees; conflicting values produce an error naming the
column. `total` and `response` are recalculated from the counts.

## Bootstrapping and run time

The bootstrap refits each model to thousands of resampled datasets to put uncertainty bounds on the results. Large bootstraps (thousands of replicates) and the opt-in exact beta-Poisson fit can take minutes to hours, depending on your computer. Start with a small number of replicates (for example `bootstrap_times = 200`) to check your pipeline, then scale up.

[mirai](https://mirai.r-lib.org/) runs the bootstrap refits on background R processes, so the run finishes sooner on a multi-core machine and the R console can stay free while it works. It is optional: bootstraps above 1,000 replicates use it when it is installed, and otherwise run one after another in your current R session. To choose the number of workers, set `workers` in `analyze_dose_response()`, or start a pool yourself with `mirai::daemons(4)`. See the README for details.

## Run

`analyze_dose_response()` does everything in one call: trend test, model fits, diagnostics, comparison, assessment, and bootstrap uncertainty. A fixed `seed` makes the bootstrap reproducible.
Expand Down
Loading