dranobob - 4 months ago 22

Python Question

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.