Source code for neurokit2.complexity.entropy_increment

import numpy as np
import pandas as pd

from .utils_complexity_embedding import complexity_embedding
from .entropy_shannon import entropy_shannon

[docs] def entropy_increment(signal, dimension=2, q=4, **kwargs): """**Increment Entropy (IncrEn) and its Multiscale variant (MSIncrEn)** Increment Entropy (IncrEn) quantifies the magnitudes of the variations between adjacent elements into ranks based on a precision factor *q* and the standard deviation of the time series. IncrEn is conceptually similar to :func:`permutation entropy <entropy_permutation>` in that it also uses the concepts of symbolic dynamics. In the IncrEn calculation, two letters are used to describe the relationship between adjacent elements in a time series. One letter represents the volatility direction, and the other represents the magnitude of the variation between the adjacent elements. The time series is reconstructed into vectors of *m* elements. Each element of each vector represents the increment between two neighbouring elements in the original time series. Each increment element is mapped to a word consisting of two letters (one letter represents the volatility direction, and the other represents the magnitude of the variation between the adjacent elements), and then, each vector is described as a symbolic (discrete) pattern. The :func:`Shannon entropy <entropy_shannon>` of the probabilities of independent patterns is then computed. Parameters ---------- signal : Union[list, np.array, pd.Series] The signal (i.e., a time series) in the form of a vector of values. dimension : int Embedding Dimension (*m*, sometimes referred to as *d* or *order*). See :func:`complexity_dimension` to estimate the optimal value for this parameter. q : float The quantifying resolution *q* represents the precision of *IncrEn*, with larger values indicating a higher precision, causing IncrEn to be more sensitive to subtle fluctuations. The IncrEn value increases with increasing *q*, until reaching a plateau. This property can be useful to selecting an optimal *q* value. **kwargs : optional Other keyword arguments, such as the logarithmic ``base`` to use for :func:`entropy_shannon`. Returns -------- incren : float The Increment Entropy of the signal. info : dict A dictionary containing additional information regarding the parameters used, such as the average entropy ``AvEn``. See Also -------- entropy_shannon, entropy_multiscale Examples ---------- .. ipython:: python import neurokit2 as nk # Simulate a Signal signal = nk.signal_simulate(duration=2, sampling_rate=200, frequency=[5, 6], noise=0.5) # IncrEn incren, _ = nk.entropy_increment(signal, dimension=3, q=2) incren # Multiscale IncrEn (MSIncrEn) @savefig p_entropy_increment1.png scale=100% msincren, _ = nk.entropy_multiscale(signal, method="MSIncrEn", show=True) @suppress plt.close() References ----------- * Liu, X., Jiang, A., Xu, N., & Xue, J. (2016). Increment entropy as a measure of complexity for time series. Entropy, 18(1), 22. * Liu, X., Jiang, A., Xu, N., & Xue, J. (2016). Correction on Liu, X.; Jiang, A.; Xu, N.; Xue, J. Increment Entropy as a Measure of Complexity for Time Series. Entropy 2016, 18, 22. Entropy, 18(4), 133. * Liu, X., Wang, X., Zhou, X., & Jiang, A. (2018). Appropriate use of the increment entropy for electrophysiological time series. Computers in Biology and Medicine, 95, 13-23. """ # Sanity checks if isinstance(signal, (np.ndarray, pd.DataFrame)) and signal.ndim > 1: raise ValueError( "Multidimensional inputs (e.g., matrices or multichannel data) are not supported yet." ) # Store parameters info = {"Dimension": dimension, "q": q} # Time-embedding of the consecutive differences ("increment series") embedded = complexity_embedding(np.diff(signal), dimension=dimension, **kwargs) # The sign indicates the direction of the volatility between the corresponding neighbouring # elements in the original time series; it takes values of 1, 0, or 1, indicating a rise, no # change, or a decline sign = np.sign(embedded) # The size describes the magnitude of the variation between these adjacent elements Temp = np.tile(np.std(embedded, axis=1, ddof=1, keepdims=True), (1, dimension)) size = np.minimum(q, np.floor(abs(embedded) * q / Temp)) size[np.any(Temp == 0, axis=1), :] = 0 # Each element in each vector is mapped to a word consisting of the sign and the size words = sign * size # Get probabilities of occurence freq = np.unique(words, axis=0) freq = [np.sum(~np.any(words - freq[k, :], axis=1)) for k in range(len(freq))] freq = np.array(freq) / np.sum(freq) # Compute entropy incren, _ = entropy_shannon(freq=freq, **kwargs) # Normalize incren = incren / (dimension - 1) return incren, info