Y-Achsenabschnitt aus Funktionsterm filtern

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
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Ich möchte aus einer ganzrationalen Funktion den Y-Achsenabschnitt herausfiltern. Die Schwierigkeit besteht für mich darin, nicht zu viel zu filtern. Im Code-Beispiel wurden fälschlicherweise die -3 aus dem 1. Term und die +5 aus dem 2. Term gematcht. Es sollte in dem Fall aber eine Liste mit '13.8' als einzigen Inhalt zurückgegeben werden. Eventuell kann man dieses Problem auch viel einfacher/eleganter lösen, indem auf reguläre Ausdrücke verzichtet wird. Meine Python-Version ist 2.5.2.

Code: Alles auswählen

In [1]: import re

In [2]: equation = '-3.9x^2+5.2x-13.8'

In [3]: re.findall(r'(?<!\^)[+-]?\d+(?:\.\d+)?(?![*xX])', equation)
Out[3]: ['-3', '+5', '-13.8']
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also ich steige durch Deinen RegExp nicht so ganz durch, aber eigentlich muss der doch folgendes können:

Raussuchen aller Teile, die durch "+" oder "-" getrennt sind. Innerhalb dieser Terme darf alles stehen außer ein "x". Wenn dem so ist, so ist das ein Ergebnis, ansonsten muss er das verwerfen.

Ich weiß ja nicht, wo die Eingabe her kommt, aber es könnten ja auch ggf. Brüche auftauchen, also "/". Das sehe ich bei Dir z.B. auch noch nicht.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Ich persönlich würde ja einfach den String nach + und - splitten.
Jetzt mal grad ungetestet sowas:

Code: Alles auswählen

[x for x in re.split('-+', '-3.9x^2+5.2x-13.8') if 'x' not in x]
Könnte aber auch leere Strings enthalten, die du dann halt entfernen musst.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Wichtig ist, dass die Information über das Vorzeichen nicht verloren geht. Ich erkläre mal meinen regex:

Code: Alles auswählen

>>> pattern = r'''
... (?# don't start with a caret)
... (?<!\^)
... (?# either a plus or a minus sign (optional))
... [+-]?
... (?# the number, can be a float)
... \d+(?:\.\d+)?
... (?# don't end with an asterisk, x or X)
... (?![*xX])
... '''
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Sorry, das mit dem Vorzeichen hab ich gar nicht bedacht, das war dumm.
Aber man kann das ja mit re.findall('[\+-]', string) zusätzlich suchen und dann zusammenfügen.
Folgendes ist wieder nicht getestet, muss aber eigentlich funktionieren:

Code: Alles auswählen

[y+x for x,y in zip(re.split('-+', equation), re.findall('[-\+]', equation)) if 'x' not in x]
PS: Ja ich weiß, das ist nicht gerade sehr schön und vielleicht auch etwas lang, aber ich wollte mein ursprüngliches Beispiel um das Vorzeichen ergänzen ;)
Aber da dürfte wieder ein leerer String bzw jetzt ein String mit einem '-' vorkommen.
Da könnte man noch einfach ne Bedingung hinten dranhängen

Code: Alles auswählen

[y+x for x,y in zip(re.split('-+', equation), re.findall('[-\+]', equation)) if 'x' not in x and x != '']
Aber vielleicht wär's mit einer richtigen Schleife auch übersichtlicher :p
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Hier mal die Ausgaben von deinen Vorschlägen:

Code: Alles auswählen

In [29]: equation
Out[29]: '-3.9x^2-3.4+5.2x-13.8+5x^4-12.7'

In [30]: [y+x for x,y in zip(re.split('-+', equation), re.findall('[-\+]', equation)) if 'x' not in x and x != '']
Out[30]: ['+12.7']

In [31]: [y+x for x,y in zip(re.split('-+', equation), re.findall('[-\+]', equation)) if 'x' not in x]
Out[31]: ['-', '+12.7']
Wie du siehst, fehlen in beiden Fällen -3.4 und -13.8.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Kennt ihr sympy?

Mit der isympy-shell s sähe das so aus:

Code: Alles auswählen

cm-laptop:html cm$ isympy 
Python 2.5.2 console for SymPy 0.6.3

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z = symbols('xyz')
>>> k, m, n = symbols('kmn', integer=True)
>>> f, g, h = map(Function, 'fgh')

Documentation can be found at http://sympy.org/

In [1]: f = (-3.9 * x**2 + 5.2 * x - 13.8)

In [2]: f.args[0]
Out[2]: -13.8000000000000

In [10]: diff(f, x)
Out[10]: 5.20000000000000 - 7.80000000000000 * x

In [11]: integrate(f, x)
Out[11]: 
                     2                      3
-13.8000000000000 * x + 2.60000000000000 * x - 1.30000000000000 * x 
Das entspricht zwar nicht ganz der Frage, aber ist eine nette Alternative, oder? ;-)

SCNR,
Christian

