I have a list of signals (representing consecutive mesures) :
signals = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
I consider a signal valid only if equal to the previous n mesures.
Eg. if we consider only 2 mesures for validation (n=2)
, the first time signals turns from 0 to 1 we consider it still 0 but the next mesure, if it's 1 again then we consider it is still valid and make it 1. Then we would need 2 mesures of 0 to turn it to 0 again, etc... Here signals are 0 and 1 for simplification but in my application they can be other integers.
Desired output :
# For n = 2:
valid_s = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
# For n = 3:
valid_s = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0]
# For n = 4:
valid_s = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0]
I was looking of a pythonesque one-liner way of doing it but can't seem to find the desired output. I tried something along the lines :
S = signals
# For n = 2
[S[i] if S[i] == S[i-1] else S[i-2] for i, _ in enumerate(S)]
# gives [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
# For n = 3
[S[i] if S[i] == S[i-1] == S[i-2] else S[i-3] for i, _ in enumerate(S)]
# gives [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
Edit : I'm open to numpy
if it makes it easier as it's already imported.
I don't think there is a good way to make this a one-liner / list comprehension. While you could use all
with a slice of the list to see whether the value is the same as the n
values before, I don't see a good way to determine which should be the last valid value in case it is not.
Instead, you could use a good-old "many-lines" for loop:
signals = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
n = 3
last_valid = 0
current = None
repeated = 0
res = []
for s in signals:
if s == current:
repeated += 1
else:
repeated = 1
current = s
if repeated >= n:
last_valid = s
res.append(last_valid)
Afterwards, res
is [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0]
Alternatively, a bit shorter, using itertools.groupby
; result is the same:
last_valid = 0
res = []
for k, g in itertools.groupby(signals):
m = len(list(g))
if m >= n:
res.extend([last_valid] * (n-1) + [k] * (m-n+1))
last_valid = k
else:
res.extend([last_valid] * m)
signal = [0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
def each(signal, n):
p = 0
ring = [ signal[0] ] * (n-1)
v = None
for x in signal:
if v is None or all(q == x for q in ring):
v = x
yield v
ring[p] = x
p = (p+1) % (n-1)
list(each(signal, 2))
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
But I reconsidered this and think that a pure iterative (less Pythonic) approach is probably more efficient. After completing my new approach I now think that it is the same idea as @tobias_k already implemented in his answer:
def each(signal, n):
current = signal[0]
next = None
for v in signal:
if v != current:
if v == next:
next_count += 1
else:
next_count = 1
next = v
if next_count >= n:
current = v
yield current
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With