eventseries.event_series

Provides class for event series analysis, namely event synchronization (ES) and event coincidence analysis (ECA). In addition, a method for the generation of binary event series from continuous time series data is included. When instantiating a class, data must either be passed as an event matrix (for details see below) or as a continuous time series. Using the class, an ES or ECA matrix can be calculated to generate a climate network using the EventSeriesClimateNetwork class. Both ES and ECA may be called without instantiating an object of the class. Significance levels are provided using analytic calculations using Poisson point processes as a null model (for ECA only) or a Monte Carlo approach.

Modifications vs. original pyunicorn EventSeries

Modification 1 (constructor):

Removed the axis-swap heuristic that transposed data when the number of variables exceeded the number of timesteps. The heuristic assumed that datasets with more variables than timesteps were transposed by mistake, which is not always true.

Modification 2 (make_event_matrix):

Replaced np.quantile with np.nanquantile so that time series containing NaN values are handled gracefully instead of raising an error.

Modification 3 (matrix loops):

Added tqdm progress bars to _ndim_event_synchronization and _ndim_event_coincidence_analysis for visual feedback during long runs.

Modification 4 (getters):

Added get_T(), get_N(), get_timestamps(), get_taumax(), get_lag() accessor methods to expose key instance attributes without name-mangling gymnastics.

Optimization 1 — Sparse binary-search ES with lag support (finite taumax):

For finite taumax, precomputes sorted inner-event arrays once per node and uses np.searchsorted to find only the event pairs within the lag-shifted taumax window. Complexity O(N²·L·taumax/T) vs O(N²·L²). Results are exact (atol < 1e-12 vs pairwise reference).

Optimization 2 — Blocked dense ES (infinite taumax, lag=0):

Falls back to a 4-D blocked-dense tensor kernel that vectorises the double-count correction loop — the main bottleneck in the original code. Block size is tunable; joblib parallelization is supported.

Optimization 3 — Vectorized ECA via cumsum + BLAS (integer timestamps):

For uniform integer timestamps and integer-valued lag, builds lag=0 smeared indicator matrices with cumsum rolling windows, shifts by lag steps, then uses a single BLAS matrix multiply. Complexity O(T·N + N²). Precision is identical to pairwise within float32 rounding (atol < 1e-6).

Optimization 4 — Optional joblib parallelization:

All kernel dispatchers accept an n_jobs keyword argument. If joblib is installed, computation is distributed across n_jobs worker processes. Falls back to a single-process loop when joblib is absent.

Contributors

Guruprem Bishnoi — Modifications 1–4 and Optimizations 1–4 (2026)

class pyunicorn.eventseries.event_series.EventSeries(data, *, timestamps=None, taumax=inf, lag=0.0, threshold_method=None, threshold_values=None, threshold_types=None)[source]

Bases: Cached

__cache_state__() Tuple[Hashable, ...][source]

Hashable tuple of mutable object attributes, which will determine the instance identity for ALL cached method lookups in this class, in addition to the built-in object id(). Returning an empty tuple amounts to declaring the object immutable in general. Mutable dependencies that are specific to a method should instead be declared via @Cached.method(attrs=(…)).

NOTE:

A subclass is responsible for the consistency and cost of this state descriptor. For example, hashing a large array attribute may be circumvented by declaring it as a property, with a custom setter method that increments a dedicated mutation counter.

__init__(data, *, timestamps=None, taumax=inf, lag=0.0, threshold_method=None, threshold_values=None, threshold_types=None)[source]

Initialize an instance of EventSeries. Input data must be a 2D numpy array with time as the first axis and variables as the second axis. Event data is stored as an eventmatrix.

Format of eventmatrix: An eventmatrix is a 2D numpy array with the first dimension covering the timesteps and the second dimensions covering the variables. Each variable at a specific timestep is either ‘1’ if an event occured or ‘0’ if it did not, e.g. for 3 variables with 10 timesteps the eventmatrix could look like

