Python 给定尺寸的值范围的组合

Python 给定尺寸的值范围的组合,python,arrays,numpy,Python,Arrays,Numpy,我使用以下代码为数组创建索引列表。但是,我希望索引以Fortran顺序运行,即内部循环是变化较快的循环。有没有一种方法可以在python中实现这一点。目前,我得到的输出是C顺序的 np.transpose(np.nonzero(np.ones([32,30]))) 输出: array([[ 0, 0], [ 0, 1], [ 0, 2], ..., [31, 27], [31, 28], [31, 29

我使用以下代码为数组创建索引列表。但是,我希望索引以Fortran顺序运行,即内部循环是变化较快的循环。有没有一种方法可以在python中实现这一点。目前,我得到的输出是C顺序的

np.transpose(np.nonzero(np.ones([32,30])))
输出:

array([[ 0,  0],
       [ 0,  1],
       [ 0,  2],
       ..., 
       [31, 27],
       [31, 28],
       [31, 29]])
array([[ 0,  0],
       [ 1,  0],
       [ 2,  0],
       ..., 
       [29, 29],
       [30, 29],
       [31, 29]])
但是,我需要以下格式的ouptut:

array([[ 0,  0],
       [ 1,  0],
       [ 2,  0],
       ..., 
       [29, 29],
       [30, 29],
       [31, 29]])
A.双参数解决方案(两列输出) 您可以使用
np.index
生成这些索引,然后进行转置和重塑-

np.indices((32,30)).T.reshape(-1,2)
样本输出-

In [36]: np.indices((32,30)).T.reshape(-1,2)
Out[36]: 
array([[ 0,  0],
       [ 1,  0],
       [ 2,  0],
       ..., 
       [29, 29],
       [30, 29],
       [31, 29]])
运行时测试-

In [74]: points = [32,30]

# @218's soln
In [75]: %timeit np.transpose(np.nonzero(np.ones(points[::-1])))[:,::-1]
100000 loops, best of 3: 18.6 µs per loop

In [76]: %timeit np.indices((points)).T.reshape(-1,2)
100000 loops, best of 3: 16.1 µs per loop

In [77]: points = [320,300]

# @218's soln
In [78]: %timeit np.transpose(np.nonzero(np.ones(points[::-1])))[:,::-1]
100 loops, best of 3: 2.14 ms per loop

In [79]: %timeit np.indices((points)).T.reshape(-1,2)
1000 loops, best of 3: 1.26 ms per loop
性能进一步提升

我们可以使用翻转的
np.索引
进一步优化它,然后使用
np.column\u stack
创建最终的
2
列数组。让我们计时并对照已经提出的方案进行验证。下面列出这两种方法-

def app1(points):
    return np.indices((points)).T.reshape(-1,2)

def app2(points):
    R,C = np.indices((points[::-1]))
    return np.column_stack((C.ravel(), R.ravel()))
时间安排-

In [146]: points = [32,30]

In [147]: np.allclose(app1(points), app2(points))
Out[147]: True

In [148]: %timeit app1(points)
100000 loops, best of 3: 14.8 µs per loop

In [149]: %timeit app2(points)
100000 loops, best of 3: 17.4 µs per loop

In [150]: points = [320,300]

In [151]: %timeit app1(points)
1000 loops, best of 3: 1.1 ms per loop

In [152]: %timeit app2(points)
1000 loops, best of 3: 822 µs per loop
所以,这个更适合较大的形状


B.通用解决方案(通用列输出) 我们将使它成为通用的,这样我们就可以使用给定的尽可能多的参数,就像这样-

def get_combinations(params, order='right'):
    # params : tuple of input scalars that denotes sizes
    # The order arg is used for the LSB position. So, with order='right', the
    # rightmost column is the least significant, hence it will change the most
    # when going through the rows. For order='left', the leftmost column
    # would change the most.
    all_indices = np.indices(params)
    if order=='right':
        return np.moveaxis(all_indices,0,-1).reshape(-1,len(params))
    elif order=='left':
        return all_indices.T.reshape(-1,len(params))
    else:
        raise Exception('Wrong side value!')
案例运行示例-

In [189]: get_combinations((2,3), order='left')
Out[189]: 
array([[0, 0],
       [1, 0],
       [0, 1],
       [1, 1],
       [0, 2],
       [1, 2]])

In [191]: get_combinations((2,3,2), order='right')
Out[191]: 
array([[0, 0, 0],
       [0, 0, 1],
       [0, 1, 0],
       [0, 1, 1],
       [0, 2, 0],
       [0, 2, 1],
       [1, 0, 0],
       [1, 0, 1],
       [1, 1, 0],
       [1, 1, 1],
       [1, 2, 0],
       [1, 2, 1]])

这就是你想要的吗

a = np.transpose(np.nonzero(np.ones([32,30])))  
a.reshape(32,30,2).transpose(1,0,2).reshape(-1,2)
Out[2197]: 
array([[ 0,  0],
       [ 1,  0],
       [ 2,  0],
       ..., 
       [29, 29],
       [30, 29],
       [31, 29]], dtype=int64)
Nils-Werner的评论中建议了一个通用解决方案(适用于更高维度的索引,如3D、4D)等:

points = [32,30]
np.transpose(np.nonzero(np.ones(points[::-1])))[:,::-1]
输出:

array([[ 0,  0],
       [ 0,  1],
       [ 0,  2],
       ..., 
       [31, 27],
       [31, 28],
       [31, 29]])
array([[ 0,  0],
       [ 1,  0],
       [ 2,  0],
       ..., 
       [29, 29],
       [30, 29],
       [31, 29]])

您可以使用
np.transpose(np.nonzero(np.ones([32,30]))[:,::-1]
简单地反转列,虽然这并不能解决问题,因为尽管内部循环现在变化更快,但它从0..29而不是0..39运行,也就是说,如果索引是(x,y),我们现在有效地拥有(y,x)。它不会使x变量成为变化更快的变量。@NilsWerner不会解决它。看看预期的第二列。当然,也交换
np.ones()
的参数……根据定义,内部循环是变化最快的。按顺序C,尺寸是最后一个,按顺序F,尺寸是第一个。