编辑我保留了下面所面临的更复杂的问题,但是我的问题可以更好地总结如下。假设您有一个shapenp.take的数组,另一个shapeimg的数组,您希望使用它们创建shape(planes, rows)的新数组,其中lut。这可以通过以下花式索引实现:

In [4]: %timeit lut[np.arange(planes).reshape(-1, 1), img]
1000 loops, best of 3: 471 us per loop

但是,如果使用take和python循环而不是花哨的索引,那么可以极大地加快(planes, 256)的速度:
In [6]: %timeit for _ in (lut[j].take(img[j]) for j in xrange(planes)) : pass
10000 loops, best of 3: 59 us per loop

是否可以以某种方式重新排列out(planes, rows)以使整个操作在没有python循环的情况下发生,但使用out[p,j] = lut[p, img[p, j]](或其他方法)而不是传统的花式索引来保持速度优势?
原始问题
我有一组查找表(LUT),要在图像上使用。保存LUT的数组的形状为planes,图像的形状为lut。两者均为img,与LUT的numpy.take轴匹配。其思想是从LUT的第n个平面通过每个LUT运行图像的第n个平面。
如果my(planes, 256, n)(planes, rows, cols)如下:
planes, rows, cols, n = 3, 4000, 4000, 4
lut = np.random.randint(-2**31, 2**31 - 1,
                        size=(planes * 256 * n // 4,)).view('uint8')
lut = lut.reshape(planes, 256, n)
img = np.random.randint(-2**31, 2**31 - 1,
                    size=(planes * rows * cols // 4,)).view('uint8')
img = img.reshape(planes, rows, cols)

我可以在使用这种花哨的索引之后实现我现在的目标
out = lut[np.arange(planes).reshape(-1, 1, 1), img]

这给了我一个形状数组,其中包含了通过lut的第n个平面的第n个lut的第n个lut的第n个平面。
除此之外,一切都很好:
In [2]: %timeit lut[np.arange(planes).reshape(-1, 1, 1), img]
1 loops, best of 3: 5.65 s per loop

这是完全不可接受的,尤其是我有以下所有不好看的选择,使用dtype = 'uint8'比运行快得多:
单个平面上的单个LUT运行速度约为X70:
In [2]: %timeit np.take(lut[0, :, 0], img[0])
10 loops, best of 3: 78.5 ms per loop

在所有需要的组合中运行的python循环可以更快地完成X6:
In [2]: %timeit for _ in (np.take(lut[j, :, k], img[j]) for j in xrange(planes) for k in xrange(n)) : pass
1 loops, best of 3: 947 ms per loop

即使运行LUT和图像中的所有平面组合,然后丢弃不需要的平面也比花式索引快:
In [2]: %timeit np.take(lut, img, axis=1)[np.arange(planes), np.arange(planes)]
1 loops, best of 3: 3.79 s per loop

我能想到的最快的组合是在平面上迭代一个python循环并更快地完成x13:
In [2]: %timeit for _ in (np.take(lut[j], img[j], axis=0) for j in xrange(planes)) : pass
1 loops, best of 3: 434 ms per loop

当然,问题是,如果没有任何python循环,就无法使用256执行此操作吗?理想情况下,无论需要什么整形或调整大小都应该发生在LUT上,而不是图像上,但我愿意接受任何你可以想到的…

最佳答案

首先,我必须说我真的很喜欢你的问题。在不重新排列LUTIMG的情况下,以下解决方案起作用:

%timeit a=np.take(lut, img, axis=1)
# 1 loops, best of 3: 1.93s per loop

但从结果中,您必须查询对角线:a[0,0]、a[1,1]、a[2,2];才能得到您想要的。我试图找到一种方法,只对对角线元素进行索引,但仍然没有成功。
以下是重新排列您的LUTIMG的一些方法:
如果IMG中的索引为0-255,对于第一个平面,256-511对于第二个平面,512-767对于第三个平面,则以下内容适用,但这将阻止您使用'uint8',这可能是一个大问题…:
lut2 = lut.reshape(-1,4)
%timeit np.take(lut2,img,axis=0)
# 1 loops, best of 3: 716 ms per loop
# or
%timeit np.take(lut2, img.flatten(), axis=0).reshape(3,4000,4000,4)
# 1 loops, best of 3: 709 ms per loop

在我的机器中,您的解决方案仍然是最佳选择,而且非常充分,因为您只需要对角评估,即plane1-plane1、plane2-plane2和plane3-plane3:
%timeit for _ in (np.take(lut[j], img[j], axis=0) for j in xrange(planes)) : pass
# 1 loops, best of 3: 677 ms per loop

我希望这能给你一些更好的解决方案的见解。如果能用flatten()和类似于np.apply_over_axes()np.apply_along_axis()的方法来寻找更多的选项,这将是一个不错的选择。
我使用下面的代码生成数据:
import numpy as np
num = 4000
planes, rows, cols, n = 3, num, num, 4
lut = np.random.randint(-2**31, 2**31-1,size=(planes*256*n//4,)).view('uint8')
lut = lut.reshape(planes, 256, n)
img = np.random.randint(-2**31, 2**31-1,size=(planes*rows*cols//4,)).view('uint8')
img = img.reshape(planes, rows, cols)

关于python - 使用numpy.take进行更快速的花式索引,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14491480/

10-13 07:36