Schnelle python numpy wo Funktionalität?

Ich benutze numpy's wo Funktion viele Male in mehrere for Loops, aber es wird viel zu langsam. Gibt es irgendwelche Möglichkeiten, diese Funktionalität schneller durchzuführen? Ich habe gelesen, dass Sie versuchen sollten, in-line für Loops zu tun, sowie lokale Variablen für Funktionen vor dem for Loops zu machen, aber nichts scheint die Geschwindigkeit um zu verbessern (<1%). Die len(UNIQ_IDS) ~ 800. emiss_data und obj_data sind numpy ndarrays mit shape = (2600,5200). Ich habe das import profile , um einen Griff zu bekommen, wo die Engpässe sind und where in for Loops ein großer ist.

 import numpy as np max = np.max where = np.where MAX_EMISS = [max(emiss_data[where(obj_data == i)]) for i in UNIQ_IDS)] 

    6 Solutions collect form web for “Schnelle python numpy wo Funktionalität?”

    Kann np.unique mit return_index :

     def using_sort(): #UNIQ_IDS,uind=np.unique(obj_data, return_inverse=True) uind= np.digitize(obj_data.ravel(), UNIQ_IDS) - 1 vals=uind.argsort() count=np.bincount(uind) start=0 end=0 out=np.empty(count.shape[0]) for ind,x in np.ndenumerate(count): end+=x out[ind]=np.max(np.take(emiss_data,vals[start:end])) start+=x return out 

    Mit @ unutbu's Antwort als Grundlinie für shape = (2600,5200) :

     np.allclose(using_loop(),using_sort()) True %timeit using_loop() 1 loops, best of 3: 12.3 s per loop #With np.unique inside the definition %timeit using_sort() 1 loops, best of 3: 9.06 s per loop #With np.unique outside the definition %timeit using_sort() 1 loops, best of 3: 2.75 s per loop #Using @Jamie's suggestion for uind %timeit using_sort() 1 loops, best of 3: 6.74 s per loop 

    Es stellt sich heraus, dass eine reine Python-Schleife viel viel schneller sein kann als NumPy-Indizierung (oder Anrufe an np.wo) in diesem Fall.

    Betrachten Sie die folgenden Alternativen:

     import numpy as np import collections import itertools as IT shape = (2600,5200) # shape = (26,52) emiss_data = np.random.random(shape) obj_data = np.random.random_integers(1, 800, size=shape) UNIQ_IDS = np.unique(obj_data) def using_where(): max = np.max where = np.where MAX_EMISS = [max(emiss_data[where(obj_data == i)]) for i in UNIQ_IDS] return MAX_EMISS def using_index(): max = np.max MAX_EMISS = [max(emiss_data[obj_data == i]) for i in UNIQ_IDS] return MAX_EMISS def using_max(): MAX_EMISS = [(emiss_data[obj_data == i]).max() for i in UNIQ_IDS] return MAX_EMISS def using_loop(): result = collections.defaultdict(list) for val, idx in IT.izip(emiss_data.ravel(), obj_data.ravel()): result[idx].append(val) return [max(result[idx]) for idx in UNIQ_IDS] def using_sort(): uind = np.digitize(obj_data.ravel(), UNIQ_IDS) - 1 vals = uind.argsort() count = np.bincount(uind) start = 0 end = 0 out = np.empty(count.shape[0]) for ind, x in np.ndenumerate(count): end += x out[ind] = np.max(np.take(emiss_data, vals[start:end])) start += x return out def using_split(): uind = np.digitize(obj_data.ravel(), UNIQ_IDS) - 1 vals = uind.argsort() count = np.bincount(uind) return [np.take(emiss_data, item).max() for item in np.split(vals, count.cumsum())[:-1]] for func in (using_index, using_max, using_loop, using_sort, using_split): assert using_where() == func() 

    Hier sind die Benchmarks, mit shape = (2600,5200) :

     In [57]: %timeit using_loop() 1 loops, best of 3: 9.15 s per loop In [90]: %timeit using_sort() 1 loops, best of 3: 9.33 s per loop In [91]: %timeit using_split() 1 loops, best of 3: 9.33 s per loop In [61]: %timeit using_index() 1 loops, best of 3: 63.2 s per loop In [62]: %timeit using_max() 1 loops, best of 3: 64.4 s per loop In [58]: %timeit using_where() 1 loops, best of 3: 112 s per loop 

    So ist die Verwendung von [ using_loop (reiner Python) mehr als 11x schneller als using_where .

    Ich bin nicht ganz sicher, warum reine Python ist schneller als NumPy hier. Meine Vermutung ist, dass die reine Python-Version Reißverschlüsse (ja, Wortspiel beabsichtigt) durch beide Arrays einmal. Es nutzt die Tatsache, dass trotz all der Phantasie Indizierung, wir wollen wirklich nur jeden Wert einmal zu besuchen . So ist es Seiten-Schritte das Problem mit genau zu bestimmen, welche Gruppe jeder Wert in emiss_data fällt. Aber das ist nur vage Spekulation. Ich wusste nicht, dass es schneller wäre, bis ich benchmarked

    Ich glaube, der schnellste Weg, dies zu erreichen, ist, die groupby() Operationen im pandas Paket zu verwenden. Im Vergleich zu @ Ophion's using_sort() -Funktion ist Pandas etwa 10 Faktor schneller:

     import numpy as np import pandas as pd shape = (2600,5200) emiss_data = np.random.random(shape) obj_data = np.random.random_integers(1, 800, size=shape) UNIQ_IDS = np.unique(obj_data) def using_sort(): #UNIQ_IDS,uind=np.unique(obj_data, return_inverse=True) uind= np.digitize(obj_data.ravel(), UNIQ_IDS) - 1 vals=uind.argsort() count=np.bincount(uind) start=0 end=0 out=np.empty(count.shape[0]) for ind,x in np.ndenumerate(count): end+=x out[ind]=np.max(np.take(emiss_data,vals[start:end])) start+=x return out def using_pandas(): return pd.Series(emiss_data.ravel()).groupby(obj_data.ravel()).max() print('same results:', np.allclose(using_pandas(), using_sort())) # same results: True %timeit using_sort() # 1 loops, best of 3: 3.39 s per loop %timeit using_pandas() # 1 loops, best of 3: 397 ms per loop 

    Kannst du es nicht tun

     emiss_data[obj_data == i] 

    ? Ich bin mir nicht sicher, warum du überhaupt where wirst.

    Das Zuweisen eines Tupels ist viel schneller als das Zuweisen einer Liste, je nach Tupel effizienter als Listen in Python? , Also vielleicht nur durch den Aufbau eines Tupels statt einer Liste, wird dies die Effizienz zu verbessern.

    Wenn obj_data aus relativ kleinen ganzen Zahlen besteht, kannst du numpy.maximum.at (seit v1.8.0) verwenden:

     def using_maximumat(): n = np.max(UNIQ_IDS) + 1 temp = np.full(n, -np.inf) np.maximum.at(temp, obj_data, emiss_data) return temp[UNIQ_IDS] 
    Python ist die beste Programmiersprache der Welt.