ConSod
ConSod

Reputation: 801

Count elements if over a certain value

I have a list of elements with certain values of type float. I want to iterate over the elements and count them if they are over a certain value, but also only count them if they appear over the treshold value a minimum_count of times. So for example, if a have following input:

list_of_values = [2.0, 2.0, 2.0, 2.0, 0, 0, 2.0, 2.0, 2.0, 0, 0]
treshold_value = 1.0
minimum_count = 4

the answer should be 4, since the treshold_value 1.0 is consecutively exceeded 4 times only at indexes 0-3. I now have the code below,

for value in list_of_values:
    if value >= treshold_value:
        counter += 1
    if counter >= (minimum_count):
        time_use += 1
    if value < min_treshold_value:
        counter = 0
print(time_use)

I know there should be some pythonic way to achieve this :)

Edit: The sum of all consecutive subsequence values over the threshold should be counted.

Upvotes: 3

Views: 665

Answers (4)

mhawke
mhawke

Reputation: 87084

You could use itertools.groupby() to help:

from itertools import groupby

def count_runs(list_of_values, threshold_value=1.0, minimum_count=4):
    count = 0
    for k, g in groupby(list_of_values, key=lambda x: x >= threshold_value):
        if k:
            g = list(g)
            if len(g) >= minimum_count:
                count += len(g)
    return count

>>> count_runs([2.0, 2.0, 2.0, 0.0, 0, 0, 2.0, 2.0, 2.0, 0, 0])
0
>>> count_runs([2.0, 2.0, 2.0, 2.0, 0, 0, 2.0, 2.0, 2.0, 0, 0])
4
>>> count_runs([2.0, 2.0, 2.0, 2.0, 0, 0, 3.0, 2.0, 2.0, 2.0, 10.0, 0, 0])
9

This will provide the count of the number of values that are above the threshold in groups of minimum_count or more. Note that it handles multiple groups that match the criteria.

For example the groupby() for the last example will return the following:

>>> list_of_values = [2.0, 2.0, 2.0, 2.0, 0, 0, 3.0, 2.0, 2.0, 2.0, 10.0, 0, 0]
>>> for k, g in groupby(list_of_values, key=lambda x: x >= threshold_value):
...     print(k, list(g))
... 
True [2.0, 2.0, 2.0, 2.0]
False [0, 0]
True [3.0, 2.0, 2.0, 2.0, 10.0]
False [0, 0]

Any group of 1 or more values >= the threshold will appear in a group with key True. Only those with a length >= the minimum count will be considered further, where its length will be tallied with other such groups.

This code can be written more succinctly, and far less readably, like this:

def count_runs(list_of_values, threshold_value=1.0, minimum_count=4):
    return sum(count for count in (len(list(g)) for k, g in groupby(list_of_values, key=lambda x: x >= threshold_value) if k) if count >= minimum_count)

Upvotes: 1

Eric Duminil
Eric Duminil

Reputation: 54233

It looks like you don't care about the order. In this case, groupby isn't correct because it only groups adjacent elements.

You could use a Counter and two list comprehensions to filter values:

list_of_values = [2.0, 2.0, 2.0, 2.0, 0, 0, 3.0, 2.0, 2.0, 2.0, 10.0, 0, 0]
threshold_value = 1.0
minimum_count = 4

from collections import Counter
counter = Counter([x for x in list_of_values if x > threshold_value])
print(counter)
# Counter({2.0: 7, 3.0: 1, 10.0: 1})
print([(x, count) for x, count in counter.items() if count > minimum_count])
# [(2.0, 7)]

Upvotes: 0

user2390182
user2390182

Reputation: 73460

The following use of groupby with a conditional generator and max with appropriate key function should work:

from itertools import groupby

len(max((list(g) for k, g in groupby(list_ov, key=lambda x: x > threshold) if k), key=len))

groupby groups an iterable by consecutive identical values wrt to the key function. It produces pairs of the key value and according sub-iterable.

Upvotes: 2

ddor254
ddor254

Reputation: 1628

just iterate over the list and create a dictionary with key = the float number and value = the number of times you encounter this number. and only add to dict floats that are greater then threshold . something like this:

d = {}
for f in   list_of_values :
    if f > treshold:
        if d.get(f,False):
             d[f] +=1
        else:
             d[f] = 1
max = 0
for k,v in d.iteritems():
    if v> max:
        max = v

return max

Upvotes: 0

Related Questions