Seite 1 von 1

Y-Achsenabschnitt aus Funktionsterm filtern

Verfasst: Freitag 13. März 2009, 17:40
von derdon
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']

Verfasst: Freitag 13. März 2009, 18:04
von Hyperion
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.

Verfasst: Freitag 13. März 2009, 18:12
von Nocta
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.

Verfasst: Freitag 13. März 2009, 18:17
von derdon
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])
... '''

Verfasst: Freitag 13. März 2009, 18:52
von Nocta
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

Verfasst: Freitag 13. März 2009, 19:02
von derdon
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.

Verfasst: Freitag 13. März 2009, 19:13
von CM
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.

Verfasst: Freitag 13. März 2009, 19:19
von Nocta
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)

Verfasst: Freitag 13. März 2009, 21:40
von derdon
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']

Verfasst: Samstag 14. März 2009, 17:58
von CM
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

Verfasst: Samstag 14. März 2009, 18:02
von Hyperion
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!

Verfasst: Samstag 14. März 2009, 18:03
von Nocta
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

Verfasst: Samstag 14. März 2009, 18:18
von CM
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?

Verfasst: Samstag 14. März 2009, 19:33
von Nocta
@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.

Verfasst: Sonntag 15. März 2009, 17:47
von derdon
Ja, beim Testen habe ich zwischendurch den Wert von ``equation`` geändert. Ich wollte einfach sichergehen, dass es funktioniert.