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]