Performance meines Programms

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
cptnofuture
User
Beiträge: 14
Registriert: Donnerstag 17. Juli 2008, 15:51

Moin zusammen!

Ich hatte vor einiger Zeit ein etwas grösseres Programm geschrieben. Nun wollte ich es erweitern, hab es aber noch einmal neu geschrieben um ein Paket zu verwenden, das mir einige Sachen erleichtern soll (BioPython). So weit so gut, jetzt bin ich an eine Stelle gekommen, an der ich einen Teil des codes aus dem alten Programm wiederverwenden wollte und hab ihn copy und paste in mein neues Programm eingefügt (Berechnung einer Kovarianzmatrix...). Allerdings braucht mein neues Programm um einiges länger zur Berechnung, als es mein altes tat. Der code sieht wie folgt aus:

Code: Alles auswählen

        t = time.clock() 
        exP = []
        exA = []
        print len(atomList)
        print len(atomList[0])
        for i in range(len(atomList[0])):
           v = []                     
           for j in range(len(atomList)):                              
                   v.append(atomList[j][i])              
           exP.append(v)    
                               
        for j in range(len(aveList)):          
            exA.append(aveList[j])                

        a1 = []    
        for aNr in range(len(exP)):            
            a2 = []                                                        
            for aStr in exP[aNr]:                
                a2.append(aStr-exA[aNr])
            a1.append(a2) 
      
        for elem in a1:
            row = []
            for e in a1:
                sum = 0
                for i in range(len(elem)):                    
                    sum += elem[i]*e[i]
                row.append(sum/len(elem))
            self._matrixAsArray.append(row)
            
        self._matrix = matrix(self._matrixAsArray)    
        a1 = time.clock() - t          
        print "Laufzeit: %3.2f sec" %a1    
        print self._matrix
Also messe ich nur die Zeit, die wirklich diese Berechnung dauert. Bei meinem alten Programm dauerte der Spass ca. 1,6 sec und mit meinem neuen Programm der gleiche Code 15 sec, also untragbar länger. Die Daten für die Berechnung sind die gleichen.

In meinem alten Programm hatte ich alle Daten in Listen, jetzt verwende ich die Objekt-Strukturen von BioPython, übersetze allerdings die Informationen aus den Objekten wieder in die Listenstruktur, die ich im alten Programm auch hatte, damit ich meine alten Methoden verwenden kann. (Ja ich weiss, klingt nach unnötiger Mehrarbeit, allerdings bietet mir BioPython viele Sachen, die ich sonst selber schreiben müsste. Da ist mir dieser kleine Umweg noch lieber, zumal ich das nur an zwei Stellen machen muss und ich ansonsten mit den BioPython Methoden auskomme...)

Hat irgendjemand eine Idee, woran das liegen könnte???

Vielen Dank,
cpt
BlackJack

Die ganzen ``for``-Schleifen mit Indices über `range(len(obj))` sind ja gruselig.

Alle Schleifen müsste man auf folgendes zusammenstreichen können (ungetestet):

Code: Alles auswählen

from itertools import imap, izip
from operator import mul

# ...

        exP = ([x[i] for x in atomList] for i in xrange(len(atomList[0])))
        a1 = [[aStr - y for aStr in x] for x, y in izip(exP, aveList)]
        for elem in a1:
            row = [sum(imap(mul, elem, e)) / len(elem) for e in a1]
            self._matrixAsArray.append(row)
Costi
User
Beiträge: 545
Registriert: Donnerstag 17. August 2006, 14:21

Mit cProfile kannst du kugen, wie lange eine funktion braucht:

Code: Alles auswählen

import cProfile
cProfile.run('main()')
(vieleicht hilfts dir...)
cp != mv
cptnofuture
User
Beiträge: 14
Registriert: Donnerstag 17. Juli 2008, 15:51

Moin!

Vielen Dank für die Antowrten!

@BLackJack:

Ich bin leider (noch) nicht so sehr mit Python vertraut, wie ich es mir wünschen würde, und so habe ich halt programmiert, wie ich es gewohnt war...

Ich bekomme übrigens eine exception, wenn ich versuche den von Dir vorgeschlagenen code zu benutzen.

Code: Alles auswählen

    row = [sum(imap(mul, elem, e)) / len(self.pdbs) for e in a1]
TypeError: 'float' object is not callable

um ehrlich zu sein habe ich keine Ahnung, wie das zustande kommt. Kann es an sum() liegen, dass das nicht mit floats umgehen kann? Wollte im Internet schaun, aber habe auf anhieb nichts gefunden und es erstmal sein lassen. Habe stattdessen eine eigene sum() Methode geschrieben:

Code: Alles auswählen

    def sum(self, list):
        sum = 0.0
        for elem in list:
            sum += elem
        return sum
Ich weiss nicht, ob es jetzt daran liegt, der code ist nicht schneller geworden (auch wenn das vermutlich nicht Deine Absicht war...), sondern etwas langsamer. An meinem generellen Problem hat das nichts geändert. Bin jetzt soweit gegangen, dass ich die Methode, welche die Matrix ausrechnet in eine Toolkit Klasse verfrachtet habe und sie aus dem alten und aus dem neuen Programm über diese Klasse aufrufe, aber habe das selbe Ergebnis erhalten.

Ich habe weiterhin keine Ahnung, woran das liegt. In den anderen Bereichen ist mein neues Programm durch die BioPython Objekte schneller als das alte geworden. Nur hier an der entscheidenden Stelle will es einfach nicht. Hat vielleicht jemand schonmal ähnliche Erfahrungen gemacht? Ist jetzt kein dringendes Problem, wenn Euch irgendwann mal was auf- oder einfällt bin ich Euch für Hinweise dankbar.

Vielen Dank soweit,
cpt
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Du hast wahrscheinlich ein Float-Object sum oder mul genannt. Dann wird natürlich nicht mehr die Originalfunktion, sondern der namensgleiche Float verwendet, der nicht aufrufbar ist.
MfG
HWK
cptnofuture
User
Beiträge: 14
Registriert: Donnerstag 17. Juli 2008, 15:51

Moin!

Jo danke, das war es... tja. wer seinen eigenen code kennt ist klar im Vorteil... Hat das ganze allerdings nicht schneller gemacht, ist hauchdünn langsamer als meine erste Version mit dem range(). Hatte jetzt grade mal ein wenig dazu gelesen und überall stand, dass es ohne range() schneller sein müsste. Liegt das an meiner speziellen Struktur (s.o.)? Ist die Frage, ob ich mich dann umgewöhnen muss, wenn es ausser style und ein paar Zeilen weniger nichts bringt ( und um ehrlich zu sein finde ich es auch nicht leserlicher...)...

Gruss,
cpt
BlackJack

So wie's aussieht arbeitest Du eigentlich mit mehrdimensionalen Arrays, da würde ich als erstes mal schauen, ob man das mit `numpy` nicht beschleunigen kann.

Und dann hat der Algorithmus einfach mal eine quadratische Laufzeit, die von der Länge von `a1` abhängt.
Antworten