Numpy:从给定范围生成组合的有效方法 [英] Numpy: efficient way to generate combinations from given ranges

查看:27
本文介绍了Numpy:从给定范围生成组合的有效方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个如下所示的 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 = []对于范围内的 x(ds.shape[0]):低 = ds[x][0]高 = ds[x][1]nitm = 高 - 低 + 1ar = [x+low for x in range(nitm)]nArrays.append(ar)myCombinations = 笛卡尔(nArrays)

笛卡尔函数取自 使用numpy构建两个数组的所有组合的数组

我需要这样做几百万次.

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

解决方案

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

a = np.mgrid[0:4, 0:4, 0:11] # 给定范围内 3D 网格中的所有点a = np.rollaxis(a, 0, 4) # 使第 0 个轴成为最后一个轴a = a.reshape((4 * 4 * 11, 3)) # 现在你可以在保留顺序的同时安全地重塑

说明

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

<预><代码>>>>a = np.mgrid[0:2, 0:2]>>>一种数组([[[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 值.第一直觉是根据需要重塑数组:

<预><代码>>>>a.reshape((4, 2))数组([[0, 0],[1, 1],[0, 1],[0, 1]])

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

你要做的是往下看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 的样子:

 你要阅读在这个方向(0, 0) (0, 1)||||v v/0--------0 +---->轴0x 值 |/|/|/||/|/|轴 1/|\ 1--------1 |升|||||v/|0----|--1轴2y 值 ||/|/||/|/\ 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)>>>一种数组([[[0, 0],[0, 1]],[[1, 0],[1, 1]]])

这开始看起来像你想要的,除了有一个额外的数组维度.我们想要合并维度 0 和 1 以获得单个网格点数组.但是现在扁平数组以您期望的方式读取,您可以安全地对其进行整形以提供您想要的结果.

<预><代码>>>>a = a.reshape((4, 2))>>>一种数组([[0, 0],[0, 1],[1, 0],[1, 1]])

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

I have a n-dimension array as shown below:

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

In this array, the elements denote the low and high values. Ex: [0,3] refers to [0,1,2,3]

I need to generate a combination of all values using the ranges given as above. For example, I want [0,0,0], [0,0,1] ... [0,1,0] ... [3,3,10]

I have tried the following to get what I want:

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)

The cartesian function was taken from Using numpy to build an array of all combinations of two arrays

I need to do this few million times.

My question: is there any better / efficient way to do this?

解决方案

I think what you're looking for is np.mgrid. Unfortunately, this returns the array in a format that's different from what you need, so you'll need to do a little post-processing:

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

Explanation

np.mgrid gives you a set of grid points in N-dimensional space. Let me try to show this with a smaller example, to make things clearer:

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

       [[0, 1],
        [0, 1]]])

Since I've given two sets of ranges, 0:2, 0:2, I get a 2D grid. What mgrid returns is the x-values and the y-values corresponding to the grid points (0, 0), (0, 1), (1, 0) and (1, 1) in 2D space. a[0] tells you what the x-values of the four points are, and a[1] tells you what the y-values are.

But what you really want is that list of actual grid points that I've written out, not the x- and y-values of those points separately. First instinct is to just reshape the array as desired:

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

But clearly this doesn't work, because it effectively reshapes the flattened array (the array obtained by just reading all elements in order), and that's not what you want.

What you want to do is to look down the third dimension of a, and create an array:

[ [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]] ]

which reads "First tell me the first point (x1, y1), then the second point (x2, y2), ..." and so on. Perhaps this is better explained with a figure, of sorts. This is what a looks like:

                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 gives you a way to do this. np.rollaxis(a, 0, 3) in the above example says "take the 0th (or outermost) axis and make it into the last (or innermost) axis. (Note: only axes 0, 1 and 2 actually exist here. So saying "send the 0th axis to the 3rd position" is a way of telling python to put the 0th axis after the last axis). You might also want to read this.

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

       [[1, 0],
        [1, 1]]])

This is starting to look like what you want, except there's an extra array dimension. We want to merge dimensions 0 and 1 to get just get a single array of grid points. But now that the flattened array reads in the manner that you expect, you can safely reshape it to give you the desired result.

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

The 3D version does just the same thing, except, I couldn't make a figure for that, since it'd be in 4D.

这篇关于Numpy:从给定范围生成组合的有效方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