dranobob - 7 months ago 40
Python Question

# How to select value from array that is closest to value in array using vectorization?

I have an array of values that I want to replace with from an array of choices based on which choice is linearly closest.

The catch is the size of the choices is defined at runtime.

``````import numpy as np
a = np.array([[0, 0, 0], [4, 4, 4], [9, 9, 9]])
choices = np.array([1, 5, 10])
``````

If choices was static in size, I would simply use np.where

``````d = np.where(np.abs(a - choices[0]) > np.abs(a - choices[1]),
np.where(np.abs(a - choices[0]) > np.abs(a - choices[2]), choices[0], choices[2]),
np.where(np.abs(a - choices[1]) > np.abs(a - choices[2]), choices[1], choices[2]))
``````

To get the output:

``````>>d
>>[[1, 1, 1], [5, 5, 5], [10, 10, 10]]
``````

Is there a way to do this more dynamically while still preserving the vectorization.

Answer

Subtract choices from `a`, find the index of the minimum of the result, substitute.

``````a = np.array([[0, 0, 0], [4, 4, 4], [9, 9, 9]])
choices = np.array([1, 5, 10])
b = a[:,:,None] - choices
np.absolute(b,b)
i = np.argmin(b, axis = -1)
a = choices[i]
print a

>>>
[[ 1  1  1]
[ 5  5  5]
[10 10 10]]

a = np.array([[0, 3, 0], [4, 8, 4], [9, 1, 9]])
choices = np.array([1, 5, 10])
b = a[:,:,None] - choices
np.absolute(b,b)
i = np.argmin(b, axis = -1)
a = choices[i]
print a

>>>
[[ 1  1  1]
[ 5 10  5]
[10  1 10]]
>>>
``````

The extra dimension was added to `a` so that each element of `choices` would be subtracted from each element of `a` - `choices` was broadcast against `a` in the third dimension, This link has a decent graphic. `b.shape` is (3,3,3). EricsBroadcastingDoc is a pretty good explanation and has a graphic 3-d example at the end.

For the second example:

``````>>> print b
[[[ 1  5 10]
[ 2  2  7]
[ 1  5 10]]

[[ 3  1  6]
[ 7  3  2]
[ 3  1  6]]

[[ 8  4  1]
[ 0  4  9]
[ 8  4  1]]]
>>> print i
[[0 0 0]
[1 2 1]
[2 0 2]]
>>>
``````

The final assignment uses an Index Array or Integer Array Indexing.

In the second example, notice that there was a tie for element `a[0,1]` , either one or five could have been substituted.