Speed-Up For-Loop

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

Hallo Leute,

ich hoffe ich bin hier im richtigen Thread.
Ich will meine Loops schneller machen:

Code: Alles auswählen

	
vertex_coords = np.array([])
vertex_vdw = np.array([])
for i in range (len(vertices)):
     vertex_coords = np.append(vertex_coords,vertices[i].coord) #vertices[i].coord sind x,y,z Koordinaten eines atoms
     vertex_vdw = np.append(vertex_vdw, vertices[i].vdw) # vdw-radius von dem atom

vertex_coords = vertex_coords.reshape(len(vertices),3).transpose() #dies mach ich, da ich anschließend Distanzen berechne mit numpy
Gibt es Möglichkeit die Schleife im "c-style" umzuschreiben?
So in der Art wie folgendes Code-Fragment (Funtioniert nicht).

Code: Alles auswählen

vertex_coords, vertex_vdw = [ (item.coord, item.vdw) for item in vertices ]
vertex_coords = vertex_coords.reshape(len(vertices),3).transpose() #dies mach ich, da ich anschließend Distanzen berechne mit numpy
Vielen Dank im voraus

MFG
Björn
Zuletzt geändert von björn am Montag 12. September 2011, 10:14, insgesamt 1-mal geändert.
BlackJack

@björn: Syntax für Kommentare ist in Python ``#`` und nicht ``%``. Letzteres ist der Modulo-Operator.

Ein Array mit `numpy.append()` auf zu bauen ist eine schlechte Idee weil dabei im Gegensatz zu `list.append()` jedes mal das gesamte bisherige Array kopiert wird.

Der Umweg über den Index `i` kostet zwar auch etwas mehr Rechenzeit als nötig, ist aber vor allem vom Stil her schlecht. Das ist „unpythonisch”, weil man auch direkt über die Elemente von `vertices` iterieren kann.

Ich würde entweder den Umweg über eine Liste gehen, die `numpy.array()` übergeben wird, oder `numpy.fromiter()` verwenden.
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

Danke erstmal für die Antwort!
Werde ich gleich mal testen!!
Das mit dem Kommentare Tag tut mir leid, schreibe gerade einiges in Latex, und da war das noch so im Kopf!

Gruß
Björn
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

Okay, hab nun folgendes gemacht:

Code: Alles auswählen

vertex_coords = [ (item.coord) for item in vertices ]
vertex_vdw = [ (item.vdw) for item in vertices ]

vertex_vdw = np.array(vertex_vdw)
vertex_coords = np.array(vertex_coords)
vertex_coords = vertex_coords.reshape(len(vertices),3).transpose()
Der Code oben funtioniert wunderbar, und ist auch schneller als der vorherige.

Nun würde ich jedoch gerne noch:

Code: Alles auswählen

vertex_coords = [ (item.coord) for item in vertices ]
vertex_vdw = [ (item.vdw) for item in vertices ]
in einer Schleife berechnen. Ist das möglich/ bzw. wie mach ich das??

Gruß
Björn
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also das sind doch wirklich einfachste Grundlagen...

Code: Alles auswählen

vertex_coords = []
for item in vertices:
    vertex_coords.append(item.coord)
Wozu glaubst Du eigentlich, dienen die "()" in Deinen List-Comprehensions?

Wenn das aber eh nur "Zwischenschritte" sein sollen, böte es sich mal an, mit einem Generatorausdruck zu experimentieren. Evtl. reicht das np.array() ja als Argument aus.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Generator reicht nicht aus, da kommt dann so etwas bei heraus:

Code: Alles auswählen

array(<generator object <genexpr> at 0xa69211c>, dtype=object)
Aber dafür gibt es ja `numpy.fromiter()`.

@björn: Aus den zwei LCs eine Schleife zu machen könnte übrigens unter Umständen langsamer werden. Wenn es Dir da wirklich auf Geschwindigkeit ankommen sollte, müsstest Du das mit realistischen Listengrössen mal ausmessen.
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

Ist ja schön und gut was du schreibst, nur versteh ich nicht so recht was das mit meiner Frage zu tun hat!!

Natürlich kann ich beide Variablen in eine Liste schreiben, nur wenn du meinen ersten Post gelesen hättes, hättest du gesehen, dass ich gerne den Output in zwei Variablen hätte.
Und nicht beide in einer Liste.
Ich will so was in der Art haben:

Code: Alles auswählen

