Ich arbeite an einem Code für ein Modell basierend auf einigen Fourier-Transformationen. Momentan versuche ich, einen Teil davon zu optimieren, so dass es mit einer großen Datenmenge verwendbar wäre. Beim Versuch, dies zu tun, fand ich ein merkwürdiges Verhalten, hauptsächlich eine Loop-Version meines Codes, die schneller ist als der gleiche Code, der mit numpy geschrieben wurde. Testing-Code ist wie folgt:Python-Schleife schneller als numpy Array-Operationen
# -*- coding: utf-8 -*-
import numpy as np
import timeit
def fourier_coef_loop(ts, times, k_max):
coefs = np.zeros(k_max, dtype=float)
t = 2.0 * np.pi * (times - times[0])/times[-1]
x = np.dot(np.arange(1,k_max+1)[np.newaxis].T,t[np.newaxis])
for k in xrange(1, k_max + 1):
cos_k = np.cos(x[k-1])
coefs[k - 1] = (ts[-1] - ts[0]) + (ts[:-1] * (cos_k[:-1] - cos_k[1:])).sum()
return(coefs)
def fourier_coef_np(ts, times, k_max):
coefs = np.zeros(k_max, dtype=float)
t = 2.0 * np.pi * (times - times[0])/times[-1]
x = np.dot(np.arange(1,k_max+1)[np.newaxis].T,t[np.newaxis])
coefs = np.add(np.einsum('ij,j->i',np.diff(np.cos(x)), -ts[:-1]), (ts[-1] - ts[0]))
return(coefs)
if __name__ == '__main__':
iterations = 10
size = 20000
setup = "from __main__ import fourier_coef_loop, fourier_coef_np, size\n" \
"import numpy as np"
# arg = np.random.normal(size=size)
# print(np.all(fourier_coef_np(arg, np.arange(size,dtype=float), size/2) == fourier_coef_loop(arg, np.arange(size,dtype=float), size/2)))
time_loop = timeit.timeit("fourier_coef_loop(np.random.normal(size=size), np.arange(size,dtype=float), size/2)",
setup=setup, number=iterations)
print("With loop: {} s".format(time_loop))
time_np = timeit.timeit("fourier_coef_np(np.random.normal(size=size), np.arange(size,dtype=float), size/2)",
setup=setup, number=iterations)
print("With numpy: {} s".format(time_np))
Es gibt folgende Ergebnisse:
With loop: 60.8385488987 s
With numpy: 64.9192998409 s
Kann jemand bitte sagen Sie mir, warum ist die Schleife Version schneller als die rein numpy Version? Mir sind die Ideen ausgegangen. Ich würde auch alle Vorschläge schätzen, wie man diese bestimmte Funktion schneller machen kann.
Sie sind nicht Timing der Schleife vs der vektorisierten Version, Sie Schleifen ein riesiges Durcheinander, das das Erzeugen einer Menge Pseudozufallsnormalen enthält. Darüber hinaus sieht Ihr Code stark suboptimal aus. Zum Beispiel, einsum ('ij, j-> i, ...) 'klingt sehr ähnlich wie ein Matrix-Vektor-Produkt (->' np.dot' wieder) und was auch immer' x = np.dot (np. Ein Bereich (1, k_max + 1) [np.newaxis] .T, t [np.newaxis]) sollte, ich bin mir sicher, dass es einen saubereren Weg gibt, es zu tun. –
Die Zeiten sind nicht so unterschiedlich; Wenn ich versuche, diese Größe zu verwenden, erhalte ich einen Speicherfehler. Für Größe = 2000 sind Timings auch ähnlich. Für 200 hat die np-Version einen wesentlichen Vorteil. Ich rate daher, dass bei größeren Formaten Probleme mit der Speicherverwaltung in die "numpigen" Zeiten hineinkauen. – hpaulj
@hpaulj Ich denke nicht, dass diese Zeiten relevant sind, um diese Schleife mit einer vektorisierten Version zu vergleichen (meine eigene in einem Bit). –