From 3ffad1c9fccb36db0403dcc6b8301e0ec8d16a25 Mon Sep 17 00:00:00 2001 From: "E.Z." <86618956+PiethonProgram@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:35:10 -0400 Subject: [PATCH 1/9] Update fractal.py --- antropy/fractal.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/antropy/fractal.py b/antropy/fractal.py index 74a857a..5bdc5c3 100644 --- a/antropy/fractal.py +++ b/antropy/fractal.py @@ -183,14 +183,35 @@ def katz_fd(x, axis=-1): 1.0000 """ x = np.asarray(x) - dists = np.abs(np.diff(x, axis=axis)) - ll = dists.sum(axis=axis) - ln = np.log10(ll / dists.mean(axis=axis)) - aux_d = x - np.take(x, indices=[0], axis=axis) - d = np.max(np.abs(aux_d), axis=axis) - kfd = np.squeeze(ln / (ln + np.log10(d / ll))) + + # euclidian distance calculation + euclidean_distance = np.sqrt(1+np.square(np.diff(x, axis=axis))) + + # total and average path lengths + total_path_length = euclidean_distance.sum(axis=axis) + average_path_length = euclidean_distance.mean(axis=axis) + + # max distance from first to all + horizontal_diffs = np.arange(1, x.shape[axis]) + vertical_diffs = np.take(x, indices=np.arange(1, x.shape[axis]), axis=axis) - np.take(x, indices=[0], axis=axis) + + if axis == 1: # reshape if needed + horizontal_diffs = horizontal_diffs.reshape(1, -1) + elif axis == 0: + horizontal_diffs = horizontal_diffs.reshape(-1, 1) + + # Euclidean distance and max distance + distances = np.sqrt(np.square(horizontal_diffs) + np.square(vertical_diffs)) + max_distance = np.max(distances, axis=axis) + + # Katz Fractal Dimension Calculation + full_distance = np.log10(total_path_length / average_path_length) + kfd = np.squeeze(full_distance / (full_distance + np.log10(max_distance / total_path_length))) + + # ensure scalar output if not kfd.ndim: kfd = kfd.item() + return kfd From 65353239041fae0fada69977d5094cfd64e150d0 Mon Sep 17 00:00:00 2001 From: "E.Z." <86618956+PiethonProgram@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:36:06 -0400 Subject: [PATCH 2/9] Update utils.py --- antropy/tests/utils.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/antropy/tests/utils.py b/antropy/tests/utils.py index a8c4a04..5dee582 100644 --- a/antropy/tests/utils.py +++ b/antropy/tests/utils.py @@ -5,22 +5,15 @@ NORMAL_TS = np.random.normal(size=3000) RANDOM_TS_LONG = np.random.rand(6000) PURE_SINE = np.sin(2 * np.pi * 1 * np.arange(3000) / 100) +PURE_COSINE = np.cos(2 * np.pi * 1 * np.arange(3000) / 100) ARANGE = np.arange(3000) # Data types for which to test input array compatibility TEST_DTYPES = [ # floats - np.float16, - np.float32, - np.float64, - np.int8, + np.float16, np.float32, np.float64, np.int8, # ints - np.int16, - np.int32, - np.int64, + np.int16, np.int32, np.int64, # unsigned ints - np.uint8, - np.uint16, - np.uint32, - np.uint64, + np.uint8, np.uint16, np.uint32, np.uint64, ] From 049d9398ba6d3804d3e11a1749a0ca5721742baf Mon Sep 17 00:00:00 2001 From: "E.Z." <86618956+PiethonProgram@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:36:34 -0400 Subject: [PATCH 3/9] Update test_fractal.py --- antropy/tests/test_fractal.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/antropy/tests/test_fractal.py b/antropy/tests/test_fractal.py index ca1a69c..963b3c0 100644 --- a/antropy/tests/test_fractal.py +++ b/antropy/tests/test_fractal.py @@ -51,13 +51,17 @@ def test_petrosian_fd(self): assert_equal(aal(petrosian_fd, axis=1, arr=data), petrosian_fd(data)) assert_equal(aal(petrosian_fd, axis=0, arr=data), petrosian_fd(data, axis=0)) - def test_katz_fd(self): + def test_kfd(self): x_k = [0.0, 0.0, 2.0, -2.0, 0.0, -1.0, -1.0, 0.0] + x_straight = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0] + # 1D self.assertEqual(np.round(katz_fd(x_k), 3), 5.783) - # 2D data + self.assertEqual(np.round(katz_fd(x_straight), 3), 1) + # 2D assert_equal(aal(katz_fd, axis=1, arr=data), katz_fd(data)) assert_equal(aal(katz_fd, axis=0, arr=data), katz_fd(data, axis=0)) + def test_higuchi_fd(self): """Test for function `higuchi_fd`. Results have been tested against the MNE-features and pyrem packages. From 45dff05f1b623e6a65ead0a6a16ba4dc7019797e Mon Sep 17 00:00:00 2001 From: "E.Z." <86618956+PiethonProgram@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:57:31 -0400 Subject: [PATCH 4/9] Update test_fractal.py --- antropy/tests/test_fractal.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/antropy/tests/test_fractal.py b/antropy/tests/test_fractal.py index 963b3c0..ca1a69c 100644 --- a/antropy/tests/test_fractal.py +++ b/antropy/tests/test_fractal.py @@ -51,17 +51,13 @@ def test_petrosian_fd(self): assert_equal(aal(petrosian_fd, axis=1, arr=data), petrosian_fd(data)) assert_equal(aal(petrosian_fd, axis=0, arr=data), petrosian_fd(data, axis=0)) - def test_kfd(self): + def test_katz_fd(self): x_k = [0.0, 0.0, 2.0, -2.0, 0.0, -1.0, -1.0, 0.0] - x_straight = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0] - # 1D self.assertEqual(np.round(katz_fd(x_k), 3), 5.783) - self.assertEqual(np.round(katz_fd(x_straight), 3), 1) - # 2D + # 2D data assert_equal(aal(katz_fd, axis=1, arr=data), katz_fd(data)) assert_equal(aal(katz_fd, axis=0, arr=data), katz_fd(data, axis=0)) - def test_higuchi_fd(self): """Test for function `higuchi_fd`. Results have been tested against the MNE-features and pyrem packages. From fce21d0d4607eaf1874b6a0174ff20b00aeaa10f Mon Sep 17 00:00:00 2001 From: ethan Date: Mon, 30 Sep 2024 10:30:26 -0400 Subject: [PATCH 5/9] blacked --- antropy/entropy.py | 14 +++++++++++--- antropy/fractal.py | 13 +++++++++---- antropy/tests/test_entropy.py | 5 ++++- antropy/tests/test_fractal.py | 9 +++------ antropy/tests/utils.py | 14 +++++++++++--- antropy/utils.py | 5 ++++- setup.py | 3 ++- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/antropy/entropy.py b/antropy/entropy.py index 2e7c7a9..e147a85 100644 --- a/antropy/entropy.py +++ b/antropy/entropy.py @@ -1,4 +1,5 @@ """Entropy functions""" + import numpy as np from numba import jit, types from math import factorial, log @@ -123,7 +124,9 @@ def perm_entropy(x, order=3, delay=1, normalize=False): """ # If multiple delay are passed, return the average across all d if isinstance(delay, (list, np.ndarray, range)): - return np.mean([perm_entropy(x, order=order, delay=d, normalize=normalize) for d in delay]) + return np.mean( + [perm_entropy(x, order=order, delay=d, normalize=normalize) for d in delay] + ) x = np.array(x) ran_order = range(order) hashmult = np.power(order, ran_order) @@ -408,7 +411,10 @@ def _app_samp_entropy(x, order, r, metric="chebyshev", approximate=True): return phi -@jit((types.Array(types.float64, 1, "C", readonly=True), types.int32, types.float64), nopython=True) +@jit( + (types.Array(types.float64, 1, "C", readonly=True), types.int32, types.float64), + nopython=True, +) def _numba_sampen(sequence, order, r): """ Fast evaluation of the sample entropy using Numba. @@ -436,7 +442,9 @@ def _numba_sampen(sequence, order, r): prev_in_diff = int(abs(sequence[order] - sequence[offset + order]) >= r) for idx in range(1, size - offset - order): out_diff = int(abs(sequence[idx - 1] - sequence[idx + offset - 1]) >= r) - in_diff = int(abs(sequence[idx + order] - sequence[idx + offset + order]) >= r) + in_diff = int( + abs(sequence[idx + order] - sequence[idx + offset + order]) >= r + ) n_numerator += in_diff - out_diff n_denominator += prev_in_diff - out_diff prev_in_diff = in_diff diff --git a/antropy/fractal.py b/antropy/fractal.py index 5bdc5c3..d270bd1 100644 --- a/antropy/fractal.py +++ b/antropy/fractal.py @@ -1,4 +1,5 @@ """Fractal functions""" + import numpy as np from numba import jit, types from math import log, floor @@ -185,7 +186,7 @@ def katz_fd(x, axis=-1): x = np.asarray(x) # euclidian distance calculation - euclidean_distance = np.sqrt(1+np.square(np.diff(x, axis=axis))) + euclidean_distance = np.sqrt(1 + np.square(np.diff(x, axis=axis))) # total and average path lengths total_path_length = euclidean_distance.sum(axis=axis) @@ -193,9 +194,11 @@ def katz_fd(x, axis=-1): # max distance from first to all horizontal_diffs = np.arange(1, x.shape[axis]) - vertical_diffs = np.take(x, indices=np.arange(1, x.shape[axis]), axis=axis) - np.take(x, indices=[0], axis=axis) + vertical_diffs = np.take( + x, indices=np.arange(1, x.shape[axis]), axis=axis + ) - np.take(x, indices=[0], axis=axis) - if axis == 1: # reshape if needed + if axis == 1: # reshape if needed horizontal_diffs = horizontal_diffs.reshape(1, -1) elif axis == 0: horizontal_diffs = horizontal_diffs.reshape(-1, 1) @@ -206,7 +209,9 @@ def katz_fd(x, axis=-1): # Katz Fractal Dimension Calculation full_distance = np.log10(total_path_length / average_path_length) - kfd = np.squeeze(full_distance / (full_distance + np.log10(max_distance / total_path_length))) + kfd = np.squeeze( + full_distance / (full_distance + np.log10(max_distance / total_path_length)) + ) # ensure scalar output if not kfd.ndim: diff --git a/antropy/tests/test_entropy.py b/antropy/tests/test_entropy.py index 3d900a8..e8dc376 100644 --- a/antropy/tests/test_entropy.py +++ b/antropy/tests/test_entropy.py @@ -1,4 +1,5 @@ """Test entropy functions.""" + import unittest import numpy as np from numpy.testing import assert_equal @@ -48,7 +49,9 @@ def test_spectral_entropy(self): spectral_entropy(RANDOM_TS, SF_TS, method="fft") spectral_entropy(RANDOM_TS, SF_TS, method="welch") spectral_entropy(RANDOM_TS, SF_TS, method="welch", nperseg=400) - self.assertEqual(np.round(spectral_entropy(RANDOM_TS, SF_TS, normalize=True), 1), 0.9) + self.assertEqual( + np.round(spectral_entropy(RANDOM_TS, SF_TS, normalize=True), 1), 0.9 + ) self.assertEqual(np.round(spectral_entropy(PURE_SINE, 100), 2), 0.0) # 2D data params = dict(sf=SF_TS, normalize=True, method="welch", nperseg=100) diff --git a/antropy/tests/test_fractal.py b/antropy/tests/test_fractal.py index 963b3c0..5571fa6 100644 --- a/antropy/tests/test_fractal.py +++ b/antropy/tests/test_fractal.py @@ -1,4 +1,5 @@ """Test fractal dimension functions.""" + import unittest import numpy as np from numpy.testing import assert_equal @@ -51,17 +52,13 @@ def test_petrosian_fd(self): assert_equal(aal(petrosian_fd, axis=1, arr=data), petrosian_fd(data)) assert_equal(aal(petrosian_fd, axis=0, arr=data), petrosian_fd(data, axis=0)) - def test_kfd(self): + def test_katz_fd(self): x_k = [0.0, 0.0, 2.0, -2.0, 0.0, -1.0, -1.0, 0.0] - x_straight = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0] - # 1D self.assertEqual(np.round(katz_fd(x_k), 3), 5.783) - self.assertEqual(np.round(katz_fd(x_straight), 3), 1) - # 2D + # 2D data assert_equal(aal(katz_fd, axis=1, arr=data), katz_fd(data)) assert_equal(aal(katz_fd, axis=0, arr=data), katz_fd(data, axis=0)) - def test_higuchi_fd(self): """Test for function `higuchi_fd`. Results have been tested against the MNE-features and pyrem packages. diff --git a/antropy/tests/utils.py b/antropy/tests/utils.py index 5dee582..3221a58 100644 --- a/antropy/tests/utils.py +++ b/antropy/tests/utils.py @@ -11,9 +11,17 @@ # Data types for which to test input array compatibility TEST_DTYPES = [ # floats - np.float16, np.float32, np.float64, np.int8, + np.float16, + np.float32, + np.float64, + np.int8, # ints - np.int16, np.int32, np.int64, + np.int16, + np.int32, + np.int64, # unsigned ints - np.uint8, np.uint16, np.uint32, np.uint64, + np.uint8, + np.uint16, + np.uint32, + np.uint64, ] diff --git a/antropy/utils.py b/antropy/utils.py index ba06205..b88aa52 100644 --- a/antropy/utils.py +++ b/antropy/utils.py @@ -1,4 +1,5 @@ """Helper functions""" + import numpy as np from numba import jit from math import log, floor @@ -46,7 +47,9 @@ def _embed(x, order=3, delay=1): # pre-defiend an empty list to store numpy.array (concatenate with a list is faster) embed_signal_length = N - (order - 1) * delay # define the new signal length - indice = [[(i * delay), (i * delay + embed_signal_length)] for i in range(order)] + indice = [ + [(i * delay), (i * delay + embed_signal_length)] for i in range(order) + ] # generate a list of slice indice on input signal for i in range(order): # loop with the order diff --git a/setup.py b/setup.py index 111d40a..18e9b51 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,8 @@ _has_setuptools = True except ImportError: - from distutils.core import setup + pass + # from distutils.core import setup def check_dependencies(): From 7a4e3098d608254101e6ce3d1811dc62233d33e6 Mon Sep 17 00:00:00 2001 From: ethan Date: Mon, 30 Sep 2024 10:36:50 -0400 Subject: [PATCH 6/9] . --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 18e9b51..111d40a 100644 --- a/setup.py +++ b/setup.py @@ -17,8 +17,7 @@ _has_setuptools = True except ImportError: - pass - # from distutils.core import setup + from distutils.core import setup def check_dependencies(): From 51faba332a18b227d8040f00f7591097c240e312 Mon Sep 17 00:00:00 2001 From: ethan Date: Mon, 30 Sep 2024 11:36:47 -0400 Subject: [PATCH 7/9] katz_fd(x_k)==1.503 --- antropy/tests/test_fractal.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/antropy/tests/test_fractal.py b/antropy/tests/test_fractal.py index 5571fa6..40d17e5 100644 --- a/antropy/tests/test_fractal.py +++ b/antropy/tests/test_fractal.py @@ -7,7 +7,7 @@ from antropy import petrosian_fd, katz_fd, higuchi_fd, detrended_fluctuation -from utils import RANDOM_TS, NORMAL_TS, PURE_SINE, ARANGE, TEST_DTYPES +from utils import RANDOM_TS, NORMAL_TS, PURE_SINE, PURE_COSINE, ARANGE, TEST_DTYPES PPG_SIGNAL = np.array( [ @@ -54,10 +54,11 @@ def test_petrosian_fd(self): def test_katz_fd(self): x_k = [0.0, 0.0, 2.0, -2.0, 0.0, -1.0, -1.0, 0.0] - self.assertEqual(np.round(katz_fd(x_k), 3), 5.783) + self.assertEqual(np.round(katz_fd(x_k), 3), 1.503) # 2D data - assert_equal(aal(katz_fd, axis=1, arr=data), katz_fd(data)) - assert_equal(aal(katz_fd, axis=0, arr=data), katz_fd(data, axis=0)) + data_kfd = np.vstack((RANDOM_TS, NORMAL_TS, PURE_SINE, PURE_COSINE, ARANGE)) + assert_equal(aal(katz_fd, axis=1, arr=data_kfd), katz_fd(data_kfd)) + assert_equal(aal(katz_fd, axis=0, arr=data_kfd), katz_fd(data_kfd, axis=0)) def test_higuchi_fd(self): """Test for function `higuchi_fd`. From b93c22977d0eb68631676ad4c59d41c786b24981 Mon Sep 17 00:00:00 2001 From: ethan Date: Mon, 30 Sep 2024 11:38:50 -0400 Subject: [PATCH 8/9] black . --- antropy/entropy.py | 8 ++------ antropy/fractal.py | 10 ++++------ antropy/tests/test_entropy.py | 4 +--- antropy/utils.py | 4 +--- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/antropy/entropy.py b/antropy/entropy.py index e147a85..197da5c 100644 --- a/antropy/entropy.py +++ b/antropy/entropy.py @@ -124,9 +124,7 @@ def perm_entropy(x, order=3, delay=1, normalize=False): """ # If multiple delay are passed, return the average across all d if isinstance(delay, (list, np.ndarray, range)): - return np.mean( - [perm_entropy(x, order=order, delay=d, normalize=normalize) for d in delay] - ) + return np.mean([perm_entropy(x, order=order, delay=d, normalize=normalize) for d in delay]) x = np.array(x) ran_order = range(order) hashmult = np.power(order, ran_order) @@ -442,9 +440,7 @@ def _numba_sampen(sequence, order, r): prev_in_diff = int(abs(sequence[order] - sequence[offset + order]) >= r) for idx in range(1, size - offset - order): out_diff = int(abs(sequence[idx - 1] - sequence[idx + offset - 1]) >= r) - in_diff = int( - abs(sequence[idx + order] - sequence[idx + offset + order]) >= r - ) + in_diff = int(abs(sequence[idx + order] - sequence[idx + offset + order]) >= r) n_numerator += in_diff - out_diff n_denominator += prev_in_diff - out_diff prev_in_diff = in_diff diff --git a/antropy/fractal.py b/antropy/fractal.py index d270bd1..4f2e634 100644 --- a/antropy/fractal.py +++ b/antropy/fractal.py @@ -194,9 +194,9 @@ def katz_fd(x, axis=-1): # max distance from first to all horizontal_diffs = np.arange(1, x.shape[axis]) - vertical_diffs = np.take( - x, indices=np.arange(1, x.shape[axis]), axis=axis - ) - np.take(x, indices=[0], axis=axis) + vertical_diffs = np.take(x, indices=np.arange(1, x.shape[axis]), axis=axis) - np.take( + x, indices=[0], axis=axis + ) if axis == 1: # reshape if needed horizontal_diffs = horizontal_diffs.reshape(1, -1) @@ -209,9 +209,7 @@ def katz_fd(x, axis=-1): # Katz Fractal Dimension Calculation full_distance = np.log10(total_path_length / average_path_length) - kfd = np.squeeze( - full_distance / (full_distance + np.log10(max_distance / total_path_length)) - ) + kfd = np.squeeze(full_distance / (full_distance + np.log10(max_distance / total_path_length))) # ensure scalar output if not kfd.ndim: diff --git a/antropy/tests/test_entropy.py b/antropy/tests/test_entropy.py index e8dc376..5678d17 100644 --- a/antropy/tests/test_entropy.py +++ b/antropy/tests/test_entropy.py @@ -49,9 +49,7 @@ def test_spectral_entropy(self): spectral_entropy(RANDOM_TS, SF_TS, method="fft") spectral_entropy(RANDOM_TS, SF_TS, method="welch") spectral_entropy(RANDOM_TS, SF_TS, method="welch", nperseg=400) - self.assertEqual( - np.round(spectral_entropy(RANDOM_TS, SF_TS, normalize=True), 1), 0.9 - ) + self.assertEqual(np.round(spectral_entropy(RANDOM_TS, SF_TS, normalize=True), 1), 0.9) self.assertEqual(np.round(spectral_entropy(PURE_SINE, 100), 2), 0.0) # 2D data params = dict(sf=SF_TS, normalize=True, method="welch", nperseg=100) diff --git a/antropy/utils.py b/antropy/utils.py index b88aa52..10ac2e8 100644 --- a/antropy/utils.py +++ b/antropy/utils.py @@ -47,9 +47,7 @@ def _embed(x, order=3, delay=1): # pre-defiend an empty list to store numpy.array (concatenate with a list is faster) embed_signal_length = N - (order - 1) * delay # define the new signal length - indice = [ - [(i * delay), (i * delay + embed_signal_length)] for i in range(order) - ] + indice = [[(i * delay), (i * delay + embed_signal_length)] for i in range(order)] # generate a list of slice indice on input signal for i in range(order): # loop with the order From 56883b471d575eda651a50959ebd3e0b58241412 Mon Sep 17 00:00:00 2001 From: ethan Date: Thu, 10 Oct 2024 16:26:06 -0400 Subject: [PATCH 9/9] reformatted --- antropy/fractal.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/antropy/fractal.py b/antropy/fractal.py index 4f2e634..62abdb4 100644 --- a/antropy/fractal.py +++ b/antropy/fractal.py @@ -182,16 +182,12 @@ def katz_fd(x, axis=-1): >>> x = np.arange(1000) >>> print(f"{ant.katz_fd(x):.4f}") 1.0000 + euclidean_distance = np.sqrt(1 + np.square(np.diff(x, axis=axis))) """ x = np.asarray(x) - # euclidian distance calculation euclidean_distance = np.sqrt(1 + np.square(np.diff(x, axis=axis))) - # total and average path lengths - total_path_length = euclidean_distance.sum(axis=axis) - average_path_length = euclidean_distance.mean(axis=axis) - # max distance from first to all horizontal_diffs = np.arange(1, x.shape[axis]) vertical_diffs = np.take(x, indices=np.arange(1, x.shape[axis]), axis=axis) - np.take( @@ -205,13 +201,18 @@ def katz_fd(x, axis=-1): # Euclidean distance and max distance distances = np.sqrt(np.square(horizontal_diffs) + np.square(vertical_diffs)) - max_distance = np.max(distances, axis=axis) # Katz Fractal Dimension Calculation - full_distance = np.log10(total_path_length / average_path_length) - kfd = np.squeeze(full_distance / (full_distance + np.log10(max_distance / total_path_length))) + full_distance = np.log10(euclidean_distance.sum(axis=axis) / euclidean_distance.mean(axis=axis)) + + kfd = np.squeeze( + full_distance + / ( + full_distance + + np.log10(np.max(distances, axis=axis) / euclidean_distance.sum(axis=axis)) + ) + ) - # ensure scalar output if not kfd.ndim: kfd = kfd.item()