问题
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.]]]
回答1:
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)
回答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]
.
来源:https://stackoverflow.com/questions/31887986/numpy-array-indexing-and-replacing