vertex_coords, vertex_vdw = [ (item.coord, item.vdw) for item in vertices ] # Dieser Code funktioniert NICHT
Und da wollte ich wissen ob dies Möglich ist, und keine Einführung in Listen! :(
Kritik ist ja schön und gut aber sie sollte schon auf das Thema bezogen sein.

Gruß
Björn
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

@BlackJack
Danke für die Info!
Ja, es kommt mir auf Geschwindigkeit an. Werde das mal testen, und versuchen "numpy.fromiter" zu verwenden, hat leider bisslang nur noch nciht hingehauen!!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

björn hat geschrieben:Ist ja schön und gut was du schreibst, nur versteh ich nicht so recht was das mit meiner Frage zu tun hat!!
Meinst Du mich? Dann solltest Du auch meinen Namen erwähnen, oder durch ein Quoting klar machen, worauf Du Dich beziehst!
björn hat geschrieben: Natürlich kann ich beide Variablen in eine Liste schreiben, nur wenn du meinen ersten Post gelesen hättes, hättest du gesehen, dass ich gerne den Output in zwei Variablen hätte.
Und nicht beide in einer Liste.
Ich dachte eigentlich, dass Du ein wenig Transferarbeit leisten könntest... Du kannst meinen Code ja leicht um eine zweite Liste erweitern, in der Du Dir diese "vdw"-Dinger merkst :roll:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
björn
User
Beiträge: 7
Registriert: Montag 12. September 2011, 08:54

@Hyperion
Wenn du meinen ersten Post gelesen hättest, hättest du auch gesehen, das ich genau diese Schleife gepostet habe, halt nur mit "np.arrays".
Mir geht es darum die Geschwindigkeit der Schleife zu verbessern und sonst um nichts.
Es funktioniert ja in der ersten Version.

Tut mir leid wenn ich mich da irgendwie Missverständlich ausgedrückt habe.

Das mit List-Comprehensions habe ich andersweitig gelesen . Damit soll die Schleife deutlich schneller durchlaufen.
Dies wollte ich auf meine Schleife anwenden!!
Nur habe ich dies nicht hinbekommen. Dies ist also mein Problem, und NICHT in einer normalen Schleife zwei Variablen zu speichern!!!

PROBLEM:
- Geschwindigkeit der Schleife verbessern (z.B. mit List-Comprehension)


Gruß
Björn
BlackJack

@björn: *Eine* „list comprehension” (LC) erzeugt *eine* Liste. Wenn Du mehr willst, dann kannst Du keine LC dafür verwenden.

Wenn Du das deutlich schneller haben möchtest, stösst Du wohl an die Grenzen der Sprache beziehungsweise Implementierung.
Benutzeravatar
pillmuncher
User
Beiträge: 1532
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

björn hat geschrieben:[...] würde ich jedoch gerne noch:

Code: Alles auswählen

vertex_coords = [ (item.coord) for item in vertices ]
vertex_vdw = [ (item.vdw) for item in vertices ]
in einer Schleife berechnen. Ist das möglich/ bzw. wie mach ich das??
Es wäre nicht wirklich schneller. Ganz einfach deswegen, weil n * (a + b) dasselbe ist wie n * a + n * b. Um das einzusehen, musst du nur n == len(vertices) setzen und a == Zugriffszeit auf x.coord und b == Zugriffszeit auf x.vdw.

Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@pillmuncher: Bei *einer* Schleife muss die Arbeit für das iterieren über `vertices` nur *einmal* gemacht werden. Also von daher kann es schon schneller sein. Die Frage ist hier ab wo die Grenze ist, wo das den langsamen Zugriff auf `list.append()`, der in einer LC implizit klar ist, aufwiegt. Und da muss man halt messen.
Benutzeravatar
pillmuncher
User
Beiträge: 1532
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

BlackJack hat geschrieben:@pillmuncher: Bei *einer* Schleife muss die Arbeit für das iterieren über `vertices` nur *einmal* gemacht werden. Also von daher kann es schon schneller sein. Die Frage ist hier ab wo die Grenze ist, wo das den langsamen Zugriff auf `list.append()`, der in einer LC implizit klar ist, aufwiegt. Und da muss man halt messen.
Das Setup eines Loops über eine Liste benötigt nur konstante Zeit, die zudem minimal ist. Es sind gerade mal vier Operationen, die doppelt vorkommen: SETUP_LOOP, LOAD_FAST und GET_ITER am Anfang des Loops und POP_BLOCK am Ende. Der Vergleich ist ja letztlich nicht LC vs. append(), da die Frage ja in die Richtung ging: "wie wäre es, wenn man eine LC mit eingebautem zip(*) hätte".

Ich stimme dir natürlich zu, dass man es im Zweifel immer messen sollte. Einer meiner Lieblings-Philosophen, Willard V.O. Quine, sagte immer: Don't count on what you can't count.

Viele Grüße,
Mick.

[edit] Hiermit kann man's ausprobieren.
In specifications, Murphy's Law supersedes Ohm's.
lunar

@pillmuncher: Du vergisst die Kosten der Iteration selbst, also die Kosten der ".__next__()"-Methode des aktuellen Iterators. Der Unterschied zwischen einer und zwei Schleife ist mithin nicht ein konstanter Summand (4 vs. 8 ), sondern ein konstanter Faktor (n vs. 2n). Asymptotisch ist das zwar egal, aber eben nicht zwingend im konkreten Fall.
Antworten