2009-01-19 8 views
42

Ich kann die Fehlerfunktion implementieren, ich selbst, aber ich würde es lieber nicht. Gibt es ein Python-Paket ohne externe Abhängigkeiten, das eine Implementierung dieser Funktion enthält? Ich habe this gefunden, aber das scheint Teil eines viel größeren Pakets zu sein (und es ist nicht einmal klar, welches!).Gibt es eine leicht verfügbare Implementierung von erf() für Python?

Antwort

24

Ich würde empfehlen, Sie herunterladen numpy (effizienter Matrix in Python haben) und scipy (eine Matlab Toolbox Ersatz, die numpy verwendet). Die Funktion erf befindet sich in scipy.

>>>from scipy.special import erf 
>>>help(erf) 

Sie können auch die erf Funktion in pylab definiert verwenden, aber das ist mehr bestimmt sind, in die Ergebnisse der Dinge Plotten Sie mit numpy und scipy berechnen. Wenn Sie eine All-in-One-Installation dieser Software benötigen, können Sie direkt die Python Enthought distribution verwenden.

+0

SciPy die Mother numerischer Software für Python ist. Aber es kann etwas herausfordernd sein, es zu benutzen. Beginnen Sie mit Blick auf http://www.scipy.org/ –

+1

Ich muss sagen, dass ich es total versäumt habe, es zu installieren. Es gab einen Grund, dass ich nach einem Paket ohne externe Abhängigkeiten gefragt habe. Numpy ist nicht der einzige. UMFPack ist ein anderer. Es wird einfacher sein, mein eigenes erf() zu schreiben! – rog

+1

versuchen Python Enthought, wie ich schon sagte, sie haben alles gebündelt, was Sie brauchen. – Mapad

41

Ich empfehle SciPy für numerische Funktionen in Python, aber wenn Sie etwas ohne Abhängigkeiten wollen, ist hier eine Funktion mit einem Fehler Fehler ist weniger als 1,5 * 10 -7 für alle Eingänge.

def erf(x): 
    # save the sign of x 
    sign = 1 if x >= 0 else -1 
    x = abs(x) 

    # constants 
    a1 = 0.254829592 
    a2 = -0.284496736 
    a3 = 1.421413741 
    a4 = -1.453152027 
    a5 = 1.061405429 
    p = 0.3275911 

    # A&S formula 7.1.26 
    t = 1.0/(1.0 + p*x) 
    y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*math.exp(-x*x) 
    return sign*y # erf(-x) = -erf(x) 

Der Algorithmus stammt aus Handbook of Mathematical Functions, Formel 7.1.26.

+0

Dieser Code gibt einen Division-durch-Null-Fehler für erf (0.0). – rog

+0

Sie haben Recht. Ich habe meine Antwort bearbeitet, um das Zeichen von x zu finden, eine andere Möglichkeit, dieses Problem zu beheben. Jetzt ist es ok. –

+6

aus wikipedia: "Das 'Handbuch' ist die Arbeit der US-Bundesregierung [Angestellte], nicht durch das Urheberrecht geschützt". Ich stelle hier einen direkteren Link zum Buch: http://www.math.sfu.ca/~cbm/aands/freineindex.htm – mariotomo

6

meine eigene Frage zu beantworten, ich habe mit dem folgenden Code am Ende, von einer Java-Version angepasst ich an anderer Stelle im Internet gefunden:

# from: http://www.cs.princeton.edu/introcs/21function/ErrorFunction.java.html 
# Implements the Gauss error function. 
# erf(z) = 2/sqrt(pi) * integral(exp(-t*t), t = 0..z) 
# 
# fractional error in math formula less than 1.2 * 10^-7. 
# although subject to catastrophic cancellation when z in very close to 0 
# from Chebyshev fitting formula for erf(z) from Numerical Recipes, 6.2 
def erf(z): 
    t = 1.0/(1.0 + 0.5 * abs(z)) 
     # use Horner's method 
     ans = 1 - t * math.exp(-z*z - 1.26551223 + 
          t * (1.00002368 + 
          t * (0.37409196 + 
          t * (0.09678418 + 
          t * (-0.18628806 + 
          t * (0.27886807 + 
          t * (-1.13520398 + 
          t * (1.48851587 + 
          t * (-0.82215223 + 
          t * (0.17087277)))))))))) 
     if z >= 0.0: 
      return ans 
     else: 
      return -ans 
