3

Is there a more numpythonic way to do this?

#example arrays
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7], dtype=np.float32)
values = np.array([0.2, 3.0, 1.5])

#get the indices where each value falls between values in arr
between = [np.nonzero(i > arr)[0][-1] for i in values]
0

2 Answers 2

3

For sorted arr, we can use np.searchsorted for performance -

In [67]: np.searchsorted(arr,values)-1
Out[67]: array([0, 2, 1])

Timings on large dataset -

In [81]: np.random.seed(0)
    ...: arr = np.unique(np.random.randint(0,10000, 10000))
    ...: values = np.random.randint(0,10000, 1000)

# @Andy L.'s soln
In [84]: %timeit np.argmin(values > arr[:,None], axis=0) - 1
10 loops, best of 3: 28.2 ms per loop

# Original soln
In [82]: %timeit [np.nonzero(i > arr)[0][-1] for i in values]
100 loops, best of 3: 8.68 ms per loop

# From this post
In [83]: %timeit np.searchsorted(arr,values)-1
10000 loops, best of 3: 57.8 µs per loop
Sign up to request clarification or add additional context in comments.

1 Comment

Nice solution and timing :) +1
1

Use broadcast and argmin

np.argmin(values > arr[:,None], axis=0) - 1

Out[32]: array([0, 2, 1], dtype=int32)

Note: I assume arr is monotonic increasing as in the sample

2 Comments

That seems to do the trick. I'm not sure I understand how that works. I'm not familiar with using the slice with "None" [:,None]
@RichColburn: it is a short way of adding/expand an addition dimension to an array to use with numpy broadcasting. It is equivalent to np.expand_dims(arr, axis=1). Read docs on expand_dims for more info(note: newaxis in the docs of expand_dims is just alias of None): docs.scipy.org/doc/numpy/reference/generated/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.