array([[0, 1, 0],

[1, 0, 1], [0, 0, 0], [1, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [0, 0, 0]])

If input data is not provided as an eventmatrix, the constructor tries to generate one using the make_event_matrix method. Default keyword arguments are used in this case.

Parameters:
  • data (2D Numpy array [time, variables]) – Event series array or array of non-binary variable values

  • timestamps (1D Numpy array) – Time points of events of data. If not provided, integer values are used

  • taumax (float) – maximum time difference between two events to be considered synchronous. Caution: For ES, the default is np.inf because of the intrinsic dynamic coincidence interval in ES. For ECA, taumax is a parameter of the method that needs to be defined!

  • lag (float) – extra time lag between the event series

  • threshold_method (str 'quantile' or 'value' or 1D numpy array or str 'quantile' or 'value') – specifies the method for generating a binary event matrix from an array of continuous time series. Default: None

  • threshold_values (1D Numpy array or float) – quantile or real number determining threshold for each variable. Default: None.

  • threshold_types (str 'above' or 'below' or 1D list of strings 'above' or 'below') – Determines for each variable if event is below or above threshold

__str__()[source]

Return a string representation of the EventSeries object.

_compute_eca_pairwise(window_type)[source]

Pairwise ECA loop — identical to original pyunicorn. Modification 3: tqdm progress bar added.

_compute_eca_vectorized_lag(window_type)[source]

Optimization 3: Vectorized ECA via cumsum rolling windows + BLAS matrix multiply, extended to support any integer-valued lag.

Core idea: build the lag=0 smeared indicator matrix with a cumsum rolling window, then shift it by lag steps along the time axis. Boundary corrections mirror the pairwise formula exactly.

For lag=0 the output is bit-for-bit identical to the pairwise path within float32 rounding (atol < 1e-6 vs pairwise reference). Complexity: O(T·N + N²) vs O(N²·L²) for the pairwise approach.

_compute_es_matrix_blocked(node_data, block_size=32, n_jobs=1)[source]

Optimization 2: Assemble the full N×N directed ES matrix from blocked 4-D computations (infinite taumax, lag=0).

Optimization 4: n_jobs > 1 uses joblib if available.

_compute_es_matrix_sparse_lag(node_data, n_jobs=1)[source]

Optimization 1: Assemble the full N×N directed ES matrix using the lag-aware sparse binary-search kernel. Works for any scalar lag value.

Row-based chunking minimises joblib serialisation overhead. Optimization 4: n_jobs > 1 uses joblib if available.

_eca_coincidence_rate(eventseriesx, eventseriesy, *, window_type='symmetric', ts1=None, ts2=None)[source]

Event coincidence analysis: Returns the coincidence rates of two event series for both directions

Parameters:
  • eventseriesx (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • eventseriesy (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • ts1 (1D Numpy array) – Event time array containing time points when events of event series 1 occur, not obligatory

  • ts2 (1D Numpy array) – Event time array containing time points when events of event series 2 occur, not obligatory

  • window_type (str {'retarded', 'advanced', 'symmetric'}) – Only for ECA. Determines if precursor coincidence rate (‘advanced’), trigger coincidence rate (‘retarded’) or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed (‘symmetric’). Default: ‘symmetric’

Return type:

list

Returns:

Precursor coincidence rates [XY, YX]

_empirical_percentiles(method=None, n_surr=1000, symmetrization='directed', window_type='symmetric')[source]

Compute p-values of event synchronisation (ES) and event coincidence analysis (ECA) using a Monte-Carlo approach. Surrogates are obtained by shuffling the event series. ES/ECA scores of the surrogate event series are computed and p-values are the empirical percentiles of the original event series compared to the ES/ECA scores of the surrogates.

Parameters:
  • method (str 'ES' or 'ECA') – determines if ES or ECA should be used

  • n_surr (int) – number of surrogates for Monte-Carlo method

  • symmetrization (str {'directed', 'symmetric', 'antisym', 'mean', 'max', 'min'} for ES, str {'directed', 'mean', 'max', 'min'} for ECA) – determines if and which symmetrisation method should be used for the ES/ECA score matrix

  • window_type (str {'retarded', 'advanced', 'symmetric'}) – Only for ECA. Determines if precursor coincidence rate (‘advanced’), trigger coincidence rate (‘retarded’) or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed (‘symmetric’). Default: ‘symmetric’

Return type:

2D numpy array

Returns:

p-values of the ES/ECA scores for all

_ndim_event_coincidence_analysis(window_type='symmetric')[source]

Computes NxN event coincidence matrix of event coincidence rate.

Routing (Optimization 3):

uniform integer timestamps + integer lag → vectorized cumsum + BLAS otherwise → pairwise loop (original)

Parameters:

window_type (str {'retarded', 'advanced', 'symmetric'}) – Only for ECA. Determines if precursor coincidence rate (‘advanced’), trigger coincidence rate (‘retarded’) or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed (‘symmetric’). Default: ‘symmetric’

Return type:

NxN numpy array where N is the number of variables of the eventmatrix

Returns:

event coincidence matrix

_ndim_event_synchronization()[source]

Compute NxN event synchronization matrix [i,j] with event synchronization from j to i without symmetrization.

Routing (Optimizations 1 & 2):

finite taumax, any lag → sparse binary-search (fast, exact) infinite taumax, lag=0 → blocked-dense 4-D (vectorized) infinite taumax, lag≠0 → pairwise loop (fallback)

Return type:

NxN numpy array where N is the number of variables of the eventmatrix

Returns:

event synchronization matrix

_ndim_event_synchronization_pairwise()[source]

Pairwise ES loop — identical to original pyunicorn. Used as fallback when taumax=inf and lag≠0.

Modification 3: tqdm progress bar added.

_precompute_es_node_data()[source]

Optimization 1 / 2: Precompute inner-event times and per-event dynamic tau2 for every node. Called once before the matrix loop.

static _symmetrization_antisym(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

antisymmetrized matrix

static _symmetrization_directed(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

original matrix

static _symmetrization_max(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

symmetrized matrix using element-wise maximum of matrix and transposed matrix

static _symmetrization_mean(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

symmetrized matrix using element-wise mean of matrix and transposed matrix

static _symmetrization_min(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

symmetrized matrix using element-wise minimum of matrix and transposed matrix

static _symmetrization_symmetric(matrix)[source]

Helper function for symmetrization options

Parameters:

matrix (2D numpy array) – pairwise ECA/ES scores of data

Return type:

2D numpy array

Returns:

symmetrized matrix

event_analysis_significance(*, method=None, surrogate='shuffle', n_surr=1000, symmetrization='directed', window_type='symmetric')[source]

Returns significance levels (1 - p-values) for event synchronisation (ES) and event coincidence analysis (ECA). For ECA, there is an analytic option providing significance levels based on independent Poisson processes. The ‘shuffle’ option uses a Monte-Carlo approach, calculating ES or ECA scores for surrogate event time series obtained by shuffling the original event time series. The significance levels are the empirical percentiles of the ES/ECA scores of the original event series compared with the scores of the surrogate data.

Parameters:
  • method (str 'ES' or 'ECA') – determines if ES or ECA should be used

  • surrogate (str 'analytic' or 'shuffle') – determines if p-values should be calculated using a Monte-Carlo method or (only for ECA) an analytic Poisson process null model

  • n_surr (int) – number of surrogates for Monte-Carlo method

  • symmetrization (str {'directed', 'symmetric', 'antisym', 'mean', 'max', 'min'} for ES, str {'directed', 'mean', 'max', 'min'} for ECA) – determines if and which symmetrisation method should be used for the ES/ECA score matrix

  • window_type (str {'retarded', 'advanced', 'symmetric'}) – Only for ECA. Determines if precursor coincidence rate (‘advanced’), trigger coincidence rate (‘retarded’) or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed (‘symmetric’). Default: ‘symmetric’

Return type:

2D numpy array

Returns:

significance levels of the ES/ECA scores for all pairs of event series in event matrix

static event_coincidence_analysis(eventseriesx, eventseriesy, taumax, *, ts1=None, ts2=None, lag=0.0)[source]

Event coincidence analysis: Returns the precursor and trigger coincidence rates of two event series X and Y following the algorithm described in [Odenweller2020].

Parameters:
  • eventseriesx (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • eventseriesy (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • ts1 (1D Numpy array) – Event time array containing time points when events of event series 1 occur, not obligatory

  • ts2 (1D Numpy array) – Event time array containing time points when events of event series 2 occur, not obligatory

  • taumax (float) – coincidence interval width

  • lag (int) – lag parameter

Return type:

list

Returns:

[Precursor coincidence rate XY, Trigger coincidence rate XY, Precursor coincidence rate YX, Trigger coincidence rate YX]

event_series_analysis(method='ES', symmetrization='directed', window_type='symmetric')[source]

Returns the NxN matrix of the chosen event series measure where N is the number of variables. The entry [i, j] denotes the event synchronization or event coincidence analysis from variable j to variable i. According to the ‘symmetrization’ parameter the event series measure matrix is symmetrized or not.

The event coincidence rate of ECA is calculated according to the formula: r(Y|X, DeltaT1, DeltaT2, tau) = 1/N_X sum_{i=1}^{N_X} Theta[sum{j=1}^{N_Y} 1_[DeltaT1, DeltaT2] (t_i^X - (t_j^Y + tau))], where X is the first input event series, Y the second input event series, N_X the number of events in X, DeltaT1 and DeltaT2 the given coincidence interval boundaries, tau the lag between X and Y, Theta the Heaviside function and 1 the indicator function.

Parameters:
  • method (str 'ES' or 'ECA') – determines if ES or ECA should be used

  • symmetrization (str {'directed', 'symmetric', 'antisym', 'mean', 'max', 'min'} for ES, str {'directed', 'mean', 'max', 'min'} for ECA) – determines if and which symmetrisation method should be used for the ES/ECA score matrix

  • window_type (str {'retarded', 'advanced', 'symmetric'}) – Only for ECA. Determines if precursor coincidence rate (‘advanced’), trigger coincidence rate (‘retarded’) or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed (‘symmetric’). Default: ‘symmetric’

Return type:

2D numpy array

Returns:

pairwise event synchronization or pairwise coincidence rates symmetrized according to input parameter ‘symmetrization’

static event_synchronization(eventseriesx, eventseriesy, *, ts1=None, ts2=None, taumax=inf, lag=0.0)[source]

Calculates the directed event synchronization from two event series X and Y using the algorithm described in [Quiroga2002], [Odenweller2020]

Parameters:
  • eventseriesx (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • eventseriesy (1D Numpy array) – Event series containing ‘0’s and ‘1’s

  • ts1 (1D Numpy array) – Event time array containing time points when events of event series 1 occur, not obligatory

  • ts2 (1D Numpy array) – Event time array containing time points when events of event series 2 occur, not obligatory

  • taumax (float) – maximum distance of two events to be counted as synchronous

  • lag (float) – delay between the two event series, the second event series is shifted by the value of lag

Return type:

list

Returns:

[Event synchronization XY, Event synchronization YX]

static make_event_matrix(data, threshold_method='quantile', threshold_values=None, threshold_types=None)[source]

Create a binary event matrix from continuous time series data. Data format is eventmatrix, i.e. a 2D numpy array with first dimension covering time and second dimension covering the values of the variables.

Parameters:
  • data (2D numpy array) – Continuous input data

  • threshold_method (str 'quantile' or 'value' or 1D numpy array of strings 'quantile' or 'value') – specifies the method for generating a binary event matrix from an array of continuous time series. Default: ‘quantile’

  • threshold_values (1D Numpy array or float) – quantile or real number determining threshold for each variable. Default: None.

  • threshold_types (str 'above' or 'below' or 1D list of strings 'above' or 'below') – Determines for each variable if event is below or above threshold

Return type:

2D numpy array

Returns:

eventmatrix

pyunicorn.eventseries.event_series._compute_es_block(node_data, block_a, block_b)[source]

Exact ES for all node pairs in two blocks via 4-D dense boolean tensors.

Vectorises the double-count correction loop that is the bottleneck in pyunicorn’s pairwise code. Used by the blocked-dense kernel (Opt 2).

pyunicorn.eventseries.event_series._compute_es_pair_sparse_lag(tx, tau2x, ty, tau2y, *, taumax, lag)[source]

Exact ES for one pair using sorted inner-event times + binary search, extended to support any scalar lag (Optimization 1).

Parameters

tx, tau2x : 1-D float64 — inner event times and per-event tau2 for X ty, tau2y : 1-D float64 — inner event times and per-event tau2 for Y taumax : float — coincidence window cap (must be finite) lag : float — time lag (Y is conceptually shifted by +lag)

Returns

(countxy / norm, countyx / norm) : float64 pair

pyunicorn.eventseries.event_series._pad_block(node_data, indices)[source]

Pad inner-event arrays for a block of nodes into dense 2-D arrays.

Used by the blocked-dense ES kernel (Optimization 2).

pyunicorn.eventseries.event_series._process_es_rows_sparse_lag(r_start, r_end, N, node_data, *, taumax, lag)[source]

Process all pairs (i, j > i) where i in [r_start, r_end) — row-based chunk for joblib (Optimization 1 / 4).