Python 使用每个矩阵行的可变范围对numpy.argmin搜索进行矢量化

Python 使用每个矩阵行的可变范围对numpy.argmin搜索进行矢量化,python,numpy,vectorization,Python,Numpy,Vectorization,有没有办法摆脱下面代码中的循环并用矢量化操作替换它 给定一个数据矩阵,对于每一行,我希望找到最小值的索引,该索引符合在单独数组中定义的范围(每行) 下面是一个例子: import numpy as np np.random.seed(10) # Values of interest, for this example a random 6 x 100 matrix data = np.random.random((6,100)) # For each row, define an inclu

有没有办法摆脱下面代码中的循环并用矢量化操作替换它

给定一个数据矩阵,对于每一行,我希望找到最小值的索引,该索引符合在单独数组中定义的范围(每行)

下面是一个例子:

import numpy as np
np.random.seed(10)

# Values of interest, for this example a random 6 x 100 matrix
data = np.random.random((6,100))

# For each row, define an inclusive min/max range
ranges = np.array([[0.3, 0.4],
                   [0.35, 0.5],
                   [0.45, 0.6],
                   [0.52, 0.65],
                   [0.6,  0.8],
                   [0.75,  0.92]])


# For each row, find the index of the minimum value that fits inside the given range
result = np.zeros(6).astype(np.int)
for i in xrange(6):
    ind = np.where((ranges[i][0] <= data[i]) & (data[i] <= ranges[i][1]))[0]
    result[i] = ind[np.argmin(data[i,ind])]

print result
# Result: [35  8 22  8 34 78]

print data[np.arange(6),result]
# Result: [ 0.30070006  0.35065639  0.45784951  0.52885388  0.61393513  0.75449247]
将numpy导入为np
np.随机种子(10)
#感兴趣的值,例如随机6 x 100矩阵
数据=np.random.random((6100))
#对于每一行,定义一个包含的最小/最大范围
ranges=np.数组([[0.3,0.4],
[0.35, 0.5],
[0.45, 0.6],
[0.52, 0.65],
[0.6,  0.8],
[0.75,  0.92]])
#对于每一行,找到适合给定范围的最小值的索引
结果=np.zero(6).astype(np.int)
对于x范围内的i(6):
ind=np.其中((范围[i][0]方法#1:使用和
np.最小值-

mask = (ranges[:,None,0] <= data) & (data <= ranges[:,None,1])
r,c = np.nonzero(mask)
cut_idx = np.unique(r, return_index=1)[1]
out = np.minimum.reduceat(data[mask], cut_idx)
方法#2:使用
广播
并用
nan
填充无效位置,然后使用
np.nanargmin
-

mask = (ranges[:,None,0] <= data) & (data <= ranges[:,None,1])
result = np.nanargmin(np.where(mask, data, np.nan), axis=1)
out = data[np.arange(6),result]
方法#4:这里还有一个可能的循环解决方案。我们的想法是对每行数据进行排序。然后,在
np.searchsorted
的帮助下,使用每行的两个范围限制来决定开始和停止索引。此外,我们将使用这些索引进行切片,然后获得最小值。受益于sl这样,我们将使用
视图
,因此在内存和性能方面都非常高效

实现看起来像这样-

out = np.zeros(6)
sdata = np.sort(data, axis=1)
for i in xrange(6):
    start = np.searchsorted(sdata[i], ranges[i,0])
    stop = np.searchsorted(sdata[i], ranges[i,1], 'right')    
    out[i] = np.min(sdata[i,start:stop])
此外,我们可以在实现之后以矢量化的方式获得这些开始、停止索引

根据for的建议,当我们处理的范围在给定
数据的限制范围内时,我们可以简单地使用起始指数-

out[i] = sdata[i, start]

假设范围内至少有一个值,您甚至不必担心上限:

result = np.empty(6)
for i in xrange(6):
    lt = (ranges[i,0] >= data[i]).sum() 
    result[i] = np.argpartition(data[i], lt)[lt]
实际上,您甚至可以使用
argpartition

lt = (ranges[:,None,0] >= data).sum(1)
result = np.argpartition(data, lt)[np.arange(data.shape[0]), lt]

当然,这只有在
data.shape[0]
For#4时才有效:不是
sdata[i,np.searchsorted(sdata[i],ranges[i,0])]
已经是最小值,除非它在边界之外吗?只要
where
测试该值,如果它超出边界,就返回
nan
。@DanielF不确定我找到了你。为什么
sdata[i,np.searchsorted(sdata[i],ranges[i,0])]
beminimum?在排序数组
sdata
中,我们正在寻找
ranges[i,0]
将位于其左侧的第一个索引。但
stop
需要编辑:
np.searchsorted(sdata[i],ranges[i,1],“right”)
覆盖此类已排序数据右侧的第一个索引。因为如果
sdata
已排序,
min(sdata[start:stop])
将始终是
sdata[start]
。实际上,如果所有值都低于下限,您现在拥有的将抛出一个错误,因为
start
stop
将是
sdata.shape[1]
@DanielF啊,是的!我知道了。我编辑了这篇文章来涵盖这一点。谢谢!@DanielF如果
数据中的所有值都低于起始范围,原始代码也不会工作,并且这种情况下的预期o/p也不会在文章中讨论。因此,在这一点上,我假设不必担心这种情况。如果所有
数据都用完了怎么办给定行的
range
?我还没有机会查找问题,但是当运行第一个示例时,我在这行得到一个索引越界错误:
result[i]=np.argpartition(data,lt)[lt]
…第二个示例成功了。是的,修复了这个问题。
result = np.empty(6)
for i in xrange(6):
    lt = (ranges[i,0] >= data[i]).sum() 
    result[i] = np.argpartition(data[i], lt)[lt]
lt = (ranges[:,None,0] >= data).sum(1)
result = np.argpartition(data, lt)[np.arange(data.shape[0]), lt]