name ' ' is not defined

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
eastlib
User
Beiträge: 2
Registriert: Samstag 23. Februar 2019, 21:53

Hallo Python-Forum,

ich programmiere erst seit kurzem in Python und habe eine Frage. Ich möchte ein Attribut mit einem Funktionswert belegen, dessen Funktion ich im Voraus schon deklariert habe. Nun wird, sobald ich das Programm laufen lasse, mir der Fehler angezeigt, dass die Funktion nicht definiert wurde, obwohl ich das schon gemacht habe.
def fitFunc(x):

fitness = len(x)
for i in range (len(x)):
fitness =+ math.sin(x) - x*2

return fitness


Nun wird mir an der markierten Stelle der Fehler name 'fitFunc' is not defined angezeigt.

def updateFitness(R, M, nPop, pBestPos, pBestValue, gBestPos, gBestValue):

for p in range(0, nPop):
:arrow: M[p] = fitFunc(R[p])

if M[p] < gBestValue:
gBestValue = M[p]
gBestPos = R[p]

if M[p] < pBestValue[p]:
pBestValue[p] = M[p]
pBestPos[p] = R[p]

return gBestValue

if M[p] < gBestValue:
gBestValue = M[p]
gBestPos = R[p]

if M[p] < pBestValue[p]:
pBestValue[p] = M[p]
pBestPos[p] = R[p]

return gBestValue


Wenn mir jemand helfen könnte, wäre ich sehr glücklich.
Liebe Grüße
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Die Namensgebung der Variablen ist ein Albtraum.

Bitte verwende Code-Tags (</> Knopf über dem vollständigen Editor) für deinen Code.

Bitte zeig deinen kompletten Stacktrace aus der Fehlermeldung. Und wenn der Interpreter das sagt, dann ist die Funktion an der Stelle nicht bekannt. Wird sie davor definiert? Im selben Namensraum?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@eastlib: ohne den ganzen Code zu sehen, kann man da nicht viel sagen.
Die for-Schleife in `fitFunc` ist unsinnig, da sowieso nur die letzte Zahl benutzt wird. Das sieht falsch aus, was Du da aber wirklich berechnen willst, wird nicht so ganz klar.

Die Funktion `updateFitness` sieht auch falsch aus, doppelt kopierter Code, falsche Einrückungen, gBestPos wird nicht verwendet.
Du scheinst mit Vektoren zu rechnen, dann nutze numpy und keine for-Schleifen.

Halte Dich an die Namenskonvention, Variablen und Funktionen werden klein_mit_unterstrich geschrieben. Keine Abkürzungen verwenden, was sollen die Präfixe n, g oder p bedeuten?
eastlib
User
Beiträge: 2
Registriert: Samstag 23. Februar 2019, 21:53

Code: Alles auswählen

from random import random
import numpy
import math
import numpy as np

