Примечание: лучший ответ до сих пор - просто использовать numpy.logaddexp(logA,logB)
.
Почему именно вы сравниваете с log(0)
? Это равно -numpy.inf
, в этом случае вы получите log(1 + math.exp(-inf-logB) ) + logB
, который сводится к logB. Этот вызов всегда выдаст предупреждающее сообщение, которое будет очень медленным.
Я мог бы придумать эту строчку. Однако вам нужно действительно измерить, чтобы увидеть, если это на самом деле быстрее. Он использует только одну «сложную» функцию вычисления вместо двух, которые вы используете, и рекурсия не происходит, if
все еще там, но скрыто (и может быть оптимизировано) в fabs
/ maximum
.
def log_add(logA,logB):
return numpy.logaddexp(0,-numpy.fabs(logB-logA)) + numpy.maximum(logA,logB)
редактирование:
Я быстро сделал timeit () со следующими результатами:
- Ваша оригинальная версия заняла около 120 с
- Моя версия заняла около 30 с
- Я удалил сравнение с журналом (0) из вашей версии, и оно уменьшилось до 20 с
- Я отредактировал свой код, чтобы сохранить
logaddexp
, но также работал с вашим рекурсивом, если и он уменьшился до 18.
Обновленный код, вы также можете переключать рекурсивный вызов с помощью встроенной обновленной формулы, но это мало изменило мои временные тесты:
def log_add2(logA, logB):
if logA < logB:
return log_add2(logB, logA)
return numpy.logaddexp(0,logB-logA)+logA
Редактировать 2:
Как отметил в комментариях pv, вы могли бы просто сделать numpy.logaddexp(logA, logB)
, что сводится к вычислению log(exp(logA)+exp(logB))
, что, конечно, равно log(A+B)
. Я рассчитал его (на той же машине, что и выше), и он пошел еще дальше до 10 секунд. Итак, мы снизились до 1/12, неплохо;).