2016-05-26 14 views
5

Oggi ho definito una funzione e ho trovato (almeno a me) un collo di bottiglia strano: Creazione di un array mascherato con mask=None o mask=0 per inizializzare una maschera con tutti gli zeri, ma la stessa forma del data è molto lento:Perché la creazione di un array numpy mascherato è così lento con mask = None o mask = 0

>>> import numpy as np 
>>> data = np.ones((100, 100, 100)) 

>>> %timeit ma_array = np.ma.array(data, mask=None, copy=False) 
1 loop, best of 3: 803 ms per loop 

>>> %timeit ma_array = np.ma.array(data, mask=0, copy=False) 
1 loop, best of 3: 807 ms per loop 

d'altra parte utilizzando mask=False o la creazione della maschera a mano è molto più veloce:

>>> %timeit ma_array = np.ma.array(data, mask=False, copy=False) 
1000 loops, best of 3: 438 µs per loop 

>>> %timeit ma_array = np.ma.array(data, mask=np.zeros(data.shape, dtype=bool), copy=False) 
1000 loops, best of 3: 453 µs per loop 

Perché sta dando None o 0 quasi 2000 volte più lento di False o np.zeros(data.shape) come parametro mask? Dato che l'function docs dice solo che:

deve essere convertibile in un array di booleani con la stessa forma di dati. True indica un dato mascherato (cioè non valido).

Io uso python 3.5, NumPy 1.11.0 su Windows 10

+0

Hai già scavato nel codice di Numpy? –

risposta

4

mask=False è special-cased nel NumPy 1.11.0 source code:

if mask is True and mdtype == MaskType: 
    mask = np.ones(_data.shape, dtype=mdtype) 
elif mask is False and mdtype == MaskType: 
    mask = np.zeros(_data.shape, dtype=mdtype) 

mask=0 o mask=None prendere il lento cammino, facendo un 0- array di maschere dimensionali e passando attraverso np.resize per ridimensionarlo.

+0

E 'resize' fa' a = concatenate ((a,) * n_copies) '. – hpaulj

1

Credo che @ utente2357112 abbia la spiegazione. Ho fatto il profilo entrambi i casi, ecco i risultati:

In [14]: q.run('q.np.ma.array(q.data, mask=None, copy=False)') 
     49 function calls in 0.161 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     3 0.000 0.000 0.000 0.000 :0(array) 
     1 0.154 0.154 0.154 0.154 :0(concatenate) 
     1 0.000 0.000 0.161 0.161 :0(exec) 
     11 0.000 0.000 0.000 0.000 :0(getattr) 
     1 0.000 0.000 0.000 0.000 :0(hasattr) 
     7 0.000 0.000 0.000 0.000 :0(isinstance) 
     1 0.000 0.000 0.000 0.000 :0(len) 
     1 0.000 0.000 0.000 0.000 :0(ravel) 
     1 0.000 0.000 0.000 0.000 :0(reduce) 
     1 0.000 0.000 0.000 0.000 :0(reshape) 
     1 0.000 0.000 0.000 0.000 :0(setprofile) 
     5 0.000 0.000 0.000 0.000 :0(update) 
     1 0.000 0.000 0.161 0.161 <string>:1(<module>) 
     1 0.000 0.000 0.161 0.161 core.py:2704(__new__) 
     1 0.000 0.000 0.000 0.000 core.py:2838(_update_from) 
     1 0.000 0.000 0.000 0.000 core.py:2864(__array_finalize__) 
     5 0.000 0.000 0.000 0.000 core.py:3264(__setattr__) 
     1 0.000 0.000 0.161 0.161 core.py:6119(array) 
     1 0.007 0.007 0.161 0.161 fromnumeric.py:1097(resize) 
     1 0.000 0.000 0.000 0.000 fromnumeric.py:128(reshape) 
     1 0.000 0.000 0.000 0.000 fromnumeric.py:1383(ravel) 
     1 0.000 0.000 0.000 0.000 numeric.py:484(asanyarray) 
     0 0.000    0.000   profile:0(profiler) 
     1 0.000 0.000 0.161 0.161 profile:0(q.np.ma.array(q.data, mask=None, copy=False)) 

In [15]: q.run('q.np.ma.array(q.data, mask=False, copy=False)') 
     37 function calls in 0.000 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 :0(array) 
     1 0.000 0.000 0.000 0.000 :0(exec) 
     11 0.000 0.000 0.000 0.000 :0(getattr) 
     1 0.000 0.000 0.000 0.000 :0(hasattr) 
     5 0.000 0.000 0.000 0.000 :0(isinstance) 
     1 0.000 0.000 0.000 0.000 :0(setprofile) 
     5 0.000 0.000 0.000 0.000 :0(update) 
     1 0.000 0.000 0.000 0.000 :0(zeros) 
     1 0.000 0.000 0.000 0.000 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 core.py:2704(__new__) 
     1 0.000 0.000 0.000 0.000 core.py:2838(_update_from) 
     1 0.000 0.000 0.000 0.000 core.py:2864(__array_finalize__) 
     5 0.000 0.000 0.000 0.000 core.py:3264(__setattr__) 
     1 0.000 0.000 0.000 0.000 core.py:6119(array) 
     0 0.000    0.000   profile:0(profiler) 
     1 0.000 0.000 0.000 0.000 profile:0(q.np.ma.array(q.data, mask=False, copy=False)) 

Così sembra che il passo concatenazione di array è il collo di bottiglia.