Search code examples
python-3.xnumpynumpy-random

Filling a zeros array at limited number of random places except diagonal ones


I have a 2D numpy array which has only 0s in (N,N) size. I randomly want to insert twelve 1s to this array while keeping the diagonal locations' value equal to 0. What I have tried until now is :

import numpy as np
def func(N=20):
    x= np.zeros((N,N))
    for m in range(N):
        for n in range(N):
                if m == n:
                    x[m][n] == 0
                else:
                    if np.count_nonzero(x) <= 12:
                            x.fill(1)
                            return (np.count_nonzero)
    print (x)

The output I am getting is an N,N array full of 1s. I cannot stop inserting the 1s after their quantity reaches to 12. How can I fix it?


Solution

  • Since you are using NumPy and if you are okay with an alternate vectorized solution, here's one with masking and choosing those places with np.random.choice -

    def random_off_diag_fill(N, num_rand = 12, fillval=1):
        # Initialize array
        x= np.zeros((N,N),dtype=type(fillval))
    
        # Generate flat nondiagonal indices using masking
        idx = np.flatnonzero(~np.eye(N,dtype=bool))
    
        # Select num_rand random indices from those and set those
        # in a flattened view of the array to be as fillval
        x.ravel()[np.random.choice(idx, num_rand, replace=0)] = fillval
        return x
    

    Sample runs -

    In [57]: random_off_diag_fill(N=8, num_rand=12, fillval=1)
    Out[57]: 
    array([[0, 0, 0, 0, 0, 1, 1, 0],
           [0, 0, 0, 0, 0, 0, 0, 0],
           [1, 0, 0, 0, 0, 0, 1, 1],
           [0, 0, 0, 0, 0, 0, 0, 0],
           [1, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 1, 0, 1, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0],
           [1, 0, 1, 0, 0, 0, 0, 0]])
    
    In [63]: random_off_diag_fill(N=5, num_rand=12, fillval=2.45)
    Out[63]: 
    array([[ 0.  ,  0.  ,  0.  ,  0.  ,  2.45],
           [ 2.45,  0.  ,  2.45,  0.  ,  2.45],
           [ 0.  ,  2.45,  0.  ,  2.45,  2.45],
           [ 2.45,  2.45,  0.  ,  0.  ,  0.  ],
           [ 2.45,  2.45,  0.  ,  2.45,  0.  ]])