Numpy: Replace random elements in an array

2019-03-28 06:10发布

I already googled a bit and didn't find any good answers.

The thing is, I have a 2d numpy array and I'd like to replace some of its values at random positions.

I found some answers using numpy.random.choice to create a mask for the array. Unfortunately this does not create a view on the original array so I can not replace its values.

So here is an example of what I'd like to do.

Imagine I have 2d array with float values.

[[ 1., 2., 3.],
 [ 4., 5., 6.],
 [ 7., 8., 9.]]

And then I'd like to replace an arbitrary amount of elements. It would be nice if I could tune with a parameter how many elements are going to be replaced. A possible result could look like this:

[[ 3.234, 2., 3.],
 [ 4., 5., 6.],
 [ 7., 8., 2.234]]

I couldn't think of nice way to accomplish this. Help is appreciated.

EDIT

Thanks for all the quick replies.

5条回答
姐就是有狂的资本
2楼-- · 2019-03-28 06:19

It's easy to choose indices at random when the array is one-dimensional, so I'd recommend reshaping the array to 1D, changing random elements, then reshaping back to the original shape.

For example:

import numpy as np

def replaceRandom(arr, num):
    temp = np.asarray(arr)   # Cast to numpy array
    shape = temp.shape       # Store original shape
    temp = temp.flatten()    # Flatten to 1D
    inds = np.random.choice(temp.size, size=num)   # Get random indices
    temp[inds] = np.random.normal(size=num)        # Fill with something
    temp = temp.reshape(shape)                     # Restore original shape
    return temp

So this does something like:

>>> test = np.arange(24, dtype=np.float).reshape(2,3,4)
>>> print replaceRandom(test, 10)
[[[  0.          -0.95708819   2.           3.        ]
  [ -0.35466096   0.18493436   1.06883205   7.        ]
  [  8.           9.          10.          11.        ]]
 [[ -1.88613449  13.          14.          15.        ]
  [  0.57115795  -1.25526377  18.          -1.96359786]
  [ 20.          21.           2.29878207  23.        ]]]

Here I've replaced elements choosing from a normal distribution --- but obviously you can replace the call to np.random.normal with whatever you want.

查看更多
走好不送
3楼-- · 2019-03-28 06:21

You could always randomly generated n integers to index a flattened view (1D version) of your array, and set those indexed values equal to n random values:

In [1]: import numpy as np
In [2]: x = np.arange(1, 10).reshape(3, 3).astype(float)
In [3]: m = np.product(x.shape)
In [4]: n = 3
In [5]: x.ravel()[np.random.randint(0, m, size=n)] = np.random.rand(n)
In [6]: x
Out[6]: 
array([[ 0.28548823,  0.28819589,  3.        ],
       [ 4.        ,  5.        ,  6.        ],
       [ 7.        ,  8.        ,  0.28772056]])

You could scale the randomly generated values by some factor if you want values greater than 1; for example np.random.rand(n) * m would yield values between 0 and np.product(x.shape).

Note that numpy.ravel operates inplace by default.

查看更多
Animai°情兽
4楼-- · 2019-03-28 06:22

Just mask your input array with a random one of the same shape.

import numpy as np

# input array
x = np.array([[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.]])

# random boolean mask for which values will be changed
mask = np.random.randint(0,2,size=x.shape).astype(np.bool)

# random matrix the same shape of your data
r = np.random.rand(*x.shape)*np.max(x)

# use your mask to replace values in your input array
x[mask] = r[mask]

Produces something like this:

[[ 1.          2.          3.        ]
 [ 4.          5.          8.54749399]
 [ 7.57749917  8.          4.22590641]]
查看更多
劫难
5楼-- · 2019-03-28 06:25

You can create bernoulli random variables using scipy, and the parameter p will control what percent of values in your array you end up replacing. Then replace values in your original array based on whether the bernoulli random variable takes on a value of 0 or 1.

from scipy.stats import bernoulli as bn
import numpy as np

array = np.array([[ 1., 2., 3.],[ 4., 5., 6.],[ 7., 8., 9.]])
np.random.seed(123)
flag = bn.rvs(p=0.5,size=(3,3))
random_numbers = np.random.randn(3,3)
array[flag==0] = random_numbers[flag==0]
查看更多
迷人小祖宗
6楼-- · 2019-03-28 06:34

Not really optimized, but a starting point to help you figuring out a way of doing it:

import numpy as np

a = np.array( [[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.]])

def replace(ar,nbr):
  x,y = ar.shape
  s = x*y 
  mask = [1]*nbr + [0]*(s-nbr)
  np.random.shuffle(mask)
  mask = np.array(mask) == 1
  ar.reshape( (s) )[mask] = [ np.random.random() for _ in range(nbr) ]
查看更多
登录 后发表回答