Skip to content

Commit c5b4293

Browse files
committed
refactor: update ruff lint rules and fix tests
The old ` numpy.math ` module is replaced with `math`. Added numpy and doc-specific lint rules. Tests use `numpy.testing` instead of standard asserts with rounds
1 parent f2c6581 commit c5b4293

File tree

3 files changed

+73
-63
lines changed

3 files changed

+73
-63
lines changed

pyentrp/entropy.py

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import math
12
from collections import Counter
23

34
import numpy as np
45

56

6-
def time_delay_embedding(time_series, embedding_dimension, delay=1):
7-
"""
8-
Time-delayed embedding.
7+
def time_delay_embedding(time_series, embedding_dimension, delay):
8+
"""Calculate time-delayed embedding.
99
1010
Parameters
1111
----------
@@ -20,6 +20,7 @@ def time_delay_embedding(time_series, embedding_dimension, delay=1):
2020
-------
2121
embedded : ndarray
2222
The embedded time series with shape (n_times - (order - 1) * delay, order).
23+
2324
"""
2425
series_length = len(time_series)
2526
embedded_series = np.empty((embedding_dimension, series_length - (embedding_dimension - 1) * delay))
@@ -29,8 +30,7 @@ def time_delay_embedding(time_series, embedding_dimension, delay=1):
2930

3031

3132
def util_pattern_space(time_series, lag, dim):
32-
"""
33-
Create a set of sequences with given lag and dimension
33+
"""Create a set of sequences with a given lag and dimension.
3434
3535
Parameters
3636
----------
@@ -49,6 +49,7 @@ def util_pattern_space(time_series, lag, dim):
4949
Raises
5050
------
5151
ValueError: If the lag is less than 1 or the result matrix exceeds the size limit.
52+
5253
"""
5354
n = len(time_series)
5455

@@ -66,8 +67,7 @@ def util_pattern_space(time_series, lag, dim):
6667

6768

6869
def util_granulate_time_series(time_series, scale):
69-
"""
70-
Extract coarse-grained time series
70+
"""Extract coarse-grained time series.
7171
7272
Parameters
7373
----------
@@ -79,7 +79,8 @@ def util_granulate_time_series(time_series, scale):
7979
Returns
8080
-------
8181
cts : np.ndarray
82-
Array of coarse-grained time series with given scale factor
82+
Array of coarse-grained time series with a given scale factor
83+
8384
"""
8485
if not isinstance(time_series, np.ndarray):
8586
time_series = np.array(time_series)
@@ -91,8 +92,7 @@ def util_granulate_time_series(time_series, scale):
9192

9293

9394
def shannon_entropy(time_series):
94-
"""
95-
Return the Shannon Entropy of the sample data.
95+
"""Calculate Shannon Entropy of the sample data.
9696
9797
Parameters
9898
----------
@@ -103,6 +103,7 @@ def shannon_entropy(time_series):
103103
-------
104104
ent: float
105105
The Shannon Entropy as float value
106+
106107
"""
107108
if isinstance(time_series, str):
108109
# Calculate frequency counts
@@ -130,11 +131,10 @@ def shannon_entropy(time_series):
130131

131132

132133
def sample_entropy(time_series, sample_length, tolerance=None):
133-
"""
134-
Calculates the sample entropy of degree m of a time_series.
134+
"""Calculate the sample entropy of degree m of a time_series.
135135
136136
This method uses Chebyshev norm.
137-
It is quite fast for random data, but can be slower is there is
137+
It is quite fast for random data but can be slower is there is
138138
structure in the input time series.
139139
140140
Parameters
@@ -150,7 +150,7 @@ def sample_entropy(time_series, sample_length, tolerance=None):
150150
-------
151151
sampen: np.ndarray
152152
Array of Sample Entropies SE.
153-
SE[k] is ratio `#templates of length k+1` / `#templates of length k`
153+
SE[k] is the ratio `#templates of length k+1` / `#templates of length k`
154154
where `#templates of length 0` = n*(n - 1) / 2, by definition
155155
156156
Notes
@@ -162,6 +162,7 @@ def sample_entropy(time_series, sample_length, tolerance=None):
162162
.. [1] http://en.wikipedia.org/wiki/Sample_Entropy
163163
.. [2] http://physionet.incor.usp.br/physiotools/sampen/
164164
.. [3] Madalena Costa, Ary Goldberger, CK Peng. Multiscale entropy analysis of biological signals
165+
165166
"""
166167
if not isinstance(time_series, np.ndarray):
167168
time_series = np.array(time_series)
@@ -177,7 +178,7 @@ def sample_entropy(time_series, sample_length, tolerance=None):
177178
# N_temp[k] holds matches templates of length k
178179
N_temp = np.zeros(sample_length + 2)
179180

180-
# Templates of length 0 matches by definition:
181+
# Templates of length 0 match by definition:
181182
N_temp[0] = n * (n - 1) / 2
182183

183184
for i in range(n - sample_length - 1):
@@ -195,9 +196,7 @@ def sample_entropy(time_series, sample_length, tolerance=None):
195196

196197

197198
def multiscale_entropy(time_series, sample_length, tolerance=None, maxscale=None):
198-
"""
199-
Calculate the Multiscale Entropy of the given time series considering
200-
different time-scales of the time series.
199+
"""Calculate Multiscale Entropy considering different time-scales of the time series.
201200
202201
Parameters
203202
----------
@@ -219,6 +218,7 @@ def multiscale_entropy(time_series, sample_length, tolerance=None, maxscale=None
219218
----------
220219
.. [1] http://en.pudn.com/downloads149/sourcecode/math/detail646216_en.html
221220
Can be viewed at https://web.archive.org/web/20170207221539/http://en.pudn.com/downloads149/sourcecode/math/detail646216_en.html
221+
222222
"""
223223
if tolerance is None:
224224
tolerance = 0.1 * np.std(time_series)
@@ -234,12 +234,11 @@ def multiscale_entropy(time_series, sample_length, tolerance=None, maxscale=None
234234

235235

236236
def permutation_entropy(time_series, order=3, delay=1, normalize=False):
237-
"""
238-
Permutation Entropy.
237+
"""Calculate Permutation Entropy.
239238
240239
Parameters
241240
----------
242-
time_series : list | np.array
241+
time_series : list | np.ndarray
243242
Time series
244243
order : int
245244
Order of permutation entropy
@@ -286,6 +285,7 @@ def permutation_entropy(time_series, order=3, delay=1, normalize=False):
286285
>>> # Return a value comprised between 0 and 1.
287286
>>> print(permutation_entropy(x, order=3, normalize=True))
288287
0.589
288+
289289
"""
290290
x = np.array(time_series)
291291
hashmult = np.power(order, np.arange(order))
@@ -299,13 +299,13 @@ def permutation_entropy(time_series, order=3, delay=1, normalize=False):
299299
p = np.true_divide(c, c.sum())
300300
pe = -np.multiply(p, np.log2(p)).sum()
301301
if normalize:
302-
pe /= np.log2(np.math.factorial(order))
302+
factorial = math.factorial(order)
303+
pe /= np.log2(factorial)
303304
return pe
304305

305306

306307
def multiscale_permutation_entropy(time_series, m, delay, scale):
307-
"""
308-
Calculate the Multiscale Permutation Entropy
308+
"""Calculate the Multiscale Permutation Entropy.
309309
310310
Parameters
311311
----------
@@ -328,6 +328,7 @@ def multiscale_permutation_entropy(time_series, m, delay, scale):
328328
.. [1] Francesco Carlo Morabito et al. Multivariate Multi-Scale Permutation Entropy for
329329
Complexity Analysis of Alzheimer`s Disease EEG. www.mdpi.com/1099-4300/14/7/1186
330330
.. [2] http://www.mathworks.com/matlabcentral/fileexchange/37288-multiscale-permutation-entropy-mpe/content/MPerm.m
331+
331332
"""
332333
mspe = np.empty(scale)
333334
for i in range(scale):
@@ -337,11 +338,10 @@ def multiscale_permutation_entropy(time_series, m, delay, scale):
337338

338339

339340
def weighted_permutation_entropy(time_series, order=2, delay=1, normalize=False):
340-
"""
341-
Calculate the weighted permutation entropy. Weighted permutation
342-
entropy captures the information in the amplitude of a signal where
343-
standard permutation entropy only measures the information in the
344-
ordinal pattern, "motif".
341+
"""Calculate the weighted permutation entropy.
342+
343+
Weighted permutation entropy captures the information in the amplitude of a signal where
344+
standard permutation entropy only measures the information in the ordinal pattern, "motif".
345345
346346
Parameters
347347
----------
@@ -385,6 +385,7 @@ def weighted_permutation_entropy(time_series, order=2, delay=1, normalize=False)
385385
>>> # Return a value comprised between 0 and 1.
386386
>>> print(permutation_entropy(x, order=3, normalize=True))
387387
0.547
388+
388389
"""
389390
x = time_delay_embedding(time_series, embedding_dimension=order, delay=delay)
390391

@@ -406,14 +407,13 @@ def weighted_permutation_entropy(time_series, order=2, delay=1, normalize=False)
406407
wpe = -np.dot(pw, b)
407408

408409
if normalize:
409-
wpe /= np.log2(np.math.factorial(order))
410+
wpe /= np.log2(math.factorial(order))
410411

411412
return wpe
412413

413414

414415
def composite_multiscale_entropy(time_series, sample_length, scale, tolerance=None):
415-
"""
416-
Composite Multiscale Entropy of the given time series
416+
"""Calculate Composite Multiscale Entropy.
417417
418418
Parameters
419419
----------
@@ -435,6 +435,7 @@ def composite_multiscale_entropy(time_series, sample_length, scale, tolerance=No
435435
----------
436436
.. [1] Wu, Shuen-De, et al. "Time series analysis using
437437
composite multiscale entropy." Entropy 15.3 (2013): 1069-1084.
438+
438439
"""
439440
if tolerance is None:
440441
tolerance = 0.1 * np.std(time_series)

pyproject.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ numpy = ">=1.26,<3.0"
1515

1616

1717
[tool.poetry.group.dev.dependencies]
18-
ruff = ">=0.5.0,<0.5.1"
1918
black = ">=23.3,<25.0"
2019
codecov = "^2.1.13"
2120
commitizen = "^3.2.2"
2221
pre-commit = "^3.3.2"
22+
ruff = ">=0.5.0,<0.5.1"
2323

2424

2525
[tool.commitizen]
@@ -102,4 +102,15 @@ select = [
102102
"PGH",
103103
# Ruff-specific rules
104104
"RUF",
105+
# NumPy-specific rules
106+
"NPY",
107+
# pydocstyle
108+
"D",
105109
]
110+
ignore = [
111+
"D100", "D104",
112+
"D203", "D213"
113+
]
114+
115+
[tool.ruff.lint.per-file-ignores]
116+
"**/{tests}/*" = ["D101", "D102", "D103"]

tests/test_entropy.py

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
from pyentrp import entropy as ent
66

7-
np.random.seed(1234567)
8-
7+
rng = np.random.default_rng(1234567)
98

109
TIME_SERIES = [1, 1, 1, 2, 3, 4, 5]
1110
TIME_SERIES_STRING = "1112345"
@@ -22,15 +21,15 @@
2221

2322
PERM_ENTROPY_BANDT = [4, 7, 9, 10, 6, 11, 3]
2423

25-
RANDOM_TIME_SERIES = np.random.rand(1000)
24+
RANDOM_TIME_SERIES = rng.random(1000)
2625

2726

2827
class TestEntropy(unittest.TestCase):
2928
def test_shannon_entropy_string(self):
30-
self.assertEqual(round(ent.shannon_entropy(TIME_SERIES_STRING), 5), SHANNON_ENTROPY)
29+
np.testing.assert_allclose(ent.shannon_entropy(TIME_SERIES_STRING), SHANNON_ENTROPY, rtol=1e-5)
3130

3231
def test_shannon_entropy_numerical(self):
33-
self.assertEqual(round(ent.shannon_entropy(TIME_SERIES), 5), SHANNON_ENTROPY)
32+
np.testing.assert_allclose(ent.shannon_entropy(TIME_SERIES), SHANNON_ENTROPY, rtol=1e-5)
3433

3534
def test_sample_entropy(self):
3635
ts = TS_SAMPLE_ENTROPY
@@ -42,49 +41,48 @@ def test_multiscale_entropy(self):
4241
multi_scale_entropy = ent.multiscale_entropy(RANDOM_TIME_SERIES, 4, maxscale=4)
4342
np.testing.assert_allclose(
4443
multi_scale_entropy,
45-
np.array([2.52572864, 2.31911439, 1.65292302, 1.86075234]),
44+
np.array([3.178054, 3.178054, 2.890372, 3.401197]),
45+
rtol=1e-6,
4646
)
4747

4848
def test_permutation_entropy(self):
49-
self.assertEqual(
50-
np.round(ent.permutation_entropy(PERM_ENTROPY_BANDT, order=2, delay=1), 3),
49+
np.testing.assert_allclose(
50+
ent.permutation_entropy(PERM_ENTROPY_BANDT, order=2, delay=1),
5151
0.918,
52+
rtol=1e-3,
5253
)
53-
self.assertEqual(
54-
np.round(ent.permutation_entropy(PERM_ENTROPY_BANDT, order=3, delay=1), 3),
54+
55+
np.testing.assert_allclose(
56+
ent.permutation_entropy(PERM_ENTROPY_BANDT, order=3, delay=1),
5557
1.522,
58+
rtol=1e-3,
5659
)
60+
5761
# Assert that a fully random vector has an entropy of 0.99999...
58-
self.assertEqual(
59-
np.round(
60-
ent.permutation_entropy(RANDOM_TIME_SERIES, order=3, delay=1, normalize=True),
61-
3,
62-
),
62+
np.testing.assert_allclose(
63+
ent.permutation_entropy(RANDOM_TIME_SERIES, order=3, delay=1, normalize=True),
6364
0.999,
65+
rtol=1e-3,
6466
)
6567

6668
def test_weighted_permutation_entropy(self):
67-
self.assertEqual(
68-
np.round(
69-
ent.weighted_permutation_entropy(PERM_ENTROPY_BANDT, order=2, delay=1),
70-
3,
71-
),
69+
np.testing.assert_allclose(
70+
ent.weighted_permutation_entropy(PERM_ENTROPY_BANDT, order=2, delay=1),
7271
0.913,
72+
rtol=1e-3,
7373
)
74-
self.assertEqual(
75-
np.round(
76-
ent.weighted_permutation_entropy(PERM_ENTROPY_BANDT, order=3, delay=1),
77-
3,
78-
),
74+
75+
np.testing.assert_allclose(
76+
ent.weighted_permutation_entropy(PERM_ENTROPY_BANDT, order=3, delay=1),
7977
1.414,
78+
rtol=1e-3,
8079
)
80+
8181
# Assert that a fully random vector has an entropy of 0.99999...
82-
self.assertEqual(
83-
np.round(
84-
ent.weighted_permutation_entropy(RANDOM_TIME_SERIES, order=3, delay=1, normalize=True),
85-
3,
86-
),
82+
np.testing.assert_allclose(
83+
ent.weighted_permutation_entropy(RANDOM_TIME_SERIES, order=3, delay=1, normalize=True),
8784
0.999,
85+
rtol=1e-3,
8886
)
8987

9088
def test_multiscale_permutation_entropy(self):

0 commit comments

Comments
 (0)