Combinations from range of values for given sizes

后端 未结 3 501
误落风尘
误落风尘 2021-01-14 18:39

I\'m using the following code to create a list of indices for an array. However, I would like the index to run in Fortran order i.e. the inner loop being the faster varying

相关标签:
3条回答
  • 2021-01-14 19:24

    A general solution (that would work for higher dimensional indices e.g. 3D, 4D) etc. seems to be as suggested in the comments by Nils Werner:

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

    Output:

    array([[ 0,  0],
           [ 1,  0],
           [ 2,  0],
           ..., 
           [29, 29],
           [30, 29],
           [31, 29]])
    
    0 讨论(0)
  • 2021-01-14 19:30

    A. Two param solution (two column output)

    You could generate those indices with np.indices and then a transpose and a reshape does the job -

    np.indices((32,30)).T.reshape(-1,2)
    

    Sample output -

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

    Runtime test -

    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
    

    Further performance boost

    We can optimize it further by using flipped points with np.indices and then using np.column_stack to create the final 2 columns array. Let's time and verify it against the already proposed one. Listing those two approaches below -

    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()))
    

    Timings -

    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
    

    So, this one's better on bigger shapes.


    B. Generic solution (Generic column output)

    We will make it generic so that we could work with as many params as given, like so -

    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!')
    

    Sample case runs -

    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]])
    
    0 讨论(0)
  • Is this what you are after?

    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)
    
    0 讨论(0)
提交回复
热议问题