+0

Schön, aber ab 2.7 sollten wir tun 'aus Mathe importieren erf '(für Portabilität, Genauigkeit, Geschwindigkeit, etc.) – smci

7

Eine reine Python-Implementierung im mpmath Modul gefunden werden kann (http://code.google.com/p/mpmath/)

Vom doc string:

>>> from mpmath import * 
>>> mp.dps = 15 
>>> print erf(0) 
0.0 
>>> print erf(1) 
0.842700792949715 
>>> print erf(-1) 
-0.842700792949715 
>>> print erf(inf) 
1.0 
>>> print erf(-inf) 
-1.0 

Für große reale x, \mathrm{erf}(x) approache s 1 sehr schnell ::

>>> print erf(3) 
0.999977909503001 
>>> print erf(5) 
0.999999999998463 

Die Fehlerfunktion ist eine ungerade Funktion ::

>>> nprint(chop(taylor(erf, 0, 5))) 
[0.0, 1.12838, 0.0, -0.376126, 0.0, 0.112838] 

: func: erf implementiert beliebiger Genauigkeit Auswerte- und unterstützt komplexe Zahlen ::

>>> mp.dps = 50 
>>> print erf(0.5) 
0.52049987781304653768274665389196452873645157575796 
>>> mp.dps = 25 
>>> print erf(1+j) 
(1.316151281697947644880271 + 0.1904534692378346862841089j) 

Ähnliche Funktionen

Siehe auch: func: erfc, die für große x, und genauer ist: func: erfi, die die Stammfunktion von \exp(t^2) gibt.

Die Fresnel-Integrale: func: fresnels und: func: fresnelc sind auch auf die Fehlerfunktion bezogen.

+0

das ist wirklich interessant. Vermutlich ist diese Multi-Präzisions-Implementierung ein bisschen langsamer als die Verwendung von nativem Gleitkomma? – rog

7

Ich habe eine Funktion, die 10^5 erf Anrufe. Auf meiner Maschine ...

scipy.special.erf macht es Zeit um 6.1s

erf Handbook of Mathematical Functions nimmt 8.3s

erf Numerical Recipes 6.2 nimmt 9.5s

(drei geführte mittelt, Code genommen von oben Plakate).

+1

erf mit ctypes von libm.so aufgerufen (Standard-c-Math-Bibliothek, 64-Bit-Linux hier) geht auf 5,6 s herunter. – meteore

+0

Ich benötige auch 1000er Erf-Anrufe. Basierend auf deinen Zahlen gehe ich mit scipy.special.erf. Hast du etwas schneller gefunden? Ich habe darüber nachgedacht, einen Nachschlag zu verwenden. – jtlz2

+1

FWIW, wie benutzt du Scipys 'erf' Funktion? Mit folgendem Setup: 'from scipy.special import erf; import numpy als np; data = np.random.randn (10e5) ', bekomme ich sehr schnelle Laufzeiten von:' result = erf (data) '. Insbesondere bekomme ich in diesem Fall 32ms pro Schleife. Die einzige Möglichkeit, Laufzeiten> 1s zu erhalten, besteht darin, dass ich naiv alle Elemente in einem "numpy" Array überstreiche. – 8one6

4

Ein Hinweis für alle, die eine höhere Leistung Ziel: vectorize, wenn möglich.

import numpy as np 
from scipy.special import erf 

def vectorized(n): 
    x = np.random.randn(n) 
    return erf(x) 

def loopstyle(n): 
    x = np.random.randn(n) 
    return [erf(v) for v in x] 

%timeit vectorized(10e5) 
%timeit loopstyle(10e5) 

gibt Ergebnisse

# vectorized 
10 loops, best of 3: 108 ms per loop 

# loops 
1 loops, best of 3: 2.34 s per loop 
Verwandte Themen