itertools产品加速

我使用itertools.product来生成长度为13的4个元素的所有可能的变化。4和13可以是任意的,但是,实际上,我得到4 ^ 13个结果,这是很多的。 我需要结果作为一个Numpy数组,目前做到以下几点:

c = it.product([1,-1,np.complex(0,1), np.complex(0,-1)], repeat=length) sendbuf = np.array(list(c)) 

有了一些简单的剖析代码,它看起来像第一行几乎是瞬间的,而转换到列表然后Numpy数组需要大约3个小时。 有没有办法让这个更快? 这很可能是我忽视的一些事情。

谢谢!

itertools.product()的NumPy相当于numpy.indices() ,但它只会得到0,…,k-1forms范围的乘积:

 numpy.rollaxis(numpy.indices((2, 3, 3)), 0, 4) array([[[[0, 0, 0], [0, 0, 1], [0, 0, 2]], [[0, 1, 0], [0, 1, 1], [0, 1, 2]], [[0, 2, 0], [0, 2, 1], [0, 2, 2]]], [[[1, 0, 0], [1, 0, 1], [1, 0, 2]], [[1, 1, 0], [1, 1, 1], [1, 1, 2]], [[1, 2, 0], [1, 2, 1], [1, 2, 2]]]]) 

对于你的特殊情况,你可以使用

 a = numpy.indices((4,)*13) b = 1j ** numpy.rollaxis(a, 0, 14) 

(这不会在一个32位的系统上运行,因为这个数组太大了,从我可以testing的大小推断,它应该在不到一分钟的时间内运行)。

EIDT:只要提一下:调用numpy.rollaxis()或多或less都是numpy.rollaxis() ,以获得与itertools.product()相同的输出。 如果你不关心索引的顺序,你可以忽略它(但是,只要你没有任何后续操作将你的数组转换成连续的数组,那么它就很便宜)。

编辑2:得到确切的模拟

 numpy.array(list(itertools.product(some_list, repeat=some_length))) 

您可以使用

 numpy.array(some_list)[numpy.rollaxis( numpy.indices((len(some_list),) * some_length), 0, some_length + 1) .reshape(-1, some_length)] 

这完全是不可读的 – 只是告诉我,我是否应该进一步解释:)

第一行似乎是即时的,因为没有实际的操作发生。 一个生成器对象只是被构造出来的,只有当你在迭代操作时才会发生。 正如你所说,你得到4^13 = 67108864号码,所有这些都是计算,并在list调用。 我看到,np.array只接受列表或元组,所以你可以尝试从你的迭代器中创build一个元组,并将它传递给np.array,以查看是否有任何性能差异,并且不会影响程序的整体性能。 这只能通过尝试你的用例来确定,尽pipe有一些说tuple稍快的点。

尝试一个元组,而不是列表只是做

 sendbuf = np.array(tuple(c)) 

你可以通过跳转到列表来加快速度:

 numpy.fromiter(c, count=…) # Using count also speeds things up, but it's optional 

有了这个函数,NumPy数组首先被分配,然后逐个元素地被初始化,而不需要经过列表构造的附加步骤。

PSfromiter()不处理由product()返回的元组,所以现在可能不是解决scheme。 如果fromiter()确实处理了fromiter() dtype=object ,这应该可以工作。

PPS :正如乔·金顿(Joe Kington)指出的那样,可以通过将元组放在一个结构化数组中来实现 。 但是,这似乎并不总是加快速度。

您可能想尝试一种完全不同的方法:首先创build一个所需大小的空数组:

 result = np.empty((4**length, length), dtype=complex) 

然后使用NumPy的切片function来自己填充arrays:

 # Set up of the last "digit": result[::4, length-1] = 1 result[1::4, length-1] = -1 result[2::4, length-1] = 1j result[3::4, length-1] = -1j 

您可以为其他“数字”(即结果[:,2],结果[:,1]和结果[:,0])的元素做类似的事情。 整个事情当然可以放在循环遍历每个数字。

转移整个操作( np.empty((length, 4**length)…) )是值得尝试的,因为它可能会带来速度增益(通过更好地使用内存caching)。

可能不是优化,但更less依赖pythontypes转换:

 ints = [1,2,3,4] repeat = 3 def prod(ints, repeat): w = repeat l = len(ints) h = l**repeat ints = np.array(ints) A = np.empty((h,w), dtype=int) rng = np.arange(h) for i in range(w): x = l**i idx = np.mod(rng,l*x)/x A[:,i] = ints[idx] return A 

让numpy.meshgrid做所有的工作:

 length = 13 x = [1, -1, 1j, -1j] mesh = numpy.meshgrid(*([x] * length)) result = numpy.vstack([y.flat for y in mesh]).T 

在我的笔记本上需要〜2分钟