2

I have a 2d ndarray called weights of shape (npts, nweights). For every column of weights, I wish to randomly shuffle the rows. I want to repeat this process num_shuffles times, and store the collection of shufflings into a 3d ndarray called weights_matrix. Importantly, for each shuffling iteration, the shuffling indices of each column of weights should be the same.

Below appears an explicit naive double-for-loop implementation of this algorithm. Is it possible to avoid the python loops and generate weights_matrix in pure Numpy?

import numpy as np 
npts, nweights = 5, 2
weights = np.random.rand(npts*nweights).reshape((npts, nweights))

num_shuffles = 3
weights_matrix = np.zeros((num_shuffles, npts, nweights))
for i in range(num_shuffles):
    indx = np.random.choice(np.arange(npts), npts, replace=False)
    for j in range(nweights):
        weights_matrix[i, :, j] = weights[indx, j]
Divakar
  • 218,885
  • 19
  • 262
  • 358
aph
  • 1,765
  • 2
  • 19
  • 34

2 Answers2

1

You can start by filling your 3-D array with copies of the original weights, then perform a simple iteration over slices of that 3-D array, using numpy.random.shuffle to shuffle each 2-D slice in-place.

For every column of weights, I wish to randomly shuffle the rows...the shuffling indices of each column of weights should be the same

is just another way of saying "I want to randomly reorder the rows of a 2D array". numpy.random.shuffle is a numpy-array-capable version of random.shuffle: it will reorder the elements of a container in-place. And that's all you need, since the "elements" of a 2-D numpy array, in that sense, are its rows.

import numpy
weights = numpy.array( [ [ 1, 2, 3 ], [ 4, 5, 6], [ 7, 8, 9 ] ] )
weights_3d = weights[ numpy.newaxis, :, : ].repeat( 10, axis=0 )

for w in weights_3d:
    numpy.random.shuffle( w )  # in-place shuffle of the rows of each slice

print( weights_3d[0, :, :] )
print( weights_3d[1, :, :] )
print( weights_3d[2, :, :] )
jez
  • 14,867
  • 5
  • 37
  • 64
1

Here's a vectorized solution with the idea being borrowed from this post -

weights[np.random.rand(num_shuffles,weights.shape[0]).argsort(1)]

Sample run -

In [28]: weights
Out[28]: 
array([[ 0.22508764,  0.8527072 ],
       [ 0.31504052,  0.73272155],
       [ 0.73370203,  0.54889059],
       [ 0.87470619,  0.12394942],
       [ 0.20587307,  0.11385946]])

In [29]: num_shuffles = 3

In [30]: weights[np.random.rand(num_shuffles,weights.shape[0]).argsort(1)]
Out[30]: 
array([[[ 0.87470619,  0.12394942],
        [ 0.20587307,  0.11385946],
        [ 0.22508764,  0.8527072 ],
        [ 0.31504052,  0.73272155],
        [ 0.73370203,  0.54889059]],

       [[ 0.87470619,  0.12394942],
        [ 0.22508764,  0.8527072 ],
        [ 0.73370203,  0.54889059],
        [ 0.20587307,  0.11385946],
        [ 0.31504052,  0.73272155]],

       [[ 0.73370203,  0.54889059],
        [ 0.31504052,  0.73272155],
        [ 0.22508764,  0.8527072 ],
        [ 0.20587307,  0.11385946],
        [ 0.87470619,  0.12394942]]])
Divakar
  • 218,885
  • 19
  • 262
  • 358