Cómo hacer un “todo” acumulativo.

Preparar
Considera la matriz numpy a

 >>> np.random.seed([3,1415]) >>> a = np.random.choice([True, False], (4, 8)) >>> a array([[ True, False, True, False, True, True, False, True], [False, False, False, False, True, False, False, True], [False, True, True, True, True, True, True, True], [ True, True, True, False, True, False, False, False]], dtype=bool) 

Pregunta
Para cada columna, quiero determinar el equivalente acumulativo de todos.

El resultado debería verse así:

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

Toma la primera columna

 a[: 0] # Original First Column array([ True, False, False, True], dtype=bool) # So far so good # \ False from here on # | /---------------\ array([ True, False, False, False], dtype=bool) # Cumulative all 

Básicamente, todo acumulativo es True siempre que tengamos True y cambiemos a False partir de ese momento en el primer False


Lo que he intentado
Puedo obtener el resultado con

 a.cumprod(0).astype(bool) 

Pero no puedo evitar preguntarme si es necesario realizar cada multiplicación cuando sé que todo será False desde el primer False que veo.

Considera la matriz 1-D más grande

 b = np.array(list('111111111110010101010101010101010101010011001010101010101')).astype(int).astype(bool) 

Sostengo que estos dos producen la misma respuesta.

 bool(b.prod()) 

y

 b.all() 

Pero b.all() puede b.all() un cortocircuito, mientras que b.prod() no lo hace. Si los cronometro:

 %timeit bool(b.prod()) %timeit b.all() 100000 loops, best of 3: 2.05 µs per loop 1000000 loops, best of 3: 1.45 µs per loop 

b.all() es más rápido. Esto implica que debe haber una manera de llevar a cabo un acumulativo todo lo que es más rápido que mi a.cumprod(0).astype(bool)

Todos los ufuncs tienen 5 métodos : reduce , accumulate , reduceat , outer y at . En este caso, use accumulate ya que devuelve el resultado de las aplicaciones acumulativas de ufunc:

 In [41]: np.logical_and.accumulate(a, axis=0) Out[50]: array([[ True, False, True, False, True, True, False, True], [False, False, False, False, True, False, False, True], [False, False, False, False, True, False, False, True], [False, False, False, False, True, False, False, False]], dtype=bool) 

 In [60]: np.random.seed([3,1415]) In [61]: a = np.random.choice([True, False], (400, 80)) In [57]: %timeit np.logical_and.accumulate(a, axis=0) 10000 loops, best of 3: 85.6 µs per loop In [59]: %timeit a.cumprod(0).astype(bool) 10000 loops, best of 3: 138 µs per loop