Skip to main content
 首页 » 编程设计

python之Numpy:从给定范围生成组合的有效方法

2025年05月04日10tuyile006

我有一个 n 维数组,如下所示:

np.array([[0,3],[0,3],[0,10]]) 

在此数组中,元素表示低值和高值。例如:[0,3] 指的是 [0,1,2,3]

我需要使用上面给出的范围生成所有值的组合。 例如,我想要 [0,0,0], [0,0,1] ... [0,1,0] ... [3,3,10]

我尝试了以下方法来获得我想要的:

ds = np.array([[0,3],[0,3],[0,10]]) 
nItems = int(reduce(lambda a,b: a * (b[1] - b[0] + 1), ds, 1)) 
myCombinations = np.zeros((nItems,)) 
nArrays = [] 
for x in range(ds.shape[0]): 
    low = ds[x][0] 
    high= ds[x][1] 
    nitm = high - low + 1 
    ar = [x+low for x in range(nitm) ] 
    nArrays.append(ar) 
 
myCombinations = cartesian(nArrays) 

笛卡尔函数取自 Using numpy to build an array of all combinations of two arrays

我需要这样做几百万次。

我的问题:是否有更好/更有效的方法来做到这一点?

请您参考如下方法:

我认为您正在寻找的是 np.mgrid。不幸的是,这会以与您需要的格式不同的格式返回数组,因此您需要进行一些后期处理:

a = np.mgrid[0:4, 0:4, 0:11]     # All points in a 3D grid within the given ranges 
a = np.rollaxis(a, 0, 4)         # Make the 0th axis into the last axis 
a = a.reshape((4 * 4 * 11, 3))   # Now you can safely reshape while preserving order 

解释

np.mgrid为您提供 N 维空间中的一组网格点。让我试着用一个更小的例子来说明这一点,让事情更清楚:

>>> a = np.mgrid[0:2, 0:2] 
>>> a 
array([[[0, 0], 
        [1, 1]], 
 
       [[0, 1], 
        [0, 1]]]) 

因为我给出了两组范围,0:2, 0:2,所以我得到了一个二维网格。 mgrid返回的是二维网格点(0, 0), (0, 1), (1, 0), (1, 1)对应的x值和y值空间。 a[0] 告诉您四个点的 x 值是多少,a[1] 告诉您 y 值是多少。

但您真正想要的是我写出的实际网格点列表,而不是这些点的 x 和 y 值。第一直觉是根据需要 reshape 数组:

>>> a.reshape((4, 2)) 
array([[0, 0], 
       [1, 1], 
       [0, 1], 
       [0, 1]]) 

但显然这行不通,因为它有效地 reshape 了展平的数组(仅按顺序读取所有元素获得的数组),而这不是您想要的。

你要做的是查看 a 的第三维,并创建一个数组:

[ [a[0][0, 0], a[1][0, 0]], 
  [a[0][0, 1], a[1][0, 1]], 
  [a[0][1, 0], a[1][1, 0]], 
  [a[0][1, 1], a[1][1, 1]] ] 

上面写着“首先告诉我第一个点 (x1, y1),然后是第二个点 (x2, y2), ...”等等。也许用某种形式的数字更好地解释这一点。这是 a 的样子:

                you want to read 
                in this direction 
                 (0, 0)   (0, 1) 
                   |        | 
                   |        | 
                   v        v 
 
          /        0--------0            +----> axis0 
 x-values |       /|       /|           /| 
          |      / |      / |    axis1 / | 
          \     1--------1  |         L  | 
                |  |     |  |            v 
          /     |  0-----|--1           axis2 
 y-values |     | /      | / 
          |     |/       |/ 
          \     0--------1 
 
                |        | 
                |        | 
                v        v 
              (1, 0)   (1, 1) 

np.rollaxis 为您提供了执行此操作的方法。 np.rollaxis(a, 0, 3) 在上面的例子中说“取第 0 个(或 最外面)轴并使其成为最后一个(或 最里面) 轴。(注意:这里实际上只存在轴 0、1 和 2。所以说“将第 0 个轴发送到第 3 个位置”是告诉 python 将第 0 个轴放在最后一个轴之后的一种方式)。您可能还想阅读 this。

>>> a = np.rollaxis(a, 0, 3) 
>>> a 
array([[[0, 0], 
        [0, 1]], 
 
       [[1, 0], 
        [1, 1]]]) 

这开始看起来像你想要的,除了有一个额外的数组维度。我们想要合并维度 0 和 1 以获得单个网格点数组。但现在展平数组以您期望的方式读取,您可以安全地 reshape 它以获得所需的结果。

>>> a = a.reshape((4, 2)) 
>>> a 
array([[0, 0], 
       [0, 1], 
       [1, 0], 
       [1, 1]]) 

3D 版本做同样的事情,除了,我无法为它制作图形,因为它是 4D 的。