Python itertools产品加速

Python itertools产品加速,python,numpy,itertools,Python,Numpy,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生成长度为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个小时。 有没有办法让这更快?这可能是我忽略的一些非常明显的事情

谢谢

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

要尝试使用元组,而不是列表,只需执行以下操作

sendbuf = np.array(tuple(c))

可能没有优化,但对python类型转换的依赖性要小得多:

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.fromiter(c, count=…)  # Using count also speeds things up, but it's optional
使用此函数,NumPy数组首先被分配,然后逐个元素初始化,而无需执行列表构造的附加步骤

PS
fromiter()
不处理
product()
返回的元组,因此目前这可能不是解决方案。如果
fromiter()
确实处理了
dtype=object
,这应该是可行的


PPS:正如乔·金顿(Joe Kington)指出的那样,这可以通过以下方式实现。但是,这似乎并不总是能提高速度。

itertools.product()
相当的NumPy是
NumPy.index()
,但它只能得到形式为0,…,k-1的范围的乘积:

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)
numpy.array(some_list)[numpy.rollaxis(
    numpy.indices((len(some_list),) * some_length), 0, some_length + 1)
    .reshape(-1, some_length)]
(这不会在32位系统上运行,因为阵列太大。从我可以测试的大小推断,它应该在不到一分钟内运行。)

EIDT:只需提一下:调用
numpy.rollaxis()
或多或少是一种美容,以获得与
itertools.product()相同的输出。如果不关心索引的顺序,可以忽略它(但只要不进行任何后续操作,就可以将数组转换为连续数组,这样做很便宜)

编辑2:为了得到与

numpy.array(list(itertools.product(some_list, repeat=some_length)))
你可以用

a = numpy.indices((4,)*13)
b = 1j ** numpy.rollaxis(a, 0, 14)
numpy.array(some_list)[numpy.rollaxis(
    numpy.indices((len(some_list),) * some_length), 0, some_length + 1)
    .reshape(-1, some_length)]

这完全不可读--请告诉我是否需要进一步解释:)

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

result = np.empty((4**length, length), dtype=complex)
然后使用NumPy的切片功能自己填充阵列:

# 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((长度,4**length)…)
)是值得尝试的,因为它可能会带来速度增益(通过更好地使用内存缓存)。

让numpy.meshgrid完成所有工作:
在我的笔记本上,大约需要2分钟

您可能会通过为Numpy阵列实施产品而获益匪浅。。。难道没有这样的事吗?编辑:开始请参阅。使用如何
sendbuf=np.fromiter(c,np.complex)
第一行是瞬时的,因为它只是创建一个迭代器,实际上并不生成序列。序列在第二行创建,生成4^13元素的速度会很慢。您试图解决的实际问题是什么?最有可能的解决方案不需要您生成所有4^13序列。您需要13 x 4^13 2D数组还是python元组对象的1D数组?尚未测试,但这正是我所设想的,谢谢@克里斯托夫:我认为NumPy会抱怨,因为
fromiter()
试图创建元组的1D数组(该函数只创建1D数组)。因此,一个好的类型选择似乎是
dtype=object
…但NumPy拒绝这样做。我不知道如何解决这个问题(除了游说有可能使用
dtype=object
:)&@Christoph-您可以通过使用结构化数组,然后将其视为“常规”数组来解决这个问题。方法是这样的:不幸的是,它并没有比使用列表或元组更快,正如您最初所做的那样。不过我得重新塑造。但这可能更快。谢谢让我来玩一玩。@Christoph:重塑很便宜,因为它根本不会改变数据。@Christoph:不,调用不是绝对必要的,它只会使数组的形状与原始版本完全相同。我不知道你们将如何处理排列,所以我不能给出如何处理排列的建议。但我个人根本不想麻烦使用
rollaxis()
reformate()
,而是按原样使用
index()
输出。例如,您可以在izip(*(a.ravel()表示在numpy.index(…))中的置换)中使用
对所有置换进行迭代。
。最有可能的是,您也可以在不重塑应用程序的情况下勉强度日。@Christoph-它们的结果完全相同,甚至顺序相同。@Christoph:如果
a=numpy.index((4,)*4)
,那么
a[0]
将包含第一个“index”的所有值,
a[1]
将是第二个“index”的值“索引”,依此类推。对于0到4^4-1范围内的每个
n
a[0]。平坦[n],a[1]。平坦[n],a[2]。平坦