Source code for neurokit2.complexity.utils_complexity_ordinalpatterns

import numpy as np

from .utils_complexity_embedding import complexity_embedding

[docs]
def complexity_ordinalpatterns(signal, delay=1, dimension=3, algorithm="quicksort", **kwargs):
"""**Find Ordinal Patterns for Permutation Procedures**

The seminal work by Bandt and Pompe (2002) introduced a symbolization approach to obtain a
sequence of ordinal patterns (permutations) from continuous data. It is used in
:func:permutation entropy <entropy_permutation> and its different variants.

Parameters
----------
signal : Union[list, np.array, pd.Series]
The signal (i.e., a time series) in the form of a vector of values.
delay : int
Time delay (often denoted *Tau* :math:\\tau, sometimes referred to as *lag*) in samples.
See :func:complexity_delay to estimate the optimal value for this parameter.
dimension : int
Embedding Dimension (*m*, sometimes referred to as *d* or *order*). See
:func:complexity_dimension to estimate the optimal value for this parameter.
algorithm : str
Can be "quicksort" (default) or "bubblesort" (used in Bubble Entropy).

Returns
-------
array
Ordinal patterns.
vector
Frequencies of each ordinal pattern.
dict

Examples
----------
Example given by Bandt and Pompe (2002):

.. ipython:: python

import neurokit2 as nk

signal = [4, 7, 9, 10, 6, 11, 3]

patterns, info = nk.complexity_ordinalpatterns(signal, delay=1, dimension=3)
patterns
info["Frequencies"]

.. ipython:: python

signal = [4, 7, 9, 10, 6, 5, 3, 6, 8, 9, 5, 1, 0]

patterns, info = nk.complexity_ordinalpatterns(signal, algorithm="bubblesort")
info["Frequencies"]

References
----------
* Bandt, C., & Pompe, B. (2002). Permutation entropy: a natural complexity measure for time
series. Physical review letters, 88(17), 174102.
* Manis, G., Aktaruzzaman, M. D., & Sassi, R. (2017). Bubble entropy: An entropy almost free of
parameters. IEEE Transactions on Biomedical Engineering, 64(11), 2711-2718.

"""
# Time-delay embedding
info = {"Embedded": complexity_embedding(signal, delay=delay, dimension=dimension)}

# Transform embedded into permutations matrix
if algorithm == "bubblesort":
info["Permutations"] = _bubblesort(info["Embedded"])
else:
info["Permutations"] = info["Embedded"].argsort(kind="quicksort")

# Count and get unique patterns
patterns, info["Uniques"], info["Frequencies"] = np.unique(
info["Permutations"],
axis=0,
return_inverse=True,
return_counts=True,
)

# Find all possible patterns (not needed for now)
# all_symbols = np.array(list(map(np.array, list(itertools.permutations(np.arange(delay * dimension))))))

# Relative Frequency
info["Frequencies"] = info["Frequencies"] / info["Frequencies"].sum()

return patterns, info

def _bubblesort(embedded):
"""
Manis, G., Aktaruzzaman, M. D., & Sassi, R. (2017). Bubble entropy: An entropy almost free of
parameters. IEEE Transactions on Biomedical Engineering, 64(11), 2711-2718.
"""
n, n_dim = np.shape(embedded)
swaps = np.zeros(n)
for y in range(n):
for t in range(n_dim - 1):
for kk in range(n_dim - t - 1):
if embedded[y, kk] > embedded[y, kk + 1]:
embedded[y, kk], embedded[y, kk + 1] = embedded[y, kk + 1], embedded[y, kk]
swaps[y] += 1
return swaps