Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fastest way to create numpy 2d array of indices

I want to create a numpy 2d array containning the cells indices, for example such 2x2 mat can be created using :

np.array([[[0,0],[0,1]],[[1,0],[1,1]]])

In other words cell at index i,j should contain the list [i,j].

I could make a nested loop to do it c way but i am wondering if there is a fast pythonic way to do that?

like image 448
Ofek Ron Avatar asked May 28 '17 17:05

Ofek Ron


3 Answers

For performance with NumPy, I would suggest an array initialization based approach -

def indices_array(n):
    r = np.arange(n)
    out = np.empty((n,n,2),dtype=int)
    out[:,:,0] = r[:,None]
    out[:,:,1] = r
    return out

For a generic (m,n,2) shaped output, we need some modifications :

def indices_array_generic(m,n):
    r0 = np.arange(m) # Or r0,r1 = np.ogrid[:m,:n], out[:,:,0] = r0
    r1 = np.arange(n)
    out = np.empty((m,n,2),dtype=int)
    out[:,:,0] = r0[:,None]
    out[:,:,1] = r1
    return out

Note: Also, read - 2019 addendum later on in this post for perf. boost with large m, n.

Sample run -

In [145]: n = 3

In [146]: indices_array(n)
Out[146]: 
array([[[0, 0],
        [0, 1],
        [0, 2]],

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

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

If you needed a 2 columns 2D array, simply reshape -

In [147]: indices_array(n).reshape(-1,2)
Out[147]: 
array([[0, 0],
       [0, 1],
       [0, 2],
       [1, 0],
       [1, 1],
       [1, 2],
       [2, 0],
       [2, 1],
       [2, 2]])

Timings and verification -

In [141]: n = 100   
     ...: out1 = np.array(list(product(range(n), repeat=2))).reshape(n,n,2)
     ...: out2 = indices_array(n)
     ...: print np.allclose(out1, out2)
     ...: 
True

# @Ofek Ron's solution
In [26]: %timeit np.array(list(product(range(n), repeat=2))).reshape(n,n,2)
100 loops, best of 3: 2.69 ms per loop

In [27]: # @Brad Solomon's soln    
    ...: def ndindex_app(n):
    ...:    row, col = n,n
    ...:    return np.array(list(np.ndindex((row, col)))).reshape(row, col, 2)
    ...: 

# @Brad Solomon's soln 
In [28]: %timeit ndindex_app(n)
100 loops, best of 3: 5.72 ms per loop

# Proposed earlier in this post
In [29]: %timeit indices_array(n)
100000 loops, best of 3: 12.1 µs per loop

In [30]: 2690/12.1
Out[30]: 222.31404958677686

200x+ speedup there for n=100 with the initialization based one!


2019 addendum

We can also use np.indices -

def indices_array_generic_builtin(m,n):
    return np.indices((m,n)).transpose(1,2,0)

Timings -

In [115]: %timeit indices_array_generic(1000,1000)
     ...: %timeit indices_array_generic_builtin(1000,1000)
100 loops, best of 3: 2.92 ms per loop
1000 loops, best of 3: 1.37 ms per loop
like image 119
Divakar Avatar answered Nov 14 '22 21:11

Divakar


np.array(list(product(range(n), repeat=2))).reshape(n,n,2)

this works

like image 44
Ofek Ron Avatar answered Nov 14 '22 23:11

Ofek Ron


You want np.ndindex.

def coords(row, col):
    return np.array(list(np.ndindex((row, col)))).reshape(row, col, 2)

coords(3, 2)
Out[32]: 
array([[[0, 0],
        [0, 1]],

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

       [[2, 0],
        [2, 1]]])
like image 37
Brad Solomon Avatar answered Nov 14 '22 23:11

Brad Solomon