Paper · 2023-11-29 · cs.LG, cs.AI
Fast, Interpretable, and Deterministic Time Series Classification With a Bag-of-Receptive-Fields
Bag-of-Receptive-Fields (BORF) slides dilated, strided windows over each signal, z-normalises each window, turns segment means into 3-symbol SAX words and counts them, giving a sparse, deterministic feature set for a ridge classifier. Author-reported on 158 UCR/UEA datasets: accuracy statistically tied with ROCKET and MiniRocket (9th average rank), second-best runtime.
Time series classificationSymbolic aggregate approximationExplainable AItime-seriesclassificationsymbolic-representationsaxinterpretabilitydeterministic
arXivPDFCodeMarkdown14 min read
AI-compiled by claude-haiku-5-5 on 2026-10-19, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
A time series is a long list of measurements over time, such as an EEG recording or a sensor trace. Many classifiers for these lists are hard to explain, and the ones that are easy to explain often shuffle their choices at random, so two runs can point at different parts of the signal.
This method looks at the signal through many small sliding windows, at several window sizes, spacings and gaps between samples. Each window is rescaled, squashed into a short pattern of three levels, and the patterns are counted. The result is a table of "this pattern appeared this many times in this channel", with nothing random in it. A simple linear model can then read those counts, and each count can be traced back to the part of the signal it came from.
The idea builds on an older method, Bag-of-Patterns, and makes it faster on long series and more flexible for many channels. The paper's main claim is that the speed-up lets it compete with other fast classifiers while staying explainable and repeatable.
TL;DR
- BORF is a deterministic transform. It counts SAX words of windows taken with several sizes, dilations and word lengths, and stores the counts as a sparse tensor (series, signal, word) §4.2 alg. 2.
- The speed-up computes all segment means of a signal once with moving averages, so the cost per window no longer grows with window size §4.1 alg. 1 §4.3.
- A default heuristic sets the configurations from the series length and feeds the counts, after an inverse hyperbolic sine, to a ridge classifier §5.
- Author-reported on 158 datasets: accuracy statistically tied with ROCKET and MiniRocket, and the best median runtime (tied with HYDRA) §5 tab. 2 tab. 3.
- Not the most accurate method: ensemble hybrids such as MR-Hydra and RDST are statistically better, and the authors state that accuracy against all methods is not their claim §5 §6.
Problem
Top time series classifiers are black boxes or use randomised features whose explanations change between runs §1. Shapelet and interval methods are interpretable, but their randomness makes explanations vary run to run §1 §2. Bag-of-Patterns is deterministic and interpretable, but its window-wise SAX step has quadratic worst-case cost in the series length when the window grows with the series §4.1 §4.3. The paper formalises window-wise SAX, which earlier papers used without a formal definition §4.1.
The method assumes equally spaced observations in the paper. Each signal is one-dimensional; multivariate series are handled channel by channel §3 §4.2.
Method
The method has three parts: window-wise PAA and SAX with dilation and stride (wSAX), a sparse bag-of-words count over many such windows (BORF), and a linear classifier on the counts.
Receptive fields. A receptive field of length w and dilation d starting at point i is the sequence [x_i, x_{i+d}, \dots, x_{i+d(w-1)}]. Stride s is the step between consecutive fields. The number of fields for a signal of length m is §4 eq. 3:
n = 1 + \left\lfloor \frac{m - w - (d-1)(w-1)}{s} \right\rfloor eq. 3
Window-wise PAA. Each field is split into l segments of size q = w/l. Within a segment the points are d apart, and consecutive segments start q \cdot d points apart. The paper writes the PAA matrix M with one row per field and one column per segment §4.1 eq. 4 eq. 5.
- The mean of each dilated segment is computed for every start point with a moving average of length q and step d §4.1 eq. 6 eq. 7.
- Segment j of field i uses the precomputed mean at index i \cdot s + j \cdot q \cdot d §4.1 eq. 9. Each entry of M is therefore a lookup, not a new average.
- The mean and standard deviation of each dilated window of length w are computed with moving statistics. The standard deviation is the population form (divided by w) §4.1 eq. 8 eq. 10 eq. 11.
- Each segment mean is z-normalised with the statistics of its own window §4.1 eq. 12.
- Each z-value is mapped to one of \alpha symbols with the Gaussian quantile breakpoints \mathbf{b} into \alpha equally likely bins §3 eq. 2. The paper's rule is: symbol 0 if z \le b_1, symbol k-1 if b_{k-1} < z \le b_k, and symbol \alpha - 1 if z > b_{\alpha-1}.
SAX words as integers. The l symbols of a field form a word. The word is read as a base-\alpha number with the first symbol most significant §4.2 eq. 13. The word is used as a feature key.
Bag of receptive fields. For every signal of every series, the words of all fields are counted. The count of word k in signal j of series i is stored in a sparse tensor of shape (series, signals, words). The paper gives the tensor as a sparse coordinate list of (series, signal, word, count) tuples §4.2 §4.3. For a classifier that needs a matrix, the last two axes are flattened §4.4.
# Window-wise SAX words of one signal [alg. 1] [eq. 3] [eq. 9]
# Input: signal (m,); window w, word length l, dilation d, stride s
# Output: words (n,), each an integer in base alphabet_size
def wsax_words(signal, w, l, d, s, alphabet_size, bins):
# Segment size q = w / l; the paper assumes w is divisible by l [§4.1]
q = w // l
# Mean of every dilated segment, for all start points [§4.1] [eq. 6]
segment_means = moving_mean(signal, q, d)
# Mean and std of every dilated window of length w [§4.1] [eq. 10]
window_means = moving_mean(signal, w, d)
window_stds = moving_std(signal, w, d)
words = []
for i in range(count_windows(len(signal), w, d, s)): # [eq. 3]
word = 0
for j in range(l):
# Segment j of window i starts at i*s + j*q*d [§4.1] [eq. 9]
mean = segment_means[i * s + j * q * d]
# Z-normalise with the window's own statistics [§4.1] [eq. 12]
# Paper gives no rule for std = 0; code returns 0 [code: core/sax.py#L80-L83]
z = zscore(mean, window_means[i * s], window_stds[i * s])
# Symbol from the Gaussian breakpoints [§3] [eq. 2]
symbol = discretize(z, bins)
# First symbol is most significant [§4.2] [eq. 13]
word = word * alphabet_size + symbol
words.append(word)
return words# Configurations of the default heuristic [§5] [tab. 4]
# Input: n, length of the (longest) series
# Output: list of (w, d, l, alphabet_size, s) configurations
def heuristic_configs(n):
# Window sizes 2^2 .. 2^floor(log2 n) [§5]
windows = powers_of_two(4, n)
# Dilations 2^0 .. 2^floor(log2 log2 n), i.e. 2^k <= log2 n [§5]
dilations = powers_of_two(1, log2(n))
configs = []
for w in windows:
for d in dilations:
# Word lengths 2, 4 and 8 only [§5]
for l in [2, 4, 8]:
# Skip words longer than the window [code: heuristic.py#L91]
if l > w:
continue
# Alphabet 3 and stride 1 [§5]
configs.append((w, d, l, 3, 1))
return configsClassifier. The count matrix is passed through element-wise inverse hyperbolic sine and then to a ridge classifier, described as interpretable §5 README.md. The paper does not state the ridge regularisation strength.
Explanations. A linear model on these counts gives one coefficient per count. Its contribution is a SHAP value per count, paired with a ridge classifier §4.5. The paper illustrates this on the synthetic CBF dataset fig. 3. Two maps follow from it:
- A saliency map over time. Each positive or negative contribution of a contained word is spread over the points it was built from, then rescaled so the total equals the summed contributions of contained words §4.5 eq. 14 eq. 15 eq. 16.
- A map for absent words. A word that is not in a series is shown by its typical shape, using a background set of series to find aligned segments §4.5 fig. 4.
Global explanations rank words by their average absolute SHAP value over series, and show how each word's count relates to the class §4.5 fig. 5.
Vector of settings. Section 5 fixes the configurations with the heuristic above; the table in Hyperparameters lists every value.
Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| window sizes w | 2^2, 2^3, \dots, 2^{\lfloor \log_2 n \rfloor} | §5 "BORF Heuristic" | n is the series length; the paper does not say whether it is per dataset or the longest series. Code uses the longest series borf.py |
| dilations d | 2^0, 2^1, \dots, 2^{\lfloor \log_2 \log_2 n \rfloor} | §5 | Equivalent to 2^k \le \log_2 n |
| word length l | 2, 4, 8 | §5 | Ablation tab. 4 shows dropping 8 costs about 0.05 accuracy |
| alphabet size \alpha | 3 | §5 | Breakpoints are Gaussian quantiles §3 |
| stride s | 1 | §5 | |
| flat-window threshold \theta | 0.15 | §5 | Window std below \theta times the signal std is treated as constant. Library default is 0.0 README.md |
| normalisation | window mean and std, population form | §4.1 eq. 10 eq. 11 | |
| inverse hyperbolic sine | element-wise, after counting | §5 | Ablation tab. 4 "w/o ash" row |
| classifier | ridge classifier | §5 | Regularisation not stated |
| missing values | linear interpolation, then last-value padding | §5 "Datasets" | Code instead ignores missing points sax.py |
| tuning set | 42 development datasets, the same as ROCKET | §5 | |
| train/test split | default split of each dataset | §5 | |
| train/inference time limit | one day per model per dataset | §5 | 32 cores, 64 GB memory |
Results
Author-reported. Setup: 158 datasets from the UCR and UEA archives, 128 univariate and 30 multivariate, default train/test splits §5 "Datasets". Metric: accuracy; runtime is training plus inference seconds. Baselines use library defaults or the values from their papers §5 "Competitors". Failed runs (time or memory limits) get the lowest rank.
Ranking. BORF has the 9th average accuracy rank. It is statistically tied with ROCKET and MiniRocket, and only RDST and MR-Hydra are statistically better. It has the 2nd best average runtime rank, tied with HYDRA §5 "Classification" fig. 6.
Comparison matrix, accuracy (paper's columns; the paper says wins, ties and losses are read against BORF) tab. 2:
| Model | Δ acc. median | Δ acc. mean | win | tie | loss | p-val |
|---|---|---|---|---|---|---|
| MR-HYDRA | +0.022192 | +0.037400 | 109 | 22 | 27 | 0.000100 |
| RDST | +0.020242 | +0.030600 | 103 | 20 | 35 | 0.000100 |
| ROCKET | +0.016769 | +0.022100 | 100 | 17 | 41 | 0.000100 |
| HYDRA | +0.011855 | +0.022700 | 95 | 19 | 44 | 0.000100 |
| MINIROCKET | +0.010000 | +0.020500 | 96 | 17 | 45 | 0.000100 |
| DrCIF | +0.006530 | +0.017600 | 91 | 8 | 59 | 0.0012 |
| RSTSF | +0.006480 | -0.000200 | 89 | 12 | 57 | 0.0160 |
| IT | +0.005714 | +0.011800 | 86 | 9 | 63 | 0.0664 |
| BORF | 0.855870 (median acc.) | 0.803461 (mean acc.) | ||||
| ST | 0.000000 | -0.014400 | 71 | 12 | 75 | 0.6036 |
| W+MUSE | 0.000000 | -0.038900 | 75 | 15 | 68 | 0.1711 |
| MrSEQL | -0.012935 | -0.038700 | 45 | 9 | 104 | 0.000100 |
| TSF | -0.019281 | -0.037400 | 50 | 7 | 101 | 0.000100 |
| MrSQM | -0.030547 | -0.048800 | 34 | 11 | 113 | 0.000100 |
| KNN-DTW | -0.055175 | -0.077400 | 32 | 6 | 120 | 0.000100 |
| REDCOM | -0.061862 | -0.094100 | 28 | 6 | 124 | 0.000100 |
| CNN | -0.100000 | -0.205500 | 22 | 5 | 131 | 0.000100 |
| MCDCNN | -0.105270 | -0.194000 | 21 | 3 | 134 | 0.000100 |
| TAPNET | -0.150854 | -0.250000 | 14 | 6 | 138 | 0.000100 |
| SAXVSM | -0.384722 | -0.393200 | 5 | 1 | 152 | 0.000100 |
| BOP | -0.431526 | -0.438800 | 3 | 1 | 154 | 0.000100 |
Grey rows in the paper (IT, RSTSF, ST, W+MUSE) are statistically tied with BORF by the Wilcoxon signed-rank test tab. 2.
Comparison matrix, runtime (seconds; BORF row gives its own absolute median and mean) tab. 3:
| Model | Δ runtime median (s) | Δ runtime mean (s) | win | loss | p-val |
|---|---|---|---|---|---|
| BORF | 1.305673 (median) | 298.748806 (mean) | |||
| HYDRA | +0.240600 | -294.475100 | 55 | 103 | 0.4150 |
| MrSQM | +1.445971 | +1717.956800 | 16 | 142 | 0.000100 |
| MR-HYDRA | +1.842159 | -286.187900 | 25 | 133 | 0.000100 |
| SAXVSM | +2.037075 | +8465.654600 | 14 | 144 | 0.000100 |
| BOP | +2.080840 | +7917.965700 | 14 | 144 | 0.000100 |
| MCDCNN | +5.178714 | +3067.028100 | 8 | 150 | 0.000100 |
| MINIROCKET | +6.569353 | -264.884700 | 15 | 143 | 0.000100 |
| RSTSF | +7.198198 | +1977.266800 | 3 | 155 | 0.000100 |
| TSF | +7.601070 | -247.130400 | 13 | 145 | 0.000100 |
| KNN-DTW | +9.648525 | +628.124900 | 11 | 147 | 0.000100 |
| RDST | +10.822470 | -157.059500 | 7 | 151 | 0.000100 |
| W+MUSE | +12.068445 | +3112.670400 | 2 | 156 | 0.000100 |
| REDCOM | +21.037976 | +304.791200 | 12 | 146 | 0.000100 |
| ROCKET | +42.215268 | -126.137100 | 4 | 154 | 0.000100 |
| CNN | +51.684931 | +1516.333400 | 5 | 153 | 0.000100 |
| MrSEQL | +74.944092 | +4104.123300 | 1 | 157 | 0.000100 |
| DrCIF | +102.230795 | +69.233300 | 4 | 154 | 0.000100 |
| IT | +488.190649 | +1275.131400 | 4 | 154 | 0.000100 |
| ST | +571.357490 | +4489.157700 | 0 | 158 | 0.000100 |
| TAPNET | +3292.977048 | +17514.254500 | 0 | 158 | 0.000100 |
The paper notes that the mean runtime is driven by two datasets, FaceDetection and InsectWingbeat (both highly multivariate and short). Without them the mean drops from 298.7 s to 27.9 s §5 "Classification".
Interpretable and SAX-based subsets fig. 7. Against SAX-based methods BORF is the most accurate and fastest. Among interpretable methods it is fastest and ranks 3rd in accuracy, behind RDST, and tied with RSTSF and ST §5 "Classification". The paper notes that RDST and RSTSF change between runs, while BORF does not §5.
Scalability. Window-wise PAA with the moving-average speed-up stays roughly flat as the window grows, while naive PAA peaks near half the series length. For a series of length 1000 with word length 8 over 10 trials, wPAA is faster than naive PAA at every window size tested. At window size half the series length, naive PAA grows quadratically and wPAA grows near-linearly with series length §5 "Scalability" fig. 9.
Space. The number of non-zero counts fits \mathit{nnz} \approx 5.74 \cdot (\text{series} \cdot \text{signals} \cdot \text{points})^{0.96} over the archives, which the paper calls nearly proportional to input size §5 "Space" fig. 10.
Ablation on the 42 development datasets. Baseline median accuracy 0.820175 and median runtime 17.954614 s. Other rows give the difference from baseline tab. 4:
| Variant | θ | d | ash | word lengths | window sizes | Δ Acc | Δ Time (s) |
|---|---|---|---|---|---|---|---|
| baseline | yes | yes | yes | 2,4,8 | all | 0.820175 (abs.) | 17.954614 (abs.) |
| w/o θ | no | yes | yes | 2,4,8 | all | -0.012570 | +7.954003 |
| w/o ash | yes | yes | no | 2,4,8 | all | -0.019762 | -0.053850 |
| w/o dilations | yes | no | yes | 2,4,8 | all | -0.009656 | -10.144182 |
| max l = 2 | yes | yes | yes | 2 | all | -0.185247 | -17.196495 |
| max l = 4 | yes | yes | yes | 2,4 | all | -0.050413 | -14.253021 |
| max l = 16 | yes | yes | yes | 2,4,8,16 | all | +0.002720 | +27.502504 |
| max w = 8 | yes | yes | yes | 2,4,8 | 4,8 | -0.043034 | -11.914014 |
| max w = 16 | yes | yes | yes | 2,4,8 | 4,8,16 | -0.014399 | -7.452427 |
| max w = 32 | yes | yes | yes | 2,4,8 | 4,8,16,32 | -0.000989 | -2.546247 |
Case study, FingerMovements (multivariate EEG, 28 channels, binary) §5 "Case Study" fig. 11. Accuracy with each channel's counts kept separate: 0.56. With all channels summed: 0.58. With parietal and frontal channels summed separately from the two occipital channels: 0.61, the best of the variants tested. The paper's point is the flexibility of choosing which counts to add up.
Per-dataset results. The full per-dataset accuracy table for the top 13 models is in tab. 6 (appendix C, not reproduced here).
Paper vs code
The official code is the fast_borf package at
https://github.com/fspinna/borf README.md. Its owner is one of
the authors (Francesco Spinnato), and the repository is MIT-licensed
LICENSE. The commit read is 69cc543. The README says the paper-era
release is v0.1.0 and that tests compare the current code with outputs of the
original implementation README.md README.md.
The v0.1.0 tree itself was not read.
- Heuristic and stride match: window sizes, dilations, word lengths 2, 4, 8, alphabet 3 and stride 1 are the defaults heuristic.py borf.py. Dilations 2^k \le \log_2 n are the same as the paper's 2^{\lfloor \log_2 \log_2 n \rfloor} bound §5.
- Flat-window threshold: the paper uses \theta = 0.15 and treats \theta \le 0.15 as constant §5. The library default is 0.0, so the heuristic must be set explicitly borf.py README.md. The comparison is strict ("<") in code sax.py, while the paper writes "≤".
- Ties at breakpoints: paper eq. 2 assigns a value equal to b_k to the
lower symbol. In code
sax_wordsthe value goes to the upper symbol sax.py §3 eq. 2. - Windows and dilations that do not fit: the code drops a configuration when window times dilation exceeds the longest series heuristic.py. The paper does not state this rule.
- Arcsinh: the paper applies inverse hyperbolic sine before the ridge classifier §5. The example pipelines do not README.md classification.py; only the explanation test does test_xai.py.
- Classifier: examples use
RidgeClassifierCV()with library defaults README.md. The paper does not state the alpha grid. - Missing values: the paper interpolates and pads §5. The code treats NaN as missing and computes windows on observed points only borf.py sax.py.
- Time weighting: the current code weights each observation by the time since the previous one, for irregular sampling sax.py sax.py. With evenly spaced timestamps the code says the weights are equal and the paper's formulas are recovered [code: core/sax.py#L5-L8]. This is a later addition not in the paper.
- Vocabulary: the default keeps only (signal, word) pairs seen during fit borf.py borf.py. This is the paper's count matrix on the training data, not a fixed set of all possible words. (The paper's Bag-of-Receptive-Fields definition fixes a set of p patterns §4.2; the code's default vocabulary is data-dependent.)
- Naming:
complexity="quadratic"is the default and gives stride 1 heuristic.py. It does not mean the cost is quadratic."linear"uses stride = word length heuristic.py.
Pitfalls
- Flat windows are ambiguous. The paper says a flat window is "all zeros" §5. The code sets the z-score to 0 sax.py. With 3 symbols, z = 0 falls into the middle symbol, not symbol 0 sax.py.
- Constant signals differ again. If a whole signal has zero standard deviation, every word is 0, which is the all-lowest-symbol word, not the middle one sax.py sax.py. Implementers should use the code's rule for both cases.
- The default threshold is off. A faithful reproduction must set \theta = 0.15 explicitly; the library default leaves near-flat windows unthresholded README.md §5. The paper's ablation shows that removing \theta lowers accuracy and raises runtime tab. 4.
- Fixed vocabulary. The default vocabulary is built on the training set.
Words that appear only in test series get no feature and are silently
dropped, and the feature count depends on the training set borf.py.
Use
vocabulary="full"for a data-independent feature space README.md. - Floating-point drift. The moving means are updated by adding and subtracting terms, and the module is compiled with fast-math. On long series with large offsets this can lose precision in the window statistics that every z-score depends on. The paper does not analyse this moving.py moving.py.
- Complexity has a catch. The per-window cost is independent of window size §4.3, but the number of possible words grows as \alpha^l. The authors report that word length 8 suffices on their benchmark §4.3, and that very long series would probably need larger word lengths §6.
- Complexity is not the whole cost. The paper's runtime wins hold for long, low-dimensional datasets. On highly multivariate short datasets such as FaceDetection and InsectWingbeat the mean runtime is much worse than ROCKET §5 "Classification".
- Accuracy is not the headline. The paper says it is not the most accurate method; MR-Hydra, RDST and ROCKET are statistically better or tied, and the comparison matrices show losses on many datasets §5 §6 tab. 2.
- Explanation maps are approximations. The saliency map spreads each word's importance over the points it came from, then rescales it. A word that is not contained has no direct location and is illustrated with a background set of aligned segments §4.5 eq. 14 eq. 15 eq. 16.
- Results are author-reported and depend on one configuration and the paper's library versions of each baseline (pyts, aeon, sktime) §5 "Competitors".
- Later work. The code README cites a 2026 time-aware extension for irregular sampling (arXiv:2609.39268). It is not on this wiki and was not read.
Lineage
- Builds on: Bag-of-Patterns, which uses SAX over sliding windows and counts words §2 §3. It also builds on SAX itself, with its PAA and breakpoint quantisation §3 eq. 1 eq. 2.
- Extends: window-wise SAX as used by other SAX classifiers, which the paper says were never formally defined. It adds dilation and stride, and a moving average speed-up §4.1.
- Compared against: SAX-based methods (Bag-of-Patterns, SAX-VSM, MrSQM, MrSEQL) and dictionary, interval, shapelet, kernel, neural and hybrid classifiers §5 "Competitors" tab. 1.
- Superseded by: nothing known in this wiki.
Source and license
Adapted from “Fast, Interpretable, and Deterministic Time Series Classification With a Bag-of-Receptive-Fields” by Francesco Spinnato, Riccardo Guidotti, Anna Monreale, Mirco Nanni (arXiv:2311.18029), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/fspinna/borf at commit 69cc54359744 (MIT). Any quoted code is shown under that license.