2016-05-26 6 views
5

Heute habe ich eine Funktion profiliert und einen (zumindest mir) seltsamen Engpass gefunden: Erstellen eines maskierten Arrays mit mask=None oder mask=0 um eine Maske zu initialisieren mit allen Nullen, aber die gleiche Form wie die data ist sehr langsam:Warum erstellt man ein maskiertes numpy array so langsam mit mask = None oder 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 

auf der anderen Seite mask=False oder Erstellen der Maske von Hand mit viel schneller:

>>> %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 

Warum erhalte None oder 0 fast 2000 mal langsamer als False oder als mask Parameter? Vorausgesetzt, die function docs sagt nur, dass es:

Muss in ein Array von Boolean mit der gleichen Form wie Daten konvertiert werden kann. True gibt eine maskierte (d. H. Ungültige) Daten an.

Ich verwende Python 3.5, numpy 1.11.0 auf 10 Windows-

+0

Haben Sie schon in den numpy Code gegraben? –

Antwort

4

mask=False ist für einen speziellen verrohrten im 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 oder mask=None nehmen den langsamen Weg, so dass ein 0- dimensionale Maske Array und durch np.resize gehen, um es zu ändern.

+0

Und 'resize' macht' a = verketten ((a,) * n_copies) '. – hpaulj

1

Ich glaube @ user2357112 hat die Erklärung. Ich habe beide Fälle profiliert, hier sind die Ergebnisse:

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)) 

So scheint es, dass der Verkettungsschritt von Arrays der Flaschenhals ist.

Verwandte Themen