Reputation: 2993
An example will tell things straight forward:
import numpy
# ------------------------------------------------------------------------
# Edit:
# commenting out below `a` assignation for the more general case as shown
#+below this commented block
# ------------------------------------------------------------------------
# a = np.array(range(8))
# print a
# array([0, 1, 2, 3, 4, 5, 6, 7])
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
a = np.random.randn(8)
print a
array([-0.53683985, -0.321736 , 0.15684836, 0.32085469, 1.99615701,
-1.16908367, -0.10995894, -1.90925978])
b = [4, 7]
# ^ ^ These values are indices of values in `a` I want to keep unchanged
# I want to set all values to,
# say np.random.random_integers(10, 100) or simply `nan` except for indices given by `b`:
# So I want something like this:
a[: (!b)] = np.random.random_integers(10, 100) # I'm using "!" as the NOT operator
print a
array([62, 96, 47, 74, 1.99615701, 32, 11, -1.90925978])
# not changed: ^^^^^^^^^^ ^^^^^^^^^^
# or:
a[: (!b)] = np.nan
print a
array([nan, nan, nan, nan, 1.99615701, nan, nan, -1.90925978])
# not changed: ^^^^^^^^^^ ^^^^^^^^^^
I know I can use np.ma.array(a, mask = False) and a.mask[b] = True, but from this point I don't know how to assign my random numbers to only unmasked values
Upvotes: 1
Views: 186
Reputation: 3571
To simply mask and update elements of a
that are not in b
,
import numpy as np
a = np.range(8)
b = [4, 7]
a[~np.in1d(a, b)] = np.random.random_integers(
10, 100, size=len(a) - len(b))
print a
> array([34, 16, 99, 67, 4, 32, 64, 7])
The key is the ~np.in1d(a, b)
construct. np.in1d(a, b)
makes an array, the size of a
such that item i
of this array is only true if a[i]
is in b
; the ~
reverses this.
Also note that the size passed to np.random.random_integers has to match the size of the masked a.
What the asker wants is to pass random numbers to a
for indices of a
that are not in b
. Now, if you wanted to assign random integers to the elements in b
, you could simply do a[b] = ...
. Excluding them is more complicated. The way to do it is this:
a[~np.in1d(np.arange(np.size(a), b))] = np.random.random_integers(
10, 100, size=len(a) - len(b))
which is similar to the a[...] = ...
assignment in the first part of this answer, except instead of passing a
to np.in1d
, np.arange
is used to make an array that gives indices, not elements, of a
to np.in1d
.
Upvotes: 4
Reputation: 880887
Rather than being parsimonious with the generation of random numbers -- especially if b
is a small list -- it would be easier to just generate a random array of size a.size
, and then copy the desired values of a
into the new array, c
:
import numpy as np
a = np.array(range(8))
b = [4, 7]
c = np.random.random_integers(10, 100, size=a.size)
c[b] = a[b]
a = c
print(a)
yields something like
[10 92 73 66 4 54 42 7]
Upvotes: 4