1

I have a 3d numpy array as follows:

(3L, 5L, 5L)

If one element in 3d positions, for instance, [150, 160, 170] exists. How can I convert all of them into [0,0,0]?

import numpy as np
a = np.ones((3,5,5))
a[0,2:4,2:4] = 150
a[0,0:1,0:1] = 150 #important!
a[1,2:4,2:4] = 160
a[2,2:4,2:4] = 170
print a

The expected result should be:

[[[ 1.  1.  1.  1.  1.]
  [ 1.  1.  1.  1.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  1.  1.  1.]]

 [[ 1.  1.  1.  1.  1.]
  [ 1.  1.  1.  1.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  1.  1.  1.]]

 [[ 1.  1.  1.  1.  1.]
  [ 1.  1.  1.  1.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  0.  0.  1.]
  [ 1.  1.  1.  1.  1.]]]
3
  • np.where( condition ) Commented Aug 8, 2015 at 0:19
  • The question and example should make it clearer that the [150,160,170] have to occur together. Commented Aug 8, 2015 at 3:11
  • @hpaulj Yes! They should be together!! Commented Aug 8, 2015 at 3:12

2 Answers 2

2

First I would convert into a stack of triples:

b = np.reshape(a.transpose(2, 1, 0), [25,3])

Then find the values you want:

idx = np.where((b == np.array([150, 160, 170])).all(axis=1))

And replace with whatever value you want:

b[idx] = 0

And finally convert back to the original shape:

c = np.reshape(b, [5, 5, 3]).transpose(2, 1, 0) 
Sign up to request clarification or add additional context in comments.

Comments

2

Construct your a:

In [48]: a=np.ones((3,5,5))    
In [49]: a[0,2:4,2:4]=150
In [50]: a[1,2:4,2:4]=160
In [51]: a[2,2:4,2:4]=170

In [52]: a
Out[52]: 
array([[[   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,  150.,  150.,    1.],
        [   1.,    1.,  150.,  150.,    1.],
        [   1.,    1.,    1.,    1.,    1.]],

       [[   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,  160.,  160.,    1.],
        [   1.,    1.,  160.,  160.,    1.],
        [   1.,    1.,    1.,    1.,    1.]],

       [[   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,    1.,    1.,    1.],
        [   1.,    1.,  170.,  170.,    1.],
        [   1.,    1.,  170.,  170.,    1.],
        [   1.,    1.,    1.,    1.,    1.]]])

Boolean of all places where the values, on the 1st dimension, are [150,160,170]. The key is to expand this to a 3d, shape (3,1,1) that can be broadcast to (3,5,5) and compared with a:

In [53]: I = a==np.array([150,160,170])[:,None,None]

In [54]: I
Out[54]: 
array([[[False, False, False, False, False],
        [False, False, False, False, False],
        [False, False,  True,  True, False],
        [False, False,  True,  True, False],
        [False, False, False, False, False]],

       [[False, False, False, False, False],
        [False, False, False, False, False],
        [False, False,  True,  True, False],
        [False, False,  True,  True, False],
        [False, False, False, False, False]],

       [[False, False, False, False, False],
        [False, False, False, False, False],
        [False, False,  True,  True, False],
        [False, False,  True,  True, False],
        [False, False, False, False, False]]], dtype=bool)

Now it's trivial to change all those slots with value True to 0:

In [55]: a[I]=0

In [56]: a
Out[56]: 
array([[[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]],

       [[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]],

       [[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  0.,  0.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]]])

Looking at the comments on a deleted answer I see you really want a case where all 3 values match. That is, contrary to your example, there may be other slots a[0,...] is 150, etc. that you don't want to change.

You could still work with this I, by just taking an all on the 1st axis:

In [58]: a[:,I.all(axis=0)]=2

In [59]: a
Out[59]: 
array([[[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]],

       [[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]],

       [[ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  1.,  1.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  2.,  2.,  1.],
        [ 1.,  1.,  1.,  1.,  1.]]])

Conceptually my answer is not that different from the accepted one. That reshapes the array into a 2d, so the matching can be done with a 1d [150,160,170]. Actually it is automatically reshaped to (1,3) which can be broadcast agains (25,3) array. Transposing and reshaping is a convenient way to standardize the format of problems like this, though it often isn't necessary.


It may help to split that last action up:

In [60]: J=I.all(axis=0)

In [61]: J
Out[61]: 
array([[False, False, False, False, False],
       [False, False, False, False, False],
       [False, False,  True,  True, False],
       [False, False,  True,  True, False],
       [False, False, False, False, False]], dtype=bool)

In [62]: a[:, J] = 3

or use np.where to convert the boolean array to 2 list of indices:

In [73]: jj=np.where(J)
In [74]: jj
Out[74]: (array([2, 2, 3, 3], dtype=int32), array([2, 3, 2, 3], dtype=int32))

In [75]: a[:, jj[0], jj[1]] = 4

a[:,jj] doesn't work, but a[(slice(None),)+jj] does. This last expression constructs a 3 element tuple, the equivalent to [75]'s.

I could also expand J to a size and shape that matches a:

In [90]: K=J[None,...].repeat(3,0)
In [91]: K
Out[91]: 
array([[[False, False, False, False, False],
        [False, False, False, False, False],
        [False, False,  True,  True, False],
        [False, False,  True,  True, False],
        [False, False, False, False, False]],

       [[False, False, False, False, False],
        ....]], dtype=bool)

and use a[K].

2 Comments

Following a[:,I.all(axis=0)]=2 part is little difficult. Can not the indices be pre-obtained using I = a==np.array([150,160,170])[:,None,None] and defining some axis like (1,3)?
I've elaborated on the I.all indexing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.