web-dev-qa-db-fra.com

Existe-t-il une implémentation facilement disponible d'erf () pour Python?

Je peux implémenter la fonction d'erreur, erf, moi-même, mais je préfère ne pas le faire. Existe-t-il un paquet python sans dépendances externes qui contient une implémentation de cette fonction? J'ai trouvé this mais cela semble faire partie d'un paquet beaucoup plus grand (et ce n'est même pas clair lequel!).

49
rog

Depuis la v.2.7. le module mathématique standard contient la fonction erf . Cela devrait être le moyen le plus simple.

http://docs.python.org/2/library/math.html#math.erf

62
golobor

Je recommande SciPy pour les fonctions numériques en Python, mais si vous voulez quelque chose sans dépendances, voici une fonction avec une erreur d'erreur inférieure à 1,5 * 10-sept pour toutes les entrées.

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)

L'algorithme provient de Handbook of Mathematical Functions , formule 7.1.26.

47
John D. Cook

Je vous recommande de télécharger numpy (pour avoir une matrice efficace en python) et scipy (un substitut de la boîte à outils Matlab, qui utilise numpy). La fonction erf réside dans scipy.

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

Vous pouvez également utiliser la fonction erf définie dans pylab, mais elle est plus destinée à tracer les résultats des choses que vous calculez avec numpy et scipy. Si vous souhaitez une installation tout-en-un de ces logiciels, vous pouvez utiliser directement le distribution Python Enthought .

25
Mapad

Une implémentation pure python peut être trouvée dans le module mpmath ( http://code.google.com/p/mpmath/ )

De la chaîne doc:

>>> 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

Pour les vrais grands x, \mathrm{erf}(x) approche 1 très rapidement ::

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

La fonction d'erreur est une fonction étrange ::

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

: func: erf implémente une évaluation de précision arbitraire et supporte les nombres complexes ::

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

Fonctions connexes

Voir aussi: func: erfc, qui est plus précis pour les grands x, et: func: erfi qui donne l'antidérivative de \exp(t^2).

Les intégrales de Fresnel: func: fresnels et: func: fresnelc sont également liées à la fonction d'erreur.

8
Charles McCreary

J'ai une fonction qui fait 10 ^ 5 appels erf. Sur ma machine ...

scipy.special.erf fait le temps à 6.1s

erf Handbook of Mathematical Functions prend 8.3s

erf Numerical Recipes 6.2 prend 9.5s

(moyennes sur trois séries, code tiré des affiches ci-dessus).

6
meteore

Pour répondre à ma propre question, j'ai fini par utiliser le code suivant, adapté d'une version Java que j'ai trouvée ailleurs sur le web:

# 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
6
rog

Une remarque pour ceux qui visent des performances plus élevées: vectoriser, si possible.

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)

donne des résultats

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

# loops
1 loops, best of 3: 2.34 s per loop
4
8one6