class particle_value:

    
    def initPosition(nPop, nVar, xMin, xMax):

        R = [[xMin + random()*(xMax-xMin) for i in range(0, nVar)]for p in range (0, nPop)]

        return R

    def initVelocity(nPop, nVar, vMin, vMax):

        V = [[vMin + random()*(vMax-vMin) for i in range(0, nVar)]for p in range (0, nPop)]
    
        return V

    

    def updateVelocity(R, V, nPop, nVar, j, w, vMin, vMax, chi, pBestPos, gBestPos):
    
            for p in range(0, nPop):
                for i in range(0, nVar):

                    r1 = random()
                    r2 = random()

                    V[p][i] = chi* (w * V[p][i] + r1*c1*(pBestPos[p][i]-R[p][i]) + r2*c2*(gBestPos[i]  -R[p][i]))

                    if V[p][i] > vMax: V[p][i] = vMax
                    if V[p][i] < vMin: V[p][i] = vMin



    def updatePosition(R, V, nPop, nVar, xMin, xMax):

        for p in range(0, nPop):
            for i in range(0, nVar):

                    R[p][i] = R[p][i] + V[p][i]

                    if R[p][i] > xMax: R[p][i] = xMax
                    if R[p][i] < xMin: R[p][i] = xMin

    def updateFitness(R, M, nPop, pBestPos, pBestValue, gBestPos, gBestValue):

                for p in range(0, nPop):
                    M[p] = fitFunc([R[p]])

                    if M[p] < gBestValue:
                        gBestValue = M[p]
                        gBestPos   = R[p]

                    if M[p] < pBestValue[p]:
                        pBestValue[p] = M[p]
                        pBestPos[p]   = R[p]

                return gBestValue

    def fitFunc(x):

        fitness = len(x)
        for i in range (len(x)):
            fitness += xVals[i]**2 - (10*math.cos(2*math.pi*xVals[i]))
        
        return fitness




    if __name__ == "__main__":

            nPop = 40
            nVar = 5
            xMin = 2
            xMax = 6
            vMin = 2
            vMax = 6
        
            c1, c2        = 2.05, 2.05
            w, wMin, wMax = 0.0, 0.4, 0.9 
            phi = c1+c2
            chi = 2.0/abs(2.0-phi-math.sqrt(pow(phi, 2)-4*phi))
            nDurch = 20

            gBestValue = float("inf")
            pBestValue = [float("inf")] * nPop
            pBestPos   = [[0]*nDurch] * nPop
            gBestPos   = [0] * nPop


            history    = []
            

            R = initPosition(nPop, nVar, xMin, xMax)
            V = initVelocity(nPop, nVar, vMin, vMax)
            M = (fitFunc[R][p] for p in range (0, nPop))

            positions = []
            velocities = []

            positions = np.array([R])
            velocities = np.array([V])
            particle_values = positions + velocities
            print("Die Positionen der Partikel: ")
            print(particle_values)

            for j in range(0, nDurch):

                updatePosition(R, V, nPop, nVar, xMin, xMax)

                gBest_Value = updateFitness(R, M, nPop, pBestPos, pBestValue, gBestPos, gBestValue)
                history.append(gBest_Value)
        
                w = wMax - ((wMax-wMin)/nDurch)*j
                updateVelocity(R, V, nPop, nVar, j, w, vMin, vMax, chi, pBestPos, gBestPos)

            for h in history:
                print (h)
Tut mir leid, ich hätte allein für den Kontext den ganzen Code reinposten sollen...
Und zu den Namen der Funktionen, so konnte ich mir halt am besten merken was ich da eigentlich mache...wenn euch das auch irritiert tut mir das erneut leid. Ich benutze python wie gesagt noch nicht sehr lange und bin für jede Kritik und jeden Rat offen.

Noch kurz zu den Präfixen:
Hier handelt es sich um den Algorithmus der Partikeschwarmoptimierung (PSO), bei dem ein Schwarm von bestimmten Individuuen versucht, im Kollektiv eine Lösung für ein Problem (beispielsweise die Futtersuche) finden, indem sie sich in einem begrenzten Suchraum umher bewegen und dort gemeinsam die beste Position im Suchraum ermitteln. Im übergeordneten Sinne beschreibt das quasi die Suche nach einer Extremwertstelle einer Funktion. Der Schwarm wird initialisiert, indem jedes Partikel mit einer zufälligen individuellen Position und einer zufälligen Geschwindigkeit belegt wird. Darüber hinaus kennt jedes Partikel seine bisher beste Position im Suchraum, also die Position, von der er das Problem bisher am effizientesten lösen konnte - das ist die pBestPosition (p steht hierbei für personal). Es gibt aber wie gesagt eine Position im Suchraum, die global als die beste angesehen werden kann - das ist die gBestPosition (g steht für global). Das n wie in nPop oder nDurch soll für Nummer stehen oder Anzahl (nPop = Anzahl der Partikel, nDurch = Anzahl der Durchläufe).
Ich hoffe es ist ein wenig klarer jetzt, wie gesagt tut mir leid, dass es so undurchsichtig war bis hierhin.

Zum Problem nochmal:

Die Fitnessfunktion (fitFunc) habe ich in der Klasse definiert, deshalb verstehe ich nicht wieso mir der Fehler an besagter Stelle ausgegeben wird.
Übersehe ich etwas?
Die Fitnessfunktion ist übrigens jene Funktion, die durch den Algorithmus optimiert wird.

