Resampling adjacent blocks instead of isolated days retains short-range order when estimating uncertainty from a stable series.
Moving-block bootstrap: preserve local dependence in resampled series
Decide what may be exchanged
A daily operational series has short runs created by queue backlog. Ordinary row resampling breaks these runs and can understate uncertainty for a mean or stable-model residual statistic. A moving-block bootstrap samples contiguous windows and joins them to form a series of the original length. It assumes blocks from the prepared series are comparable after trend, weekday effects and known policy changes are addressed. Serial dependence explains why the independent-row bootstrap is suspect.
Choose a block length deliberately
A short block can miss dependence beyond its edge; a very long block leaves few distinct windows and unstable resamples. Declare a range of block lengths spanning the observed correlation scale, then show how the interval changes. The example samples circular blocks so every start date has a full window, wrapping from the last day to the first. That wrap is a computational convention, not evidence that final and first calendar days were adjacent in reality. The project records this sensitivity before accepting a change claim.
Resample the right object
If the target is a difference around a known intervention, resampling the entire raw series can shuffle observations across regimes and erase the design. Fit planned mean structure first and resample suitable residual blocks within stable segments or use another dependence-aware inference method. If a branch panel is involved, preserve both branch and time relationships rather than applying one-series blocks across all branches. The function demonstrates only a block draw; it does not produce a valid intervention interval by itself. Controlled-series design remains separate.
Keep failure modes visible
For each interval report the statistic, segment used for resampling, number of resamples, block-length range, seed and observed calendar gaps. Large seasonal cycles, rare regime changes and long-memory behavior may require a different model or longer follow-up. A narrow interval at one convenient block length is weak evidence if nearby lengths change the decision. Coverage claims apply only to the design and assumptions actually checked.
Implementation
from random import Random
def circular_block_sample(daily_residuals, block_length, seed):
size = len(daily_residuals)
if size < 2 or not 1 <= block_length <= size:
raise ValueError("block length must fit observed series")
generator = Random(seed)
resampled = []
while len(resampled) < size:
start = generator.randrange(size)
resampled.extend(daily_residuals[(start + offset) % size]
for offset in range(block_length))
return resampled[:size]
residuals = [1, 2, 3, 4, 5, 6, 7]
assert circular_block_sample(residuals, 3, 47) == \
circular_block_sample(residuals, 3, 47)
assert len(circular_block_sample(residuals, 3, 47)) == len(residuals)
Performance and operating cost
One length-n draw takes O(n) time and O(n) space. B bootstrap draws cost O(Bn) time before recalculating the statistic. The expensive analytical step is deciding which residual segment is stable enough to resample and whether block lengths retain relevant dependence.
Common Mistakes
- Resampling isolated daily rows from a dependent series.
- Shuffling raw pre- and post-intervention observations together.
- Choosing one block length only because it gives the desired interval.
- Treating circular wraparound as literal adjacency in the operational calendar.
Read next
- Serial correlation: daily rows are not daily independent evidence
- Project: review a refund-delay change with correlated daily outcomes
- Standard error and cluster bootstrap: resample the independent unit
- Confidence intervals: interpret coverage and precision honestly
- Controlled interrupted time series with a comparison series
