'Get matrix entries based on upper and lower bound vectors?

so let`s say I have a matrix mat= [[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]] and a lower bound vector vector_low = [2.1,1.9,1.7] and upper bound vector vector_up = [3.1,3.5,4.1].

How do I get the values in the matrix in between the upper and lower bounds for every row?

Expected Output: [[3],[2,3],[2,3,4]] (it`s a list @mozway)

alternatively a vector with all of them would also do...

(Extra question: get the values of the matrix that are between the upper and lower bound, but rounded down/up to the next value in the matrix.. Expected Output: [[2,3,4],[1,2,3,4],[1,2,3,4,5]])

There should be a fast solution without loop, hope someone can help, thanks!

PS: In the end I just want to sum over the list entries, so the output format is not important...



Solution 1:[1]

I probably shouldn't indulge you since you haven't provided the code I asked for, but to satisfy my own curiosity, here my solution(s)

Your lists:

In [72]: alist = [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]
In [73]: low = [2.1,1.9,1.7]; up = [3.1,3.5,4.1]

A utility function:

In [74]: def between(row, l, u):
    ...:     return [i for i in row if l <= i <= u]

and the straightforward list comprehension solution - VERY PYTHONIC:

In [75]: [between(row, l, u) for row, l, u in zip(alist, low, up)]
Out[75]: [[3], [2, 3], [2, 3, 4]]

A numpy solutions requires starting with arrays:

In [76]: arr = np.array(alist)
In [77]: Low = np.array(low)
    ...: Up = np.array(up)

We can check the bounds with:

In [79]: Low[:, None] <= arr
Out[79]: 
array([[False, False,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True]])
In [80]: (Low[:, None] <= arr) & (Up[:,None] >= arr)
Out[80]: 
array([[False, False,  True, False, False, False],
       [False,  True,  True, False, False, False],
       [False,  True,  True,  True, False, False]])

Applying the mask to index arr produces a flat array of values:

In [81]: arr[_]
Out[81]: array([3, 2, 3, 2, 3, 4])

to get values by row, we still have to iterate:

In [82]: [row[mask] for row, mask in zip(arr, Out[80])]
Out[82]: [array([3]), array([2, 3]), array([2, 3, 4])]

For the small case I expect the list approach to be faster. For larger cases [81] will do better - IF we already have arrays. Creating arrays from the lists is not a time-trivial task.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hpaulj