-3

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...

Tom
  • 1
  • 2
  • 1
    Assuming your input is a numpy array, what should be the output? This wouldn't be a valid array – mozway Mar 07 '22 at 14:04
  • I'm confused about how the vector interacts with the matrix. – erip Mar 07 '22 at 14:08
  • @erip for the first element you have `2.1` as a `lower bound` and `3.1` as an `upper bound` so you only end up with `3`. – Thekingis007 Mar 07 '22 at 14:09
  • Yes, and what about the other two elements in each of the vectors? – erip Mar 07 '22 at 14:43
  • For clarity, give any working solution, even if you don't think it's fastest – hpaulj Mar 07 '22 at 15:16
  • @hpaulj I could just loop through the rows and then take a condition based on my upper and lower bound.. but since that`s non-pythonic, I dont want to do that... I thought maybe there`s a way to do that for the whole matrix at once, not in a loop... – Tom Mar 07 '22 at 15:39
  • @mozway it`s a list, like you see in my question, i dont see your point – Tom Mar 07 '22 at 15:40
  • @Tom then you should probably stick to what you tried – mozway Mar 07 '22 at 15:49
  • Looping through the rows is VERY pythonic, especially when working with lists. All the more so if the result is lists of varying size. `numpy` (without loops) solutions best start with arrays, and produce "rectangular" arrays. – hpaulj Mar 07 '22 at 18:42

1 Answers1

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.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Thank you very much, also for your answer here: https://stackoverflow.com/questions/56260854/how-in-numpy-get-elements-of-matrix-between-two-indices-arrays , helped me a lot! – Tom Mar 08 '22 at 09:50