Tutorial, part 2: interval statistics
Three parts: 1 · File to raster · 2 · Interval statistics · 3 · Many sessions
Part one stopped at a container of six sorted units. This part asks what those six spike trains actually do over time - how regular each one is, whether it bursts, and how to say so with a number a reviewer will accept.
Everything here reads the session12.afz saved at the end of
part one, so nothing is re-sorted. The six units kept 27 250
of the session's 41 882 events; the rest are the rejected u07 and events that no
cluster claimed, which is normal and not an error.
import axonforge as af
units = af.io.read("session12.afz") # the container from part one
for u in units.labels:
st = units.train(u)
print(u, st.n, af.stats.cv(st), af.stats.cv2(st))
Regularity: CV against CV2#
The coefficient of variation of the intervals is the obvious regularity measure, but it is
contaminated by slow rate changes: a unit that fires steadily but speeds up over the session
looks irregular to cv even though every neighbouring pair of intervals is similar.
cv2 fixes this by averaging over adjacent pairs only, so a slow drift cancels. When
the two disagree, the gap is rate drift, not spiking irregularity.
| Unit | Spikes | Rate, Hz | CV | CV2 | Fano (1 s) | Bursts | Reading |
|---|---|---|---|---|---|---|---|
u01 | 9 120 | 15.2 | 0.58 | 0.55 | 0.9 | 0 | regular, no drift |
u02 | 4 300 | 7.2 | 1.02 | 0.98 | 1.1 | 12 | close to Poisson |
u03 | 2 760 | 4.6 | 1.63 | 1.21 | 3.4 | 141 | bursts, and some drift |
u04 | 6 050 | 10.1 | 0.74 | 0.71 | 1.0 | 3 | fairly regular |
u05 | 3 480 | 5.8 | 1.18 | 0.89 | 1.9 | 44 | drift inflates CV |
u06 | 1 540 | 2.6 | 0.92 | 0.90 | 1.0 | 5 | sparse, steady |
Autocorrelograms#
The autocorrelogram counts, for each spike, how many other spikes of the same unit fall at each short lag. Its shape at small lags separates a regular cell from a bursting one at a glance: a regular unit has a clear trough near zero (its own refractory gap), while a bursting unit has a peak there because spikes arrive in clumps.
counts, edges = af.stats.autocorrelogram(units.train("u03"), bin_ms=1.0, span_ms=50.0)
b = af.stats.bursts(units.train("u03"), max_isi_ms=6.0, min_spikes=3)
print(len(b)) # 141 bursts
Fano factor and its window#
The Fano factor is the variance of the spike count divided by its mean, over fixed windows.
For a Poisson train it is one; u03's value of 3.4 reflects the clumping. The catch is that the
number depends entirely on the window, which is why stats.fano prints the window
alongside the value and refuses to be compared across windows. At 100 ms windows the same unit
reads closer to 1.6; the clumping is slower than that, so a short window misses it.
CV, CV2 and the Fano window belong together in a methods paragraph. A CV on its own invites the reader to assume stationarity you did not check; printing CV2 next to it shows whether that assumption held, and quoting the Fano window stops the factor being read as a universal constant of the cell.