RecurrenceMicrostatesAnalysis.jl

RecurrenceMicrostatesAnalysisModule

RecurrenceMicrostatesAnalysis.jl

CI codecov Package Downloads Publication

RecurrenceMicrostatesAnalysis.jl is a simple and fast Julia-based package for recurrence microstates analysis. It implements the computation of Recurrence Microstates Analysis (RMA) distributions, specific quantifiers — such as disorder — and the estimation of typical RQA quantifiers, including determinism and laminarity.

RMA is a subfield of Recurrence Analysis and is a powerful tool for analyzing large time series or large datasets using statistical methods, offering high performance and avoiding memory issues. Although the field is still relatively new, it has shown promising applications, including in Machine Learning.

The package was redesigned in version 0.4.0 to be compatible with DynamicalSystems.jl ecosystem. We therefore recommend exploring the other packages in this ecosystem — especially ComplexityMeasures.jl and RecurrenceAnalysis.jl — which can be very useful when working with RMA.

To install the package, run:

import Pkg
Pkg.add("RecurrenceMicrostatesAnalysis")

The package documentation is available online, or you can build it locally by running julia docs/make.jl.

source
GitHub

RecurrenceMicrostatesAnalysis.jl is an open-source package available on GitHub. If you find this package useful, please consider giving it a star on GitHub and don't forget to cite our work. 😉

About the documentation

The documentation of RecurrenceMicrostatesAnalysis.jl is designed to explain how to use the package while also introducing the theoretical background of the RMA framework. The bibliography used throughout the documentation is listed in the References section; please remember to cite the appropriate works if you use them.

This welcome section begins with an introduction to the Input data for RecurrenceMicrostatesAnalysis.jl. Understanding the data types used by the package and their intended purposes is essential before proceeding with the rest of the documentation. We also describe the Output data from RecurrenceMicrostatesAnalysis.jl, explaining the type of data returned when computing recurrence microstate distributions.

The Tutorial section explains how to use the package in practice. It starts with a brief introduction to RMA and demonstrates how to compute Distributions using RecurrenceMicrostatesAnalysis.jl. Next, we show how to estimate RQA Quantifiers using RMA and discuss quantifiers defined specifically for RMA. This material constitutes the basic level of the documentation and is sufficient to learn how to effectively use this package.

For users interested in more advanced topics, the Recurrence Functions section discusses different ways of computing recurrence between two states, while the Shapes and Sampling section explains motif shapes used to extract specific information from a Recurrence Plot.

We also provide a pipeline for GPU computations, which we recommend reading if you plan to use the GPU backend.

The documentation includes applied examples, such as:

Finally, developers interested in contributing to RecurrenceMicrostatesAnalysis.jl are encouraged to read the RecurrenceMicrostatesAnalysis.jl for Devs section.

Input data for RecurrenceMicrostatesAnalysis.jl

RecurrenceMicrostatesAnalysis.jl accepts three types of input, each associated with a different backend:

  • StateSpaceSet — used for multivariate time series, datasets, or state-space representations. This type is employed when working with Recurrence Plots (RP) or Cross-Recurrence Plots (CRP). For RP and CRP analyses, we strongly recommend using this data type, as the backend is optimized for this context.

  • AbstractArray{<: Real} — used for spatial data, enabling RMA to be applied within the generalized framework of Spatial Recurrence Plots (SRP) (Marwan et al., 2007). Although a Matrix can be used as a substitute for a StateSpaceSet, this is not recommended, since the AbstractArray backend is heavier and incompatible with some features.

  • AbstractGPUVector — used for time series analysis with the GPU backend. A better explanation is provided in the GPU and Computing RMA distributions sections.

Warning

RMA with SRP is an open research field. We include this functionality in the package for exploratory purposes, but the method is not yet mature enough for production use. Nevertheless, feel free to experiment with it in your research. 😃

StateSpaceSets.StateSpaceSetType
StateSpaceSet{D, T, V} <: AbstractVector{V}

A dedicated interface for sets in a state space. It is an ordered container of equally-sized points of length D, with element type T, represented by a vector of type V. Typically V is SVector{D,T} or Vector{T} and the data are always stored internally as Vector{V}. SSSet is an alias for StateSpaceSet.

The underlying Vector{V} can be obtained by vec(ssset), although this is almost never necessary because StateSpaceSet subtypes AbstractVector and extends its interface. StateSpaceSet also supports almost all sensible vector operations like append!, push!, hcat, eachrow, among others. When iterated over, it iterates over its contained points.

Construction