edit: Die schöne Darstellung der shell geht hier etwas verloren - deshalb nacheditiert, damit es immerhin lesbar ist.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Sorry, jetzt hab ichs aber auch mal wirklich getestet ;)
Diese doofen splits, ich komm nie damit klar, weil immer irgendwas passiert was man eigentlich gar nicht will, wenn man doch nur splitten will.
Beim 1. regulärem Ausdruck hab ich inkonsequenterweise nur +- geschrieben, obwohl es der selbe sein müsste wie der zweite also auch [\+-]
Und dann klappts immer noch nicht richtig, weil durch den leeren String, der am Anfang eingefügt wird, die Vorzeichen quasi eins verrutschen, also muss der auch weg.

Code: Alles auswählen

[y+x for x,y in zip(re.split('[-\+]', equation)[1:], re.findall('[-\+]', equation)) if 'x' not in x]
Gibt das gewünschte Ergebnis. Allerdings muss dann auch am Anfang echt ein Vorzeichen stehen, also auch ein +, obwohl mal das normalerweise weglässt.
Das könnte man aber mit einem

Code: Alles auswählen

if str[0] != '-' and str[0] != '+': str = '+' + str
bewerkstelligen.

Edit:
Mal als (mehr oder weniger) übersichtliche Schleife, die sich dann auch an die 80 Zeichen hält:

Code: Alles auswählen

import re
achsenabschnitt = []
equation = '-3.9x^2-3.4+5.2x-13.8+5x^4-12.7'
if equation[0] != '-' and equation[0] != '+':
    equation = '+' + equation
for x, y in zip(re.split('[-\+]', equation)[1:], re.findall('[-\+]', equation)):
    if 'x' not in x:
        achsenabschnitt.append(y+x)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Danke für die Hilfe, so funktioniert es! Hab die Funktion nochmal ein wenig umgeschrieben:

Code: Alles auswählen

In [105]: from itertools import izip

In [106]: y_achsenabschnitte = []

In [107]: def foo(equation):
    if not equation.startswith(('-', '+')):
        equation = '+' + equation
    for x, y in izip(re.split('[-+]', equation)[1:], re.findall('[-+]', equation)):
        if 'x' not in x:
            y_achsenabschnitte.append(y+x)
   .....:             
   .....:             

In [113]: foo(equation)

In [114]: y_achsenabschnitte
Out[114]: ['+2', '-3.4', '-13.8', '-12.7']
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hi,

das mag zwar die Lösung für diese Aufgabe sein, aber den mathematischen Sinn kann ich nicht nachvollziehen, weil der Achsenabschnitt ein anderer ist, als die Summe der Zahlen in dieser Liste.

Wenn Dir das egal ist, ignoriere diesen Einwand einfach - sonst habe ich Dich vielleicht auf einen Fehler hingewiesen.

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

CM hat geschrieben: das mag zwar die Lösung für diese Aufgabe sein, aber den mathematischen Sinn kann ich nicht nachvollziehen, weil der Achsenabschnitt ein anderer ist, als die Summe der Zahlen in dieser Liste.
Und das weißt Du woher? Ich sehe in dem Code-Stück keine Gleichung, aus der das hervorginge!
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

CM hat geschrieben:das mag zwar die Lösung für diese Aufgabe sein, aber den mathematischen Sinn kann ich nicht nachvollziehen, weil der Achsenabschnitt ein anderer ist, als die Summe der Zahlen in dieser Liste.
Nicht?
Also so weit ich weiß schon.

f(x) = x² + 5
-> 5 = Y-Achsenabschnitt, das ganze ist um 5 nach oben verschoben
f(x) = -2 + x² - 4
-> Summe der beiden x-freien Terme -> -6 = Y-Achsenabschnitt

Ist ja letztlich egal, wie die Sachen verteilt stehen, man kann sie einfach zusammenfassen, wodurch sich wiederum nur eine einzige Zahl ergibt, welche den Y-Achsenabschnitt angibt.

Genau wie man f(x) = x + x + x - x + 5 -x
einfach zu f(x) = x + 5
Zusammenfassen kann: x + 5 == x + x + x - x - x + 5
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Ich lese die Gleichung so:
-3.9 * x**2 -3.4+5.2 * x -13.8 +5 * x**4 -12.7
gekürzt also:
5*x**4 - 3.9 * x**2 + 5.2 * x - 29.9
damit ist der Achsenabschnitt -29.9.
2-3.4-13.8-12.7 ergibt -27.9. Vielleicht stehe ich aber auch auf dem Schlauch und habe mich vertippt oder was übersehen? Oder wir reden über eine andere Gleichung?
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

@CM: Ich hab jetzt dein Problem verstanden. Der Threadersteller hat imo eine andere Gleichung zum Testen des neuen Codes benutzt. Ich sagte ja, am Anfang müsse ein + oder - stehen. Ich denke mal er hat einfach ein +2 vorne drangehangen um dies zu testen.

Mit deiner Rechnung hast du völlig recht.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Ja, beim Testen habe ich zwischendurch den Wert von ``equation`` geändert. Ich wollte einfach sichergehen, dass es funktioniert.
Antworten