我有一个值数组,我想根据哪个选项线性最接近的选择数组替换。
catch是在运行时定义的选项的大小。
import numpy as np
a = np.array([[0, 0, 0], [4, 4, 4], [9, 9, 9]])
choices = np.array([1, 5, 10])
如果选择的大小是静态的,我只需使用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]))
获得输出:
>>d
>>[[1, 1, 1], [5, 5, 5], [10, 10, 10]]
有没有办法在保留矢量化的同时更加动态地执行此操作。
答案 0 :(得分:3)
从remove
中减去选项,找到结果最小值的索引,替换。
a
将额外维度添加到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]]
>>>
,以便从a
的每个元素中减去choices
的每个元素。 a
在第三维broadcast对choices
This link has a decent graphic EricsBroadcastingDoc。 a
是(3,3,3)。 Index Array是一个非常好的解释,并在最后有一个图形的三维示例。
对于第二个例子:
b.shape
最终作业使用Integer Array Indexing或{{3}}。
在第二个示例中,请注意元素>>> 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]]
>>>
存在 tie ,其中一个或五个可能已被替换。
答案 1 :(得分:2)
更详细地解释wwii的excellent answer:
我们的想法是创建一个新维度,负责使用numpy broadcasting将a
的每个元素与choices
中的每个元素进行比较。使用ellipsis syntax:
a
中为任意数量的维度完成此操作
>>> b = np.abs(a[..., np.newaxis] - choices)
array([[[ 1, 5, 10],
[ 1, 5, 10],
[ 1, 5, 10]],
[[ 3, 1, 6],
[ 3, 1, 6],
[ 3, 1, 6]],
[[ 8, 4, 1],
[ 8, 4, 1],
[ 8, 4, 1]]])
沿您刚创建的轴(最后一个轴,标签为-1)取argmin
,为您提供要替换的choices
中所需的索引:
>>> np.argmin(b, axis=-1)
array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2]])
最终允许您从choices
中选择这些元素:
>>> d = choices[np.argmin(b, axis=-1)]
>>> d
array([[ 1, 1, 1],
[ 5, 5, 5],
[10, 10, 10]])
对于非对称形状:
让我们说a
形状(2, 5)
:
>>> a = np.arange(10).reshape((2, 5))
>>> a
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
然后你得到:
>>> b = np.abs(a[..., np.newaxis] - choices)
>>> b
array([[[ 1, 5, 10],
[ 0, 4, 9],
[ 1, 3, 8],
[ 2, 2, 7],
[ 3, 1, 6]],
[[ 4, 0, 5],
[ 5, 1, 4],
[ 6, 2, 3],
[ 7, 3, 2],
[ 8, 4, 1]]])
这很难理解,但它所说的是,b
已经形成:
>>> b.shape
(2, 5, 3)
前两个维度来自a
的形状,也是(2, 5)
。最后一个维度是您刚刚创建的维度。为了更好的主意:
>>> b[:, :, 0] # = abs(a - 1)
array([[1, 0, 1, 2, 3],
[4, 5, 6, 7, 8]])
>>> b[:, :, 1] # = abs(a - 5)
array([[5, 4, 3, 2, 1],
[0, 1, 2, 3, 4]])
>>> b[:, :, 2] # = abs(a - 10)
array([[10, 9, 8, 7, 6],
[ 5, 4, 3, 2, 1]])
请注意,对于每个b[:, :, i]
,a
与choices[i]
之间的绝对差异i = 1, 2, 3
。
希望这有助于更清楚地解释这一点。
答案 2 :(得分:2)
我爱broadcasting
并且自己也会这样做。但是,对于大型数组,我想建议使用np.searchsorted
的另一种方法来保持内存效率,从而实现性能优势,如此 -
def searchsorted_app(a, choices):
lidx = np.searchsorted(choices, a, 'left').clip(max=choices.size-1)
ridx = (np.searchsorted(choices, a, 'right')-1).clip(min=0)
cl = np.take(choices,lidx) # Or choices[lidx]
cr = np.take(choices,ridx) # Or choices[ridx]
mask = np.abs(a - cl) > np.abs(a - cr)
cl[mask] = cr[mask]
return cl
请注意,如果choices
中的元素未排序,我们需要使用sorter
添加其他参数np.searchsorted
。
运行时测试 -
In [160]: # Setup inputs
...: a = np.random.rand(100,100)
...: choices = np.sort(np.random.rand(100))
...:
In [161]: def broadcasting_app(a, choices): # @wwii's solution
...: return choices[np.argmin(np.abs(a[:,:,None] - choices),-1)]
...:
In [162]: np.allclose(broadcasting_app(a,choices),searchsorted_app(a,choices))
Out[162]: True
In [163]: %timeit broadcasting_app(a, choices)
100 loops, best of 3: 9.3 ms per loop
In [164]: %timeit searchsorted_app(a, choices)
1000 loops, best of 3: 1.78 ms per loop
相关文章:Find elements of array one nearest to elements of array two