2015-01-05 6 views
34

Ich schrieb das folgende Skript:numpy Division mit RuntimeWarning: ungültiger Wert in double_scalars angetroffen

import numpy 

d = numpy.array([[1089, 1093]]) 
e = numpy.array([[1000, 4443]]) 
answer = numpy.exp(-3 * d) 
answer1 = numpy.exp(-3 * e) 
res = answer.sum()/answer1.sum() 
print res 

Aber ich habe dieses Ergebnis und mit dem Fehler ist aufgetreten:

nan 
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars 
    res = answer.sum()/answer1.sum() 

Es scheint, dass das zu sein Eingabeelement war zu klein, dass Python sie zu Nullen machte, aber in der Tat hat die Division ihr Ergebnis.

Wie löst man diese Art von Problem?

Antwort

39

können Sie es nicht lösen. Einfach answer1.sum()==0, und Sie können keine Division durch Null durchführen.

Dies passiert, weil answer1 die exponentielle von 2 sehr großen, negativen Zahlen ist, so dass das Ergebnis auf Null gerundet wird.

nan wird in diesem Fall wegen der Division durch Null zurückgegeben.

Jetzt Ihr Problem lösen können Sie:

  • go für eine Bibliothek für hochpräzise Mathematik, wie mpmath. Aber das macht weniger Spaß.
  • als eine Alternative zu einer größeren Waffe, einige mathematische Manipulation, wie unten beschrieben.
  • gehen Sie für eine maßgeschneiderte scipy/numpy Funktion, die genau das tut, was Sie wollen! Check out @Warren Weckesser Antwort.

Hier erkläre ich, wie man einige mathematische Manipulation, die bei diesem Problem hilft, zu tun. Wir haben, dass für den Zähler:

exp(-x)+exp(-y) = exp(log(exp(-x)+exp(-y))) 
       = exp(log(exp(-x)*[1+exp(-y+x)])) 
       = exp(log(exp(-x) + log(1+exp(-y+x))) 
       = exp(-x + log(1+exp(-y+x))) 

wo oben x=3* 1089 und y=3* 1093. Nun wird das Argument dieser exponentiellen ist

-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06

Für den Nenner Sie ähnlich vorgehen könnten aber erhalten, dass log(1+exp(-z+k)) bereits 0 abgerundet ist, so dass das Argument der Exponentialfunktion im Nenner einfach zu -z=-3000 abgerundet . Sie haben dann, dass Ihr Ergebnis

exp(-x + log(1+exp(-y+x)))/exp(-z) = exp(-x+z+log(1+exp(-y+x)) 
            = exp(-266.99999385580668) 

ist, die zu dem Ergebnis schon sehr nahe ist, die Sie erhalten, wenn Sie nur die zwei führenden Bedingungen zu halten sind (dh die erste Zahl 1089 im Zähler und die ersten Nummer 1000 im Nenner):

exp(3*(1089-1000))=exp(-267) 

aus Gründen der es, mal sehen, wie nahe wir aus der Lösung von Wolfram alpha sind (link):

Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523 

Der Unterschied zwischen dieser Zahl und dem obigen Exponenten ist +1.7053025658242404e-13, also war die Annäherung, die wir am Nenner gemacht haben, in Ordnung.

Das Endergebnis ist

'exp(-266.99999385580668) = 1.1050349147204485e-116 

Von Wolfram Alpha ist (link)

1.105034914720621496.. × 10^-116 # Wolfram alpha. 

und wieder ist es sicher auch hier zu verwenden numpy.

+0

Aber in diesem Fall muss ich Werte der Division erhalten durch 2 sehr kleine Werte. – Heinz

+1

Was meinst du? – gg349

+0

@Heinz Ich denke du meintest den Fall, in dem eine kleine Zahl durch eine kleine Zahl geteilt wird. In diesem Fall ändern Sie Ihren Algorithmus, um beide Zahlen zu erhöhen, ist viel besser als das Finden von mechanischen Drehungen. Nehmen Sie zum Beispiel den Logarithmus der analytischen Gleichungen, die Ihr Code zu simulieren versucht. Es gibt viele Probleme mit der Stabilität der Berechnung, wenn kleine Zahlen beteiligt sind. Es ist angenehmer, möglichst keine davon zu haben. – Mai

7

können Sie verwenden np.logaddexp (die die Idee implementiert in @ gg349 Antwort):

In [33]: d = np.array([[1089, 1093]]) 

In [34]: e = np.array([[1000, 4443]]) 

In [35]: log_res = np.logaddexp(-3*d[0,0], -3*d[0,1]) - np.logaddexp(-3*e[0,0], -3*e[0,1]) 

In [36]: log_res 
Out[36]: -266.99999385580668 

In [37]: res = exp(log_res) 

In [38]: res 
Out[38]: 1.1050349147204485e-116 

Oder Sie verwenden scipy.misc.logsumexp:

In [52]: from scipy.misc import logsumexp 

In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e)) 

In [54]: res 
Out[54]: 1.1050349147204485e-116 
Verwandte Themen