2015-01-05 19 views
34

遇到無效值我寫了下面的腳本:numpy的分工與RuntimeWarning:在double_scalars

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 

但我得到這個結果,並與發生錯誤:

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

這似乎是在輸入元素太小,python將它們變成零,但事實上該分區有其結果。

如何解決這類問題?

回答

39

你無法解決它。只需answer1.sum()==0,你不能執行零除。

發生這種情況是因爲answer1是2個非常大的負數的指數,所以結果舍入爲零。

nan在這種情況下歸因於零除。

我們解決您的問題,您可以:

  • 去一個庫進行高精度的數學,喜歡mpmath。但那不太有趣。
  • 作爲一個更大的武器的替代品,做一些數學操作,如下所述。
  • 去找一個量身定做的scipy/numpy功能,它完全符合你的要求!查看@Warren Weckesser的答案。

在這裏我解釋瞭如何做一些數學操作,幫助解決這個問題。我們有對分子:

以上 x=3* 1089y=3* 1093
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))) 

哪裏。現在,這個指數的說法是

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

對於分母,你可以同樣繼續進行,但獲得log(1+exp(-z+k))已經四捨五入爲0,使指數函數的分母的說法簡直是四捨五入到-z=-3000 。那麼你有你的結果是

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

這已經是非常接近的結果,如果你只保留了2個項(即在分子中的第一號1089和第一數字1000,你會得到在分母):

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

對於它的緣故,讓我們來看看我們是如何從接近Wolfram Alpha的溶液(link):

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

這個數字和上面指數的區別是+1.7053025658242404e-13,所以我們在分母上做的近似值很好。

最終的結果是

'exp(-266.99999385580668) = 1.1050349147204485e-116 

從Wolfram Alpha的是(link

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

,並再次,它是安全的太在這裏使用numpy的。

+0

但在這種情況下,我需要得到的劃分值由2個非常小的值。 – Heinz

+1

你是什麼意思? – gg349

+0

@海因茨我認爲你的意思是少數人被少數人劃分的情況。在這種情況下,改變你的算法來縮放這兩個數字比找到機械扭曲要好得多。例如,取對數的代碼試圖模擬的分析方程。 當涉及小數目時,計算的穩定性有許多問題。如果可能的話,避免使用其中的任何一個更好。 – Mai

7

您可以使用np.logaddexp(實現在@ 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 

或者你可以使用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