user1850133
user1850133

Reputation: 2993

assign all items of an array except those of the given indices

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

Answers (2)

Alex Szatmary
Alex Szatmary

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

unutbu
unutbu

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

Related Questions