Evitar np.where cuando se asigna a una matriz numpy

Me gustaría que funcionara lo siguiente (o similar) (sin usar np.where )

 >>> A = np.arange(0,10) >>> ind = np.logical_and(A>4, A%2) >>> k = np.array([0,1,0],dtype=bool) >>> A[ind][k] = np.pi # Doesn't actually assign to A 

Es decir, quiero que k sea ​​una máscara booleana adicional en los valores de ind que son verdaderos.

Sé que puedo usar np.where(ind)[0][k] , pero esto es más caro que la indexación lógica.

¿Hay alguna forma de hacer referencia a A[ind] que se refiera a la memoria base de A ?

Desde la página de indexación numpy con frecuencia referenciada:

…. Una única matriz de índice booleano es prácticamente idéntica a x [obj.nonzero ()] …. Sin embargo, es más rápida cuando obj.shape == x.shape.

np.where(cond) es np.nonzero(cond) .

Pero vamos a hacer un tiempo simple

 In [239]: x = np.arange(10000) In [240]: y = (x%2).astype(bool) In [241]: x[y].shape Out[241]: (5000,) In [242]: idx = np.nonzero(y) In [243]: x[idx].shape Out[243]: (5000,) In [244]: timeit x[y].shape 89.9 µs ± 726 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [245]: timeit x[idx].shape 13.3 µs ± 107 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [246]: timeit x[np.nonzero(y)].shape 34.2 µs ± 893 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

Por lo tanto, la indexación de matrices es más rápida que la indexación booleana, incluso cuando usamos un explícito where .


A[ind][k]= no funciona porque A[ind] es una copia, no una vista.

 In [251]: A = np.arange(100,110) In [252]: ind = np.logical_and(A>104, A%2) In [253]: ind Out[253]: array([False, False, False, False, False, True, False, True, False, True]) In [254]: k = np.array([0,1,0], dtype=bool) In [255]: A[ind] Out[255]: array([105, 107, 109]) In [256]: A[ind][k] Out[256]: array([107]) In [257]: A[ind][k] = 12 In [258]: A Out[258]: array([100, 101, 102, 103, 104, 105, 106, 107, 108, 109]) 

Pero usar la k para seleccionar índices de np.where(ind) funciona:

 In [262]: A[np.where(ind)[0][k]]=12 In [263]: A Out[263]: array([100, 101, 102, 103, 104, 105, 106, 12, 108, 109]) 

Tiempos para una recuperación en lugar de un conjunto:

 In [264]: timeit A[np.where(ind)[0][k]] 1.94 µs ± 75.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [265]: timeit A[ind][k] 1.34 µs ± 13.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

Entonces sí, el doble enmascaramiento es un poco más rápido en este caso, pero eso no importa si no funciona. No te preocupes por las pequeñas mejoras de tiempo.

Un método de indexación booleano.

 In [345]: ind1=ind.copy() In [346]: ind1[ind] = k In [348]: A[ind1]=3 In [349]: A Out[349]: array([100, 101, 102, 103, 104, 105, 106, 3, 108, 109]) 

En este pequeño ejemplo, time es básicamente el mismo que para A[np.where(ind)[0][k]]=12 .

Esto funciona para matrices pequeñas (indexar el indexador!). La optimización podría ser más difícil.

 import numpy as np A = np.arange(0,10) k = np.array([0,1,0]) ind = np.logical_and(A>4, A%2) A[ind.nonzero()[0][k.nonzero()]] = np.pi