使用numpy来构build两个数组的所有组合的数组

我试图运行一个6参数函数的参数空间来研究它的数值行为之前,试图做任何复杂的事情,所以我正在寻找一种有效的方式来做到这一点。

我的函数采用浮点值给定一个6 dim numpy数组作为input。 我最初尝试做的是这样的:

首先,我创build了一个函数,该函数接受2个数组,并使用两个数组中的所有值的组合生成一个数组

from numpy import * def comb(a,b): c = [] for i in a: for j in b: c.append(r_[i,j]) return c 

然后我使用reduce()将其应用于同一个数组的m个副本:

 def combs(a,m): return reduce(comb,[a]*m) 

然后我评估我的function是这样的:

 values = combs(np.arange(0,1,0.1),6) for val in values: print F(val) 

这工作,但它太慢了。 我知道参数的空间是巨大的,但这不应该太慢。 在这个例子中,我只采样了10 6 (百万)个点,创build数组values 15秒以上的时间。

你知道用numpy做这个更有效的方法吗?

如果必要,我可以修改函数F取其参数的方式。

这是一个纯粹的实现。 这是约。 比使用itertools快5倍。

 import numpy as np def cartesian(arrays, out=None): """ Generate a cartesian product of input arrays. Parameters ---------- arrays : list of array-like 1-D arrays to form the cartesian product of. out : ndarray Array to place the cartesian product in. Returns ------- out : ndarray 2-D array of shape (M, len(arrays)) containing cartesian products formed of input arrays. Examples -------- >>> cartesian(([1, 2, 3], [4, 5], [6, 7])) array([[1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7], [3, 4, 6], [3, 4, 7], [3, 5, 6], [3, 5, 7]]) """ arrays = [np.asarray(x) for x in arrays] dtype = arrays[0].dtype n = np.prod([x.size for x in arrays]) if out is None: out = np.zeros([n, len(arrays)], dtype=dtype) m = n / arrays[0].size out[:,0] = np.repeat(arrays[0], m) if arrays[1:]: cartesian(arrays[1:], out=out[0:m,1:]) for j in xrange(1, arrays[0].size): out[j*m:(j+1)*m,1:] = out[0:m,1:] return out 

在较新版本的numpy (> 1.8.x)中, np.meshgrid提供了更快的实现:

@PV的解决scheme

 In [113]: %timeit cartesian(([1, 2, 3], [4, 5], [6, 7])) 10000 loops, best of 3: 135 µs per loop In [114]: cartesian(([1, 2, 3], [4, 5], [6, 7])) Out[114]: array([[1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7], [3, 4, 6], [3, 4, 7], [3, 5, 6], [3, 5, 7]]) 

numpy.meshgrid使用只有2D,现在它能够ND。 在这种情况下,3D:

 In [115]: %timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3) 10000 loops, best of 3: 74.1 µs per loop In [116]: np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3) Out[116]: array([[1, 4, 6], [1, 5, 6], [2, 4, 6], [2, 5, 6], [3, 4, 6], [3, 5, 6], [1, 4, 7], [1, 5, 7], [2, 4, 7], [2, 5, 7], [3, 4, 7], [3, 5, 7]]) 

请注意,最终结果的顺序略有不同。

itertools.combinations通常是从Python容器中获取组合的最快方法(如果你实际上需要组合,即没有重复和独立的顺序;这不是你的代码似乎在做什么,但我不能告诉是否这是因为你的代码是错误的,或者因为你使用了错误的术语)。

如果你想要一些不同于组合的东西,itertools, productpermutations其他迭代器可能会更好地为你服务。 例如,它看起来像你的代码大致相同:

 for val in itertools.product(np.arange(0, 1, 0.1), repeat=6): print F(val) 

所有这些迭代器产生元组,而不是列表或numpy数组,所以如果你的F是挑剔一个numpy数组,你将不得不接受构造或清除和重新填充每一步的额外开销。

下面的numpy实现应该是大约。 2x给定答案的速度:

 def cartesian2(arrays): arrays = [np.asarray(a) for a in arrays] shape = (len(x) for x in arrays) ix = np.indices(shape, dtype=int) ix = ix.reshape(len(arrays), -1).T for n, arr in enumerate(arrays): ix[:, n] = arrays[n][ix[:, n]] return ix 

它看起来像你想要一个网格来评估你的function,在这种情况下,你可以使用numpy.ogrid (打开)或numpy.mgrid (充实):

 import numpy my_grid = numpy.mgrid[[slice(0,1,0.1)]*6] 

你可以做这样的事情

 import numpy as np def cartesian_coord(*arrays): grid = np.meshgrid(*arrays) coord_list = [entry.ravel() for entry in grid] points = np.vstack(coord_list).T return points a = np.arange(4) # fake data print(cartesian_coord(*6*[a]) 

这使

 array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 2], ..., [3, 3, 3, 3, 3, 1], [3, 3, 3, 3, 3, 2], [3, 3, 3, 3, 3, 3]]) 

还有另一种方法,使用纯粹的NumPy,没有recursion,没有列表理解,也没有明确的for循环。 它比原来的答案慢大约20%,它基于np.meshgrid。

 def cartesian(*arrays): mesh = np.meshgrid(*arrays) # standard numpy meshgrid dim = len(mesh) # number of dimensions elements = mesh[0].size # number of elements, any index will do flat = np.concatenate(mesh).ravel() # flatten the whole meshgrid reshape = np.reshape(flat, (dim, elements)).T # reshape and transpose return reshape 

例如,

 x = np.arange(3) a = cartesian(x, x, x, x, x) print(a) 

 [[0 0 0 0 0] [0 0 0 0 1] [0 0 0 0 2] ..., [2 2 2 2 0] [2 2 2 2 1] [2 2 2 2 2]]