Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate difference each time the sign changes in a list of values

Ok let's imagine that I have a list of values like so:

list = [-0.23, -0.5, -0.3, -0.8, 0.3, 0.6, 0.8, -0.9, -0.4, 0.1, 0.6]

I would like to loop on this list and when the sign changes to get the absolute difference between the maximum (minimum if it's negative) of the first interval and maximum (minimum if it's negative) of the next interval.

For example on the previous list, we would like to have a result like so:

[1.6, 1.7, 1.5]

The tricky part is that it has to work also for lists like:

list = [0.12, -0.23, 0.52, 0.2, 0.6, -0.3, 0.4]

Which would return :

[0.35, 0.83, 0.9, 0.7]

It's tricky because some intervals are 1 value long, and I'm having difficulties with managing this.

How would you solve this with the least possible number of lines?


Here is my current code, but it's not working at the moment.

list is a list of 6 lists, where each of these 6 lists contains else a nan, else a np.array of 1024 values (the values I want to evaluate)

Hmax = []
for c in range(0,6):
    Hmax_tmp = []
    for i in range(len(list[c])):
        if(not np.isnan(list[c][i]).any()):
            zero_crossings = np.where(np.diff(np.sign(list[c][i])))[0]
            if(not zero_crossings[0] == 0):
                zero_crossings = [0] + zero_crossings.tolist() + [1023]
            diff = []
            for j in range(1,len(zero_crossings)-2):
                if
                diff.append(max(list[c][i][np.arange(zero_crossings[j-1],zero_crossings[j])].min(), list[c][i][np.arange(zero_crossings[j]+1,zero_crossings[j+1])].max(), key=abs) - max(list[c][i][np.arange(zero_crossings[j+1],zero_crossings[j+2])].min(), list[c][i][np.arange(zero_crossings[j+1],zero_crossings[j+2])].max(), key=abs))
            Hmax_tmp.append(np.max(diff))
        else:
            Hmax_tmp.append(np.nan)
    Hmax.append(Hmax_tmp)
like image 571
GeoffreyB Avatar asked Jan 08 '23 01:01

GeoffreyB


1 Answers

This type of grouping operation can be greatly simplified using itertools.groupby. For example:

>>> from itertools import groupby
>>> lst = [-0.23, -0.5, -0.3, -0.8, 0.3, 0.6, 0.8, -0.9, -0.4, 0.1, 0.6] # the list
>>> minmax = [min(v) if k else max(v) for k,v in groupby(lst, lambda a: a < 0)]
>>> [abs(j-i) for i,j in zip(minmax[:-1], minmax[1:])]
[1.6, 1.7000000000000002, 1.5]

And the second list:

>>> lst2 = [0.12, -0.23, 0.52, 0.2, 0.6, -0.3, 0.4] # the list
>>> minmax = [min(v) if k else max(v) for k,v in groupby(lst2, lambda a: a < 0)]
>>> [abs(j-i) for i,j in zip(minmax[:-1], minmax[1:])]
[0.35, 0.83, 0.8999999999999999, 0.7]

So here, the list is grouped into consecutive intervals of negative/positive values. The min/max is computed for each group and stored in a list minmax. Lastly, a list comprehension finds the differences.

Excuse the inexact representations of floating point numbers!

like image 175
Alex Riley Avatar answered Jan 14 '23 16:01

Alex Riley