Ответ 1
Мы можем использовать маскированные массивы для этого:
>>> from numpy import *
>>> m = array([[1,0], [2,3]])
>>> x = ma.log(m)
>>> print x.filled(0)
[[ 0. 0. ]
[ 0.69314718 1.09861229]]
from numpy import *
m = array([[1,0],
[2,3]])
Я хотел бы вычислить элемент-мудрый log2(m)
, но только в тех местах, где m
не равен 0. В этих местах я хотел бы иметь 0. Как результат.
Сейчас я борюсь:
RuntimeWarning: divide by zero encountered in log2
Попробуйте 1: используя where
res = where(m != 0, log2(m), 0)
который вычисляет мне правильный результат, но я все еще регистрирую a RuntimeWarning: divide by zero encountered in log2
. Похоже, что (и синтаксически это совершенно очевидно) numpy все еще вычисляет log2(m)
на полной матрице, и только после этого where
выбирает значения, которые нужно сохранить.
Я бы хотел избежать этого предупреждения.
Попробуйте 2: использование масок
from numpy import ma
res = ma.filled(log2(ma.masked_equal(m, 0)), 0)
Конечно, маскировка нулей предотвратит log2
, чтобы применить к ним, не так ли? К сожалению, нет: мы все равно получаем RuntimeWarning: divide by zero encountered in log2
.
Несмотря на то, что матрица маскируется, log2
по-прежнему применяется к каждому элементу.
Как я могу эффективно вычислить элементный массив массива numpy без получения предупреждений о делении на нуль?
seterr
, но это не похоже на чистое решение.Любые идеи?
Мы можем использовать маскированные массивы для этого:
>>> from numpy import *
>>> m = array([[1,0], [2,3]])
>>> x = ma.log(m)
>>> print x.filled(0)
[[ 0. 0. ]
[ 0.69314718 1.09861229]]
Просто отключите предупреждение для этого вычисления:
from numpy import errstate,isneginf,array
m = array([[1,0],[2,3]])
with errstate(divide='ignore'):
res = log2(m)
И затем вы можете постобработать -inf
, если хотите:
res[isneginf(res)]=0
ОБНОВЛЕНИЕ: я разместил здесь некоторые комментарии о другом варианте, который использует маскированные массивы, опубликованные в другом ответе. Вы должны отключить ошибку по двум причинам:
1) Использование замаскированных массивов намного менее эффективно, чем кратковременное отключение ошибки, и вы попросили об эффективности.
2) Отключение специального предупреждения "деление на ноль" НЕ отключает другую проблему с вычислением логарифма числа, которое является отрицательным входом. Отрицательный ввод фиксируется как предупреждение о недопустимом значении, и вам придется с ним справиться.
С другой стороны, использование замаскированных массивов фиксирует две ошибки как одинаковые и приведет к тому, что вы не заметите отрицательное число на входе. Другими словами, отрицательное число на входе обрабатывается как ноль и в результате даст ноль. Это не то, что вы спросили.
3) В качестве последнего пункта и как личного мнения, отключение предупреждения очень читабельно, очевидно, что делает код, и делает его более понятным. В этом отношении я нахожу это решение чище, а затем использую маскированные массивы.
Другой вариант - использовать параметр where
для numpy ufuncs:
m = np.array([[1., 0], [2, 3]])
res = np.log2(m, out=np.zeros_like(m), where=(m!=0))
Нет RuntimeWarning
, и нули вводятся там, где лог не вычисляется.
Решение с замаскированным массивом и решение, которое отключает предупреждение, в порядке. Для разнообразия, вот другой, который использует scipy.special.xlogy
. np.sign(m)
задается в качестве аргумента x
, поэтому xlogy
возвращает 0, где np.sign(m)
равно 0.
Результат делится на np.log(2)
для получения логарифма с основанием-2.
In [4]: from scipy.special import xlogy
In [5]: m = np.array([[1, 0], [2, 3]])
In [6]: xlogy(np.sign(m), m) / np.log(2)
Out[6]:
array([[ 0. , 0. ],
[ 1. , 1.5849625]])
Как насчет следующего
from numpy import *
m=array((-1.0,0.0,2.0))
p=m > 0.0
print 'positive=',p
print m[p]
res=zeros_like(m)
res[p]=log(m[p])
print res
Вы можете использовать что-то вроде -
m = np.clip(m, 1e-12, None)
, чтобы избежать ошибки журнала (0). Это установит нижнюю границу на 1e-12
.
Вопросы: февраль 2014 года, май 2012 года
Для массива, содержащего zeros
или negatives
, мы получаем соответствующие ошибки.
y = np.log(x)
# RuntimeWarning: divide by zero encountered in log
# RuntimeWarning: invalid value encountered in log
markroxor предлагает np.clip
, в моем примере это создает горизонтальный пол. gg349 и другие используют np.errstate
и np.seterr
, я думаю, что они неуклюжи и не решают проблему. Как примечание np.complex
не работает для нулей. user3315095 использует индексирование p=0<x
, а NumPy.log имеет эту встроенную функциональность, where
/out
. mdeff демонстрирует это, но заменяет -inf
на 0
, что для меня было недостаточным и не решает проблемы с негативами.
Я предлагаю 0<x
и np.nan
(или при необходимости np.NINF
/-np.inf
).
y = np.log(x, where=0<x, out=np.nan*x)
Джон Цвинк использует матрицу масок np.ma.log
, это работает, но вычислительно медленнее, попробуйте App: timeit.
import numpy as np
x = np.linspace(-10, 10, 300)
# y = np.log(x) # Old
y = np.log(x, where=0<x, out=np.nan*x) # New
import matplotlib.pyplot as plt
plt.plot(x, y)
plt.show()
Сравнение времени для mask
и where
import numpy as np
import time
def timeit(fun, xs):
t = time.time()
for i in range(len(xs)):
fun(xs[i])
print(time.time() - t)
xs = np.random.randint(-10,+10, (1000,10000))
timeit(lambda x: np.ma.log(x).filled(np.nan), xs)
timeit(lambda x: np.log(x, where=0<x, out=np.nan*x), xs)