Und PS: bin auch für jede Anmerkung oder ähnliches bezüglich des gesamten Codes offen, also wenn euch irgendwas einfalle sollte, was umständlich geschrieben ist oder unnötig ist, könnt ihr mir das natürlich auch sagen.

Nochmals vielen Dank für eure Mühen. Gruß
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Das Hauptproblem ist meiner Meinung nach, dass du Klassen nicht für das verwendest, wozu sie gedacht sind, sondern eher als lose Klammer um Funktionen. Verzichte doch einfach auf die Klassendefinition und schieb die Funktionen eine Ebene höher. In Python muss nicht alles in Klassen stehen. Der Code, so wie du ihn gepostet hast, sollte eigentlich gar nichts tun, da selbst der "if __name__ == '__main__'":- Abschnitt in der "Klasse" verbuddelt ist und niemals ausgeführt wird.

Ansonsten schau dir für die Benennung bitte mal PEP8 an. In Python gibt es relativ strenge Vorstellungen davon, was wie benannt werden sollte, und dort werden sie erklärt. :) https://www.python.org/dev/peps/pep-0008/#id23
Benutzeravatar
__blackjack__
User
Beiträge: 13112
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@eastlib: Die Einrückung sollte vier Leerzeichen pro Ebene betragen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das heisst das Hauptprogramm das in dem ``if __name__ …``-Zweig steht, sollte in einer Funktion verschwinden, damit es keine globalen Variablen gibt.

Das würde dann auch gleich zwei Probleme aufdecken: `c1` und `c2` werden von einer Funktion benutzt, ohne dass die das als Argumente übergeben bekommt. Funktionen und Methoden sollten aber alles was sie ausser Konstanten benötigen als Argumente übergeben bekommen.

Und `fit_func()` versucht ein `xVals` zu verwenden was es gar nicht gibt.

