Bedarf:
- Ich muss ein beliebig großes Array aus Daten vergrößern.
- Ich kann die Größe (ungefähr 100-200) erraten, ohne zu garantieren, dass das Array jedes Mal passt
- Sobald es auf seine endgültige Größe angewachsen ist, muss ich numerische Berechnungen durchführen, daher würde ich es vorziehen, irgendwann zu einem 2-D-Numpy-Array zu gelangen.
- Geschwindigkeit ist entscheidend. Beispielsweise wird für eine von 300 Dateien die update () -Methode 45 Millionen Mal aufgerufen (dauert ungefähr 150 Sekunden), und die finalize () -Methode wird 500.000 Mal aufgerufen (dauert insgesamt 106 Sekunden) ... insgesamt 250 Sekunden oder so.
Hier ist mein Code:
def __init__(self):
self.data = []
def update(self, row):
self.data.append(row)
def finalize(self):
dx = np.array(self.data)
Andere Dinge, die ich versucht habe, sind der folgende Code ... aber das ist waaaaay langsamer.
def class A:
def __init__(self):
self.data = np.array([])
def update(self, row):
np.append(self.data, row)
def finalize(self):
dx = np.reshape(self.data, size=(self.data.shape[0]/5, 5))
Hier ist ein Schema, wie dies genannt wird:
for i in range(500000):
ax = A()
for j in range(200):
ax.update([1,2,3,4,5])
ax.finalize()
# some processing on ax
python
performance
numpy
Fodon
quelle
quelle
Antworten:
Ich habe ein paar verschiedene Dinge ausprobiert, mit Timing.
import numpy as np
Die Methode, die Sie als langsam erwähnen: (32.094 Sekunden)
class A: def __init__(self): self.data = np.array([]) def update(self, row): self.data = np.append(self.data, row) def finalize(self): return np.reshape(self.data, newshape=(self.data.shape[0]/5, 5))
Regelmäßige alte Python-Liste: (0,308 Sekunden)
class B: def __init__(self): self.data = [] def update(self, row): for r in row: self.data.append(r) def finalize(self): return np.reshape(self.data, newshape=(len(self.data)/5, 5))
Versuch, eine Arrayliste in Numpy zu implementieren: (0,362 Sekunden)
class C: def __init__(self): self.data = np.zeros((100,)) self.capacity = 100 self.size = 0 def update(self, row): for r in row: self.add(r) def add(self, x): if self.size == self.capacity: self.capacity *= 4 newdata = np.zeros((self.capacity,)) newdata[:self.size] = self.data self.data = newdata self.data[self.size] = x self.size += 1 def finalize(self): data = self.data[:self.size] return np.reshape(data, newshape=(len(data)/5, 5))
Und so habe ich es geplant:
x = C() for i in xrange(100000): x.update([i])
Es sieht also so aus, als wären normale alte Python-Listen ziemlich gut;)
quelle
update
undfinalize
. Siehe mein überarbeitetes Timing, das ein 100: 1-Verhältnis vonupdate
zufinalize
np.append () kopiert jedes Mal alle Daten im Array, aber list vergrößert die Kapazität um einen Faktor (1.125). Liste ist schnell, aber die Speichernutzung ist größer als Array. Sie können das Array-Modul der Python-Standardbibliothek verwenden, wenn Sie sich für den Speicher interessieren.
Hier ist eine Diskussion zu diesem Thema:
So erstellen Sie ein dynamisches Array
quelle
Unter Verwendung der Klassendeklarationen in Owens Beitrag finden Sie hier ein überarbeitetes Timing mit einigen Auswirkungen des Finalisierens.
Kurz gesagt, ich finde Klasse C, um eine Implementierung bereitzustellen, die über 60x schneller ist als die Methode im ursprünglichen Beitrag. (Entschuldigung für die Textwand)
Die Datei, die ich verwendet habe:
#!/usr/bin/python import cProfile import numpy as np # ... class declarations here ... def test_class(f): x = f() for i in xrange(100000): x.update([i]) for i in xrange(1000): x.finalize() for x in 'ABC': cProfile.run('test_class(%s)' % x)
Nun die resultierenden Timings:
EIN:
903005 function calls in 16.049 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 16.049 16.049 <string>:1(<module>) 100000 0.139 0.000 1.888 0.000 fromnumeric.py:1043(ravel) 1000 0.001 0.000 0.003 0.000 fromnumeric.py:107(reshape) 100000 0.322 0.000 14.424 0.000 function_base.py:3466(append) 100000 0.102 0.000 1.623 0.000 numeric.py:216(asarray) 100000 0.121 0.000 0.298 0.000 numeric.py:286(asanyarray) 1000 0.002 0.000 0.004 0.000 test.py:12(finalize) 1 0.146 0.146 16.049 16.049 test.py:50(test_class) 1 0.000 0.000 0.000 0.000 test.py:6(__init__) 100000 1.475 0.000 15.899 0.000 test.py:9(update) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 100000 0.126 0.000 0.126 0.000 {method 'ravel' of 'numpy.ndarray' objects} 1000 0.002 0.000 0.002 0.000 {method 'reshape' of 'numpy.ndarray' objects} 200001 1.698 0.000 1.698 0.000 {numpy.core.multiarray.array} 100000 11.915 0.000 11.915 0.000 {numpy.core.multiarray.concatenate}
B:
208004 function calls in 16.885 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 16.885 16.885 <string>:1(<module>) 1000 0.025 0.000 16.508 0.017 fromnumeric.py:107(reshape) 1000 0.013 0.000 16.483 0.016 fromnumeric.py:32(_wrapit) 1000 0.007 0.000 16.445 0.016 numeric.py:216(asarray) 1 0.000 0.000 0.000 0.000 test.py:16(__init__) 100000 0.068 0.000 0.080 0.000 test.py:19(update) 1000 0.012 0.000 16.520 0.017 test.py:23(finalize) 1 0.284 0.284 16.883 16.883 test.py:50(test_class) 1000 0.005 0.000 0.005 0.000 {getattr} 1000 0.001 0.000 0.001 0.000 {len} 100000 0.012 0.000 0.012 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 1000 0.020 0.000 0.020 0.000 {method 'reshape' of 'numpy.ndarray' objects} 1000 16.438 0.016 16.438 0.016 {numpy.core.multiarray.array}
C:
204010 function calls in 0.244 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.244 0.244 <string>:1(<module>) 1000 0.001 0.000 0.003 0.000 fromnumeric.py:107(reshape) 1 0.000 0.000 0.000 0.000 test.py:27(__init__) 100000 0.082 0.000 0.170 0.000 test.py:32(update) 100000 0.087 0.000 0.088 0.000 test.py:36(add) 1000 0.002 0.000 0.005 0.000 test.py:46(finalize) 1 0.068 0.068 0.243 0.243 test.py:50(test_class) 1000 0.000 0.000 0.000 0.000 {len} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 1000 0.002 0.000 0.002 0.000 {method 'reshape' of 'numpy.ndarray' objects} 6 0.001 0.000 0.001 0.000 {numpy.core.multiarray.zeros}
Klasse A wird durch die Aktualisierungen zerstört, Klasse B wird durch die Finalisierungen zerstört. Klasse C ist gegenüber beiden robust.
quelle
cProfile
. Es ist der erste Import und die letzte Zeile, die in meinem Code-Snippet aufgerufen wird.Es gibt einen großen Leistungsunterschied in der Funktion, die Sie für die Finalisierung verwenden. Betrachten Sie den folgenden Code:
N=100000 nruns=5 a=[] for i in range(N): a.append(np.zeros(1000)) print "start" b=[] for i in range(nruns): s=time() c=np.vstack(a) b.append((time()-s)) print "Timing version vstack ",np.mean(b) b=[] for i in range(nruns): s=time() c1=np.reshape(a,(N,1000)) b.append((time()-s)) print "Timing version reshape ",np.mean(b) b=[] for i in range(nruns): s=time() c2=np.concatenate(a,axis=0).reshape(-1,1000) b.append((time()-s)) print "Timing version concatenate ",np.mean(b) print c.shape,c2.shape assert (c==c2).all() assert (c==c1).all()
Die Verwendung von Verkettung scheint doppelt so schnell wie die erste Version und mehr als zehnmal schneller als die zweite Version zu sein.
Timing version vstack 1.5774928093 Timing version reshape 9.67419199944 Timing version concatenate 0.669512557983
quelle
Wenn Sie die Leistung mit Listenoperationen verbessern möchten, schauen Sie sich die Blist-Bibliothek an. Es ist eine optimierte Implementierung von Python-Listen und anderen Strukturen.
Ich habe es noch nicht bewertet, aber die Ergebnisse auf ihrer Seite scheinen vielversprechend.
quelle