numpy deling met RuntimeWarning: ongeldige waarde aangetroffen in double_scalars

Ik heb het volgende script geschreven:

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

Maar ik kreeg dit resultaat en de fout trad op:

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

Het lijkt erop dat het invoerelement te klein was dat Python ze in nullen veranderde, maar de deling heeft inderdaad zijn resultaat.

Hoe dit soort problemen op te lossen?


Antwoord 1, autoriteit 100%

Je kunt het niet oplossen. Gewoon answer1.sum()==0, en je kunt niet delen door nul.

Dit gebeurt omdat answer1de exponentiële waarde is van 2 zeer grote, negatieve getallen, zodat het resultaat naar nul wordt afgerond.

nanwordt in dit geval geretourneerd vanwege de deling door nul.

Om uw probleem nu op te lossen, kunt u:

  • ga naar een bibliotheek voor zeer nauwkeurige wiskunde, zoals mpmath. Maar dat is minder leuk.
  • Voer als alternatief voor een groter wapen wat wiskundige bewerkingen uit, zoals hieronder beschreven.
  • ga voor een op maat gemaakte scipy/numpy-functie die precies doet wat je wilt! Bekijk het antwoord van @Warren Weckesser.

Hier leg ik uit hoe je wat wiskundige manipulatie kunt doen die bij dit probleem helpt. We hebben dat voor de teller:

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

Waar bovendien x=3* 1089en y=3* 1093. Nu is het argument van deze exponentiële

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

Voor de noemer zou je op dezelfde manier kunnen doorgaan, maar verkrijg je dat log(1+exp(-z+k))is al afgerond op 0, zodat het argument van De exponentiële functie bij de noemer wordt eenvoudig afgerond op -z=-3000. U hebt dan dat uw resultaat

is

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

die al uitermate dicht bij het resultaat is dat u zou krijgen als u alleen de 2 leidende termen zou houden (dwz het eerste nummer 1089in de teller en het eerste nummer 1000bij de noemer):

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

Laten we eens kijken hoe dicht we komen uit de oplossing van Wolfram Alpha (Link ):

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

Het verschil tussen dit nummer en de bovenstaande exponent is +1.7053025658242404e-13, dus de benadering die we bij de noemer maakten, was prima.

Het eindresultaat is

'exp(-266.99999385580668) = 1.1050349147204485e-116

Vanaf Wolfram Alpha is (Link )

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

En nogmaals, het is veilig om hier ook Numpy te gebruiken.


Antwoord 2, Autoriteit 23%

U kunt np.logaddexp(die het idee implementeert in het antwoord van @ GG349):

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

Of u kunt scipy.special.logsumexp:

In [52]: from scipy.special import logsumexp
In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e))
In [54]: res
Out[54]: 1.1050349147204485e-116

Other episodes