`numpy` wird importiert, sogar unter zwei Namen, dann aber überhaupt nicht verwendet‽ Entweder sollte man das verwenden, dann machen parallel geführte Arrays für `R` und V` Sinn, oder man löst das ohne Numpy, *dann* sollte man aber mindestens mal `R` und `V` zu *einer* Liste aus Partikelobjekten zusammenführen die jeweils eine Position und eine Geschwindigkeit haben. Da wären wir übrigens wieder bei schlechten Namen: Das `V` wohl für „velocity“ stehen soll habe ich jetzt mal geraten. Wofür `R` steht – keine Ahnung. Wenn man da nicht so dusselige Einbuchstabennamen verwenden würde, müsste man nicht raten und würde viel besser verstehen was der Code eigentlich machen soll. Ähnliches für `nPop` was man auch `particle_count` nennen könnte, dann braucht man da nicht rätseln.

Insgesamt sieht es so aus als würdest Du nicht in Python sondern in einer anderen Programmiesprache schreiben wollen. Zum Beispiel dieses ``for i in range(0, n):`` ist kein Python sondern eher C oder Pascal, oder so. Zum einen ist das `n` ja immer die Länge einer der übergebenen Listen, also ist das als Argument an die jeweilige Funktion völlig überflüssig, denn Listen kennen in Python ihre eigene Länge. Das muss man also nicht übergeben, sondern kann es einfach mit `len()` abfragen. Und dann haben wir ``for i in range(0, len(sequence)):`` und in der Schleife wird dann `i` verwendet um auf die Sequenz und ”paralelle” Sequenzen zuzugreifen. Das ist in Python ein „anti pattern“ weil man *direkt* über die Elemente von Sequenzen iterieren kann. Wenn man über mehrere parallel iterieren möchte, gibt es die `zip()`-Funktion. Und wenn man *zusätzlich* eine laufende Zahl in der Schleife benötigt die `enumerate()`-Funktion.

Du würdest dann wahrscheinlich versucht sein die `enumerate()`-Funktion zu verwenden weil Du Listen elementweise verändert – aber das ist auch sehr unüblich in Python. Da erstellt man einfach eine *neue* Liste und gibt die dann zurück.

Um das mal an der `update_position()` zu demonstrieren:

Code: Alles auswählen

def update_position(R, V, nPop, nVar, xMin, xMax):
    for p in range(0, nPop):
        for i in range(0, nVar):
            R[p][i] = R[p][i] + V[p][i]

            if R[p][i] > xMax: R[p][i] = xMax
            if R[p][i] < xMin: R[p][i] = xMin
Erst einmal `nPop` eleminieren:

Code: Alles auswählen

def update_position(R, V, nVar, xMin, xMax):
    for rx, vx in zip(R, V):
        for i in range(0, nVar):
            rx[i] = max(min(rx[i] + vx[i], xMax), xMin)
Hier fallen wieder die Namen unangenehm auf, weil ich keine wirkliche Ahnung habe was `R` und `V` genau bedeuten. Also werden auch die Folgenamen doof.

Im nächsten Schritt jetzt `nVar` beseitigen und nicht die Eingabedaten verändern, sondern eine neue Datenstruktur zurück geben:

Code: Alles auswählen

def update_position(R, V, xMin, xMax):
    result = list()
    for rx, vx in zip(R, V):
        new_rx = list()
        for r, v in zip(rx, vx):
            new_rx.append(max(min(r + v, xMax), xMin))
        result.append(new_rx)
    return result
Als abschluss sieht man hier dann noch das sich „list comprehensions“ geradezu aufdrängen. Erst die innere Schleife:

Code: Alles auswählen

def update_position(R, V, xMin, xMax):
    result = list()
    for rx, vx in zip(R, V):
        result.append([max(min(r + v, xMax), xMin) for r, v in zip(rx, vx)])
    return result
Und dann die Äussere:

Code: Alles auswählen

def update_position(R, V, xMin, xMax):
    return [
        [max(min(r + v, xMax), xMin) for r, v in zip(rx, vx)]
        for rx, vx in zip(R, V)
    ]
*Das* sieht jetzt schon mehr nach Python aus. Allerdings sind die `zip()`\s ja nur notwendig weil die zusammengehörenden Werte in der verschiedenen Datenstrukturen stehen. Das macht nur Sinn wenn es Numpy-Arrays wären, denn dann würde die Funktion nur noch so aussehen:

Code: Alles auswählen

def update_position(R, V, xMin, xMax):
    return (R + V).clip(xMin, xMax)
Wenn man Numpy verwendet schreibt man nur noch ganz wenige Schleifen in Python. Wenn man per Schleife über Nunpy-Arrays iteriert, macht man in 99% der Fälle etwas falsch.
Sollte es bei Code ohne Numpy bleiben, dann würde man Partikelobjekte einführen die jeweils die X-Position und die Geschwindigkeit kennen, und der Code würde so aussehen:

Code: Alles auswählen

def update_position(particles, min_x, max_x):
    for row in particles:
        for particle in row:
            particle.x = max(min(particle.x + particle.velocity, max_x), min_x)
Abschliessend: Den gezeigten Code kannst Du so nicht laufen lassen haben, denn neben dem Einrückproblem bei ``if __name__ …`` versuchst Du auf `fitFunc` per Index zuzugreifen. Das geht bei Funktionsobjekten nicht. Was sollte das auch bedeuten? Und `fitFunc()` verwendet `xVals` was nirgends definiert ist, die Funktion würde so also auch nicht funktionieren, wenn man sie aufrufen würde.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

@__blackjack__: Es gibt zwar an mehreren Stellen falsche Einrückungen in dem Code von 8 oder 12 Spaces, das eigentliche "Einrückungsproblem" dürfte aber sein, dass abgesehen von den Importen der gesamte Code in einer Klasse steht. Wäre jetzt die Frage, ob das Absicht ist, oder nicht; ich vermute schon (Das wäre dann also eher Java als C oder Pascal ;) )
Benutzeravatar
__blackjack__
User
Beiträge: 13112
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nezzcarth: Für Java hätte aber jede IDE die ich kenne `particle_value` als Klassennamen angemeckert und das keine der ”Methoden” als ``static`` deklariert ist. Und dann wäre das ja auch in Java eine schlechte Lösung nicht mindestens `R` und `V` in einer Klasse zu kapseln, beziehungsweise wäre es auch in Java sehr komisch das in parallelen Datenstrukturen zu halten statt eine `Particle`-Klasse einzuführen. 🤔
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten