
Screen the report axis for batched reporting
batch_test.RdDetects batches: report dates at which a stalled reporting system releases
a backlog. A batch moves reports along the report axis without creating
them, so it shows up as a spike preceded by a deficit, while the total over a
window spanning both is unchanged. batch_test() is completely
model-free – it needs only a tbl_now(), not a fitted model – which
makes it the right tool for exploratory data analysis before any nowcasting
model is chosen.
Usage
batch_test(
data,
lookback = 7L,
baseline_window = NULL,
period = NULL,
null_model = c("auto", "poisson", "robust"),
alpha = 0.05
)Arguments
- data
A
tbl_now()object of anydata_type.- lookback
Integer
k: how many report dates beforerthe window reaches back. Should comfortably cover the longest plausible stall. Default7(a week of daily reporting).- baseline_window
Odd integer width of the smoother used to estimate the baseline (a robust local line, Siegel's repeated median). Must satisfy
baseline_window >= 2 * lookback + 3so that a clean date is never outvoted by a batch episode. Defaults to the smallest admissible odd value (adjusted upward to a multiple ofperiodplus one whenperiodis supplied).- period
Optional integer cycle length of a scheduled reporting pattern (e.g.
7for a weekly cycle on daily data).NULL(default) means the cycle is taken from the object's temporal effects if present (day-of-week ->7, week-of-year ->52), and otherwise no calendar correction is applied. A value passed here always wins.- null_model
"auto"(default) picks the null from the data. The exact Poisson/Binomial null assumes Poisson counts and a baseline that captures the mean; real surveillance counts are overdispersed, so on non-negative countsautouses the exact null only when no overdispersion is detected (dispersion at most 1.5) and otherwise falls back to the dispersion-corrected robust normal approximation. Signed (count-cumulative) increments always use the robust null."poisson"and"robust"force the choice; note that"poisson"is anti-conservative (over-flags) on overdispersed counts.- alpha
Significance level for the Benjamini-Hochberg
batchflag. Default0.05.
Value
A tibble of class batch_test, one row per (report date, stratum),
with a print() method that summarises the flagged dates. Columns:
report_dateThe report (registration) date the row describes.
stratumThe stratum label, or
"all"when the data is unstratified.reportedReports recorded on
report_date(a signed increment for"count-cumulative"data, so it can be negative).baselineThe robust expected number of reports on
report_dateunder "no batch", from the leave-window-out local line.deficitHow many reports the
lookbackdays beforereport_datewere missing relative to baseline – the transport signal. Large and positive when a stall preceded a spike.deltaThe window total minus its baseline mean – the creation signal. Near zero for a pure batch (mass only moved), large for a surge.
p_transportOne-sided p-value that the deficit is larger than noise (the raw, per-point transport test).
p_transport_bhp_transportafter a Benjamini-Hochberg correction across all rows; the flag below thresholds this.batchLogical verdict:
TRUEwhenp_transport_bh < alphaand the window is not still depleted (a hold). This is the column to trust.
Details
The idea is that a batch moves reports along the report axis without creating them. Over a window of report dates that spans both the lull and the release, the total is therefore unchanged – every report you would have seen in the window you still see, just on a different day. A genuine surge instead adds reports and inflates the window total. So two quantities separate the two cases: the deficit (how many reports the days just before the spike were missing) picks up transport, and the window total (relative to a baseline) picks up creation. A batch has a large deficit but a conserved window total; a surge has an inflated window total but no deficit.
The baseline for each candidate window is refit from report dates lying strictly outside that window, using a robust local line (Siegel's repeated median). Smoothing through the episode instead would let the deficit drag the baseline down and the batch would mask itself as a surge.
The batch flag is the trustworthy verdict: it compares dates within one
window (insensitive to the overall level) and is Benjamini-Hochberg
corrected across every (report date, stratum) pair, so it controls the false
discovery rate rather than firing on every point that crosses a raw threshold.
A per-point creation ("surge") label is deliberately not returned: it only
compares the window total against the baseline, so on a steeply curved epidemic
curve it fires on ordinary growth. If you need genuine surges, fit a model.
For "count-cumulative" data the increments are signed and reported can be
negative (a down-revision).
A reporting system that is always closed at weekends produces every batch
symptom, every week, so batch_test() needs the length of any scheduled
cycle. It reads that from the object's temporal effects when it can: a
day-of-week effect sets period = 7, a week-of-year effect
period = 52 (see add_temporal_effects()). Pass period yourself to
override; if the data is daily and carries no temporal effect, the function
suggests period = 7. With a period set, the baseline is corrected by per-phase
medians across cycles, so an irregular batch reads as an excursion relative to
the schedule.
See also
batch_shape_test() for the complementary test on which event
dates a report date drew from, and simulate_batch() to inject a known
batch for validation.
Examples
library(tbl.now)
data(denguedat, package = "tbl.now")
dengue_tbl <- tbl_now(
denguedat,
event_date = onset_week,
report_date = report_week,
data_type = "linelist",
verbose = FALSE
)
screened <- batch_test(dengue_tbl, lookback = 2)
#> Warning: ! `batch_test()` is experimental: results are not guaranteed and the interface
#> may change.
#> ℹ Treat a flagged report date as a potential batch, not a confirmed one.
#> This warning is displayed once every 8 hours.
head(screened)
#> # A tibble: 6 × 9
#> report_date stratum reported baseline deficit delta p_transport
#> <date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1990-01-01 all 3 NA NA NA NA
#> 2 1990-01-08 all 26 NA NA NA NA
#> 3 1990-01-15 all 62 43.6 65 -46.6 0.00000103
#> 4 1990-01-22 all 41 41.2 2.38 -2.62 0.430
#> 5 1990-01-29 all 40 29.8 -38 48.2 1.000
#> 6 1990-02-05 all 36 29 -17 24 0.934
#> # ℹ 2 more variables: p_transport_bh <dbl>, batch <lgl>