可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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]]
回答2:
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:
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]
回答4:
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) ]
回答5:
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.