Numpy random array from 0 to 99, including both

Viewed 1213

I'm trying to create a np array with size (80,10) so each row has random values with range 0 to 99.

I've done that by

np.random.randint(99, size=(80, 10))

But I would like to always include both 0 and 99 as values in each row.

So two values in each row are already defined and the other 8 will be random.

How would I accomplish this? Is there a way to generate an array size (80,8) and just concatenate [0,99] to every row to make it (80,10) at the end?

4 Answers

I've tried a few things and this is what I came up with

def generate_matrix(low, high, shape):
    x, y = shape
    values = np.random.randint(low+1, high-1, size=(x, y-2))
    predefined = np.tile([low, high], (x, 1))
    values = np.hstack([values, predefined])
    for row in values:
        np.random.shuffle(row)
    return values

Example usage

>>> generate_matrix(0, 99, (5, 10))
array([[94,  0, 45, 99, 18, 31, 78, 80, 32, 17],
       [28, 99, 72,  3,  0, 14, 26, 37, 41, 80],
       [18, 78, 71, 40, 99,  0, 85, 91,  8, 59],
       [65, 99,  0, 45, 93, 94, 16, 33, 52, 53],
       [22, 76, 99, 15, 27, 64, 91, 32,  0, 82]])

The way I approached it:

Generate an array of size (80, 8) in the range [1, 98] and then concatenate 0 and 99 for each row. But you probably need the 0/99 to occur at different indices for each row, so you have to shuffle them. Unfortunately, np.random.shuffle() only shuffles the rows among themselves. And if you use np.random.shuffle(arr.T).T, or random.Generator.permutation, you don't shuffle the columns independently. I haven't found a vectorised way to shuffle the rows independently other than using a Python loop.

Another way:

You can generate an array of size (80, 10) in the range [1, 98] and then substitute in random indices the values 0 and 99 for each row. Again, I couldn't find a way to generate unique indices per row (so that 0 doesn't overwrite 99 for example) without a Python loop. Since I couldn't find a way to avoid Python loops, I opted for the first way, which seemed more straightforward.

As suggested in the comments by Tim, you can generate a matrix with random values not including 0 and 99. Then replace two random indices along the second axis with the values 0 and 99.

rand_arr = np.random.randint(low=1, high=98, size=(80, 10))
rand_indices = np.random.rand(80,10).argsort(axis=1)[:,:2]
np.put_along_axis(rand_arr, rand_indices, [0,99], axis=1)

The motivation for using argsort is that we want random indices along the second axis without replacement. Just generating a random integer matrix for values 0-10 with size=(80,2) will not guarantee this.

In your scenario, you could do np.argpartion with kth=2 instead of np.argsort. This should be more efficient.

If you don't care about duplicates, create an array of zeros, replace columns 1-9 with random numbers and set column 10 to 99.

final = np.zeros(shape=(80, 10))
final[:,1:9] = np.random.randint(97, size=(80, 8))+1
final[:,9] = 99

Creating a matrix 80x10 with random values from 0 to 99 with no duplicates in the same row with 0 and 99 included in every row

import random
row99=[ n for n in range(1,99) ]
perm = [n for n in range(0,10) ]
m = []
for i in range(80):
    random.shuffle(row99)      
    random.shuffle(perm)
    
    r = row99[:10]
    r[perm[0]] = 0
    r[perm[1]] = 99

    m.append(r)
    
print(m)

Partial output:

[
   ... other elements here ...
[70, 58, 0, 25, 41, 10, 90, 5, 42, 18], 
[0, 57, 90, 71, 39, 65, 52, 24, 28, 77], 
[55, 42, 7, 9, 32, 69, 90, 0, 64, 2], 
[0, 59, 17, 35, 56, 34, 33, 37, 90, 71]]
Related