Подтвердить что ты не робот

Numpy с RuntimeWarning: недопустимое значение, обнаруженное в double_scalars

Я написал следующее script:

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 превратил их в нули, но деление имеет результат.

Как решить эту проблему?

4b9b3361

Ответ 1

Вы не можете решить это. Просто answer1.sum()==0, и вы не можете выполнить деление на ноль.

Это происходит потому, что answer1 - это экспонента из 2 очень больших отрицательных чисел, так что результат округляется до нуля.

nan возвращается в этом случае из-за деления на ноль.

Теперь, чтобы решить вашу проблему, вы можете:

  • перейти к библиотеке для высокоточной математики, как MPMAT. Но это менее весело.
  • в качестве альтернативы большему оружию, сделайте некоторые математические манипуляции, как описано ниже.
  • перейдите к scipy/numpy функции scipy/numpy которая делает именно то, что вы хотите! Проверьте ответ @Warren Weckesser.

Здесь я объясняю, как выполнять математические манипуляции, которые помогают решить эту проблему. У нас есть это для числителя:

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=3* 1089 и y=3* 1093. Теперь аргумент этой экспоненты

-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 (ссылка):

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

Разница между этим числом и +1.7053025658242404e-13 выше показателем составляет +1.7053025658242404e-13, поэтому приближение, которое мы сделали в знаменателе, было хорошим.

Конечный результат

'exp(-266.99999385580668) = 1.1050349147204485e-116

Из вольфрама альфа есть (ссылка)

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

и опять же, здесь можно безопасно использовать numpy.

Ответ 2

Вы можете использовать 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.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