Constructing a StateSpaceSet is done in three ways:

  1. By giving in each individual columns of the state space set as Vector{<:Real}: StateSpaceSet(x, y, z, ...).
  2. By giving in a matrix whose rows are the state space points: StateSpaceSet(m).
  3. By giving in directly a vector of vectors (state space points): StateSpaceSet(v_of_v).

All constructors allow for two keywords:

  • container which sets the type of V (the type of inner vectors). At the moment options are only SVector, MVector, or Vector, and by default SVector is used.
  • names which can be an iterable of length D whose elements are Symbols. This allows assigning a name to each dimension and accessing the dimension by name, see below. names is nothing if not given. Use StateSpaceSet(s; names) to add names to an existing set s.

Description of indexing

When indexed with 1 index, StateSpaceSet behaves exactly like its encapsulated vector. i.e., a vector of vectors (state space points). When indexed with 2 indices it behaves like a matrix where each row is a point.

In the following let i, j be integers, typeof(X) <: AbstractStateSpaceSet and v1, v2 be <: AbstractVector{Int} (v1, v2 could also be ranges, and for performance benefits make v2 an SVector{Int}).

  • X[i] == X[i, :] gives the ith point (returns an SVector)
  • X[v1] == X[v1, :], returns a StateSpaceSet with the points in those indices.
  • X[:, j] gives the jth variable timeseries (or collection), as Vector
  • X[v1, v2], X[:, v2] returns a StateSpaceSet with the appropriate entries (first indices being "time"/point index, while second being variables)
  • X[i, j] value of the jth variable, at the ith timepoint

In all examples above, j can also be a Symbol, provided that names has been given when creating the state space set. This allows accessing a dimension by name. This is provided as a convenience and it is not an optimized operation, hence recommended to be used primarily with X[:, j::Symbol].

Use Matrix(ssset) or StateSpaceSet(matrix) to convert. It is assumed that each column of the matrix is one variable. If you have various timeseries vectors x, y, z, ... pass them like StateSpaceSet(x, y, z, ...). You can use columns(dataset) to obtain the reverse, i.e. all columns of the dataset in a tuple.

source

Output data from RecurrenceMicrostatesAnalysis.jl

When computing the RMA distribution, RecurrenceMicrostatesAnalysis.jl returns a Probabilities structure. This type is provided by ComplexityMeasures.jl, allowing this package to interoperate naturally with its tools and workflows.

ComplexityMeasures.ProbabilitiesType
Probabilities <: Array{<:AbstractFloat, N}
Probabilities(probs::Array [, outcomes [, dimlabels]]) → p
Probabilities(counts::Counts [, outcomes [, dimlabels]]) → p

Probabilities stores an N-dimensional array of probabilities, while ensuring that the array sums to 1 (normalized probability mass). In most cases the array is a standard vector. p itself can be manipulated and iterated over, just like its stored array.

The probabilities correspond to outcomes that describe the axes of the array. If p isa Probabilities, then p.outcomes[i] is an an abstract vector containing the outcomes along the i-th dimension. The outcomes have the same ordering as the probabilities, so that p[i][j] is the probability for outcome p.outcomes[i][j]. The dimensions of the array are named, and can be accessed by p.dimlabels, where p.dimlabels[i] is the label of the i-th dimension. Both outcomes and dimlabels are assigned automatically if not given. If the input is a set of Counts, and outcomes and dimlabels are not given, then the labels and outcomes are inherited from the counts.

Examples

julia> probs = [0.2, 0.2, 0.2, 0.2]; Probabilities(probs) # will be normalized to sum to 1
 Probabilities{Float64,1} over 4 outcomes
 Outcome(1)  0.25
 Outcome(2)  0.25
 Outcome(3)  0.25
 Outcome(4)  0.25
julia> c = Counts([12, 16, 12], ["out1", "out2", "out3"]); Probabilities(c)
 Probabilities{Float64,1} over 3 outcomes
 "out1"  0.3
 "out2"  0.4
 "out3"  0.3
source
ComplexityMeasures.CountsType
Counts <: Array{<:Integer, N}
Counts(counts [, outcomes [, dimlabels]]) → c

Counts stores an N-dimensional array of integer counts corresponding to a set of outcomes. This is typically called a "frequency table" or "contingency table".

If c isa Counts, then c.outcomes[i] is an abstract vector containing the outcomes along the i-th dimension, where c[i][j] is the count corresponding to the outcome c.outcomes[i][j], and c.dimlabels[i] is the label of the i-th dimension. Both labels and outcomes are assigned automatically if not given. c itself can be manipulated and iterated over like its stored array.

source