RecurrenceMicrostatesAnalysis.jl
RecurrenceMicrostatesAnalysis — Module
RecurrenceMicrostatesAnalysis.jl
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.
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 aMatrixcan be used as a substitute for aStateSpaceSet, this is not recommended, since theAbstractArraybackend 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.
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.StateSpaceSet — Type
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:
- By giving in each individual columns of the state space set as
Vector{<:Real}:StateSpaceSet(x, y, z, ...). - By giving in a matrix whose rows are the state space points:
StateSpaceSet(m). - By giving in directly a vector of vectors (state space points):
StateSpaceSet(v_of_v).
All constructors allow for two keywords:
containerwhich sets the type ofV(the type of inner vectors). At the moment options are onlySVector,MVector, orVector, and by defaultSVectoris used.nameswhich can be an iterable of lengthDwhose elements areSymbols. This allows assigning a name to each dimension and accessing the dimension by name, see below.namesisnothingif not given. UseStateSpaceSet(s; names)to add names to an existing sets.
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 theith point (returns anSVector)X[v1] == X[v1, :], returns aStateSpaceSetwith the points in those indices.X[:, j]gives thejth variable timeseries (or collection), asVectorX[v1, v2], X[:, v2]returns aStateSpaceSetwith the appropriate entries (first indices being "time"/point index, while second being variables)X[i, j]value of thejth variable, at theith 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.
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.Probabilities — Type
Probabilities <: Array{<:AbstractFloat, N}
Probabilities(probs::Array [, outcomes [, dimlabels]]) → p
Probabilities(counts::Counts [, outcomes [, dimlabels]]) → pProbabilities 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.25julia> c = Counts([12, 16, 12], ["out1", "out2", "out3"]); Probabilities(c)
Probabilities{Float64,1} over 3 outcomes
"out1" 0.3
"out2" 0.4
"out3" 0.3ComplexityMeasures.Counts — Type
Counts <: Array{<:Integer, N}
Counts(counts [, outcomes [, dimlabels]]) → cCounts 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.