From 79b404043d9b8d1f9baee091d8fc9c083476d516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20Sch=C3=B6lzel?= Date: Fri, 24 Jan 2020 17:40:13 +0100 Subject: [PATCH 1/2] refactors sample entropy for more readability --- MultiscaleEntropy/mse.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/MultiscaleEntropy/mse.py b/MultiscaleEntropy/mse.py index 1e26035..2bc9199 100644 --- a/MultiscaleEntropy/mse.py +++ b/MultiscaleEntropy/mse.py @@ -90,20 +90,33 @@ def sample_entropy(x, m=[2], r=[0.15], sd=None, return_type='dict', safe_mode=Fa for mm in tmp_m: count[mm] = 0 + def similar_runs(data, offset, end, tolerance): + ''' + Yields start and length of all runs of pairs data[x], data[x+offset] + where abs(data[x] - data[x+offset]) < tolerance for the whole run. + + I.e. a returned value of (k, n) means that + abs(data[x+i] - data[x+offset+i]) < tolerance for k <= i < k+n. + ''' + run_length = 0 + for i in range(end): + if abs(data[i] - data[i + offset]) < tolerance: + run_length += 1 + elif run_length > 0: + yield (i - run_length, run_length) + run_length = 0 + if run_length > 0: + yield (end - run_length, run_length) + + # j = offset of template vector B w.r.t. template vector A for j in range(1, len(x)-min(m)+1): - cont = 0 - for inc in range(0, len(x)-j): - if abs(x[inc]-x[j+inc]) < threshold: - cont += 1 - elif cont > 0: - for mm in tmp_m: - tmp = cont - mm + 1 - count[mm] += tmp if tmp > 0 else 0 - cont = 0 - if cont > 0: + for start, length in similar_runs(x, j, len(x) - j, threshold): + # how many vectors of length max_m fit between start of run + # and end of data? for mm in tmp_m: - tmp = cont - mm + 1 - count[mm] += tmp if tmp > 0 else 0 + # how many vectors of length mm fit within the run? + count_mm = length - mm + 1 + count[mm] += max(0, count_mm) for mm in m: if count[mm+1] == 0 or count[mm] == 0: t = len(x)-mm+1 From 46063f818cafc9a0f9ea63b9853044905aced9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20Sch=C3=B6lzel?= Date: Fri, 24 Jan 2020 23:47:05 +0100 Subject: [PATCH 2/2] bugfix: sample entropy should only count template vectors that can be followed for full length (m+1) reference: Richman and Moorman (2000), page H2042 --- MultiscaleEntropy/mse.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MultiscaleEntropy/mse.py b/MultiscaleEntropy/mse.py index 2bc9199..3fd2826 100644 --- a/MultiscaleEntropy/mse.py +++ b/MultiscaleEntropy/mse.py @@ -87,6 +87,7 @@ def sample_entropy(x, m=[2], r=[0.15], sd=None, return_type='dict', safe_mode=Fa tmp_m.append(mm) tmp_m.append(mm+1) tmp_m = list(set(tmp_m)) + max_m = max(tmp_m) for mm in tmp_m: count[mm] = 0 @@ -109,13 +110,15 @@ def similar_runs(data, offset, end, tolerance): yield (end - run_length, run_length) # j = offset of template vector B w.r.t. template vector A - for j in range(1, len(x)-min(m)+1): + for j in range(1, len(x)-max_m+1): for start, length in similar_runs(x, j, len(x) - j, threshold): # how many vectors of length max_m fit between start of run # and end of data? + max_count = len(x) - (start + j + max_m - 1) for mm in tmp_m: # how many vectors of length mm fit within the run? count_mm = length - mm + 1 + count_mm = min(count_mm, max_count) count[mm] += max(0, count_mm) for mm in m: if count[mm+1] == 0 or count[mm] == 0: