Setting values of Numpy array when indexing an ind

2019-09-15 04:28发布

问题:

I'm trying to index some matrix, y, and then reindex that result with some boolean statement and set the corresponding elements in y to 0. The dummy code I'm using to test this indexing scheme is shown below.

x=np.zeros([5,4])+0.1;
y=x;
print(x)
m=np.array([0,2,3]);
y[0:4,m][y[0:4,m]<0.5]=0;
print(y)

I'm not sure why it does not work. The output I want:

[[ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]]
[[ 0.   0.1  0.   0. ]
 [ 0.   0.1  0.   0. ]
 [ 0.   0.1  0.   0. ]
 [ 0.   0.1  0.   0. ]
 [ 0.1  0.1  0.1  0.1]]

But what I actually get:

[[ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]]
[[ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]
 [ 0.1  0.1  0.1  0.1]]

I'm sure I'm missing some under-the-hood details that explains why this does not work. Interestingly, if you replace m with :, then the assignment works. For some reason, selecting a subset of the columns does not let me assign the zeros.

If someone could explain what's going on and help me find an alternative solution (hopefully one that does not involve generating a temporary numpy array since my actual y will be really huge), I would really appreciate it! Thank you!

EDIT: y[0:4,:][y[0:4,:]<0.5]=0; y[0:4,0:3][y[0:4,0:3]<0.5]=0; etc.

all work as expected. It seems the issue is when you index with a list of some kind.

回答1:

Make an array (this is one of my favorites because the values differ):

In [845]: x=np.arange(12).reshape(3,4)
In [846]: x
Out[846]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [847]: m=np.array([0,2,3])
In [848]: x[:,m]
Out[848]: 
array([[ 0,  2,  3],
       [ 4,  6,  7],
       [ 8, 10, 11]])
In [849]: x[:,m][:2,:]=0
In [850]: x
Out[850]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

No change. But if I do the indexing in one step, it changes.

In [851]: x[:2,m]=0
In [852]: x
Out[852]: 
array([[ 0,  1,  0,  0],
       [ 0,  5,  0,  0],
       [ 8,  9, 10, 11]])

it also works if I reverse the order:

In [853]: x[:2,:][:,m]=10
In [854]: x
Out[854]: 
array([[10,  1, 10, 10],
       [10,  5, 10, 10],
       [ 8,  9, 10, 11]])

x[i,j] is executed as x.__getitem__((i,j)). x[i,j]=v as x.__setitem__((i,j),v).

x[i,j][k,l]=v is x.__getitem__((i,j)).__setitem__((k,l),v).

The set applies to the value produced by the get. If the get returns a view, then the change affects x. But if it produces a copy, the change does not affect x.

With array m, y[0:4,m] produces a copy (do I need to demonstrate that?). y[0:4,:] produces a view.

So in short, if the first indexing produces a view the second indexed assignment works. But if produces a copy, the second has no effect.