选择在numpy中具有可变索引边界的数组元素

选择在numpy中具有可变索引边界的数组元素,numpy,Numpy,这可能是不可能的,因为中间数组将具有可变长度的行。 我试图完成的是为具有由边界数组分隔的ad索引的元素的数组赋值。例如: bounds = np.array([[1,2], [1,3], [1,4]]) array = np.zeros((3,4)) __assign(array, bounds, 1) 作业结束后,应在 array = [ [0, 1, 0, 0], [0, 1, 1, 0], [0, 1, 1, 1] ] 我在各种迭代中尝试过类似的方法,但都没有成

这可能是不可能的,因为中间数组将具有可变长度的行。 我试图完成的是为具有由边界数组分隔的ad索引的元素的数组赋值。例如:

bounds = np.array([[1,2], [1,3], [1,4]])
array = np.zeros((3,4))
__assign(array, bounds, 1)
作业结束后,应在

array = [
    [0, 1, 0, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 1]
]
我在各种迭代中尝试过类似的方法,但都没有成功:

ind = np.arange(array.shape[0])
array[ind, bounds[ind][0]:bounds[ind][1]] = 1
      

我试图避免循环,因为这个函数会被调用很多次。有什么想法吗?

我绝对不是Numpy专家,但从我能找到的不同阵列选项来看,这是我能找到的最快解决方案:

bounds = np.array([[1,2], [1,3], [1,4]])
array = np.zeros((3,4))
for i, x in enumerate(bounds):
    cols = slice(x[0], x[1]) 
    array[i, cols] = 1
在这里,我们遍历边界列表,并使用切片引用列

我尝试了下面的方法,首先构建一个列索引列表和一个行索引列表,但速度要慢得多。比如10秒加上我笔记本电脑上的vir 0.04秒,用于10000 x 10000阵列。我想切片会有很大的不同

bounds = np.array([[1,2], [1,3], [1,4]])
array = np.zeros((3,4))
cols = []
rows = []
for i, x in enumerate(bounds):
    cols += list(range(x[0], x[1])) 
    rows += (x[1] - x[0]) * [i]

# print(cols) [1, 1, 2, 1, 2, 3]
# print(rows) [0, 1, 1, 2, 2, 2]

array[rows, cols] = 1

纯NumPy方法解决此问题的一个问题是,不存在使用轴上另一个NumPy数组的边界来“切片”NumPy数组的方法。因此,生成的扩展边界最终成为一个可变长度的列表列表,如
[[1],[1,2],[1,2,3]
。然后您可以使用
np.eye
np.sum
over axis=0来获得所需的输出

bounds = np.array([[1,2], [1,3], [1,4]])

result = np.stack([np.sum(np.eye(4)[slice(*i)], axis=0) for i in bounds])
print(result)
我尝试了各种方法,从[start:stop]在一个NumPy的开始和停止数组中分割
np.eye(4)
,但遗憾的是,您需要一个迭代来完成这一点


编辑:另一种不用任何循环就可以以矢量化方式进行编辑的方法是-

def f(b):
    o = np.sum(np.eye(4)[b[0]:b[1]], axis=0)
    return o

np.apply_along_axis(f, 1, bounds)
def h(bounds):
    zz = np.zeros((len(bounds), bounds.max()))

    for z,b in zip(zz,bounds):
        z[b[0]:b[1]]=1
        
    return zz

h(bounds)
编辑:如果您正在寻找一个超快速解决方案,但可以容忍一个for循环,那么基于我的模拟,在该线程的所有答案中,最快的方法是-

def f(b):
    o = np.sum(np.eye(4)[b[0]:b[1]], axis=0)
    return o

np.apply_along_axis(f, 1, bounds)
def h(bounds):
    zz = np.zeros((len(bounds), bounds.max()))

    for z,b in zip(zz,bounds):
        z[b[0]:b[1]]=1
        
    return zz

h(bounds)

使用
numba.njit
decorator

import numpy as np
import numba



使用
numba.njit

CPU times: user 3 µs, sys: 1 µs, total: 4 µs
Wall time: 6.2 µs
CPU times: user 3.54 s, sys: 1.63 ms, total: 3.54 s
Wall time: 3.55 s

numba.njit

CPU times: user 3 µs, sys: 1 µs, total: 4 µs
Wall time: 6.2 µs
CPU times: user 3.54 s, sys: 1.63 ms, total: 3.54 s
Wall time: 3.55 s

OP要求一个没有循环的方法。作为一个临时解决方案,我实现了一个带切片的循环。我正在通过一个带有大数组(图像)的非线性回归算法运行这段代码因此,我希望它会产生相当大的影响,但我无法想出更好的解决方案。@AkshaySehgal他没有。他只是说他正在努力避免它。别误会我,我不是说你的解决方案错了,我是说它不完整。我的答案也是如此。与我的‘ind=np.arange(tsize))相比,使用切片确实节省了大约30%的时间[0])对于ind:timg[i,bounds[i][0]:bounds[i][1]=1` Akshay的zip解决方案稍微慢了一点,因此我接受了这一点,并继续讨论其余的性能瓶颈:D非常感谢大家。列表理解仍然是一个循环。您对此进行了基准测试吗?它比切片循环慢得多。请检查我的更新答案,不要使用列表理解或解释cit for loopsStill慢得多。问题的标准不是你自己决定的。OPs标准不是速度,但对于循环没有明确的标准。无论如何,在我的设备上,运行时有10纳秒的差异,这与提出问题的场景是不连续的。这个问题对任何可能的方法都是开放的在大型数据集上执行。我的直觉告诉我,在赋值过程中避免上下文切换和python解释器应该可以极大地提高性能,但分析代码是无可替代的。请检查我更新的解决方案。如果你同意for循环,我已经在我的答案中添加了一个非常快速的方法。如果不同意,请c看看我最后的第二个解决方案,它是矢量化的,但稍微慢一点。谢谢你的回答,但在测量性能后,它比循环通过ROW慢4倍。我将对此进行研究。我暂时不使用编译器,但根据性能,这可能是一个好主意。
CPU times: user 3.54 s, sys: 1.63 ms, total: 3.54 s
Wall time: 3.55 s