it-roy-ru.com

NumPy: возврат с делением на ноль

Я пытаюсь выполнить поэлементное деление в python, но если встречается ноль, мне нужно, чтобы коэффициент был просто нулем.

Например:

array1 = np.array([0, 1, 2])
array2 = np.array([0, 1, 1])

array1 / array2 # should be np.array([0, 1, 2])

Я всегда мог просто использовать цикл for для своих данных, но для того, чтобы действительно использовать оптимизацию numpy, мне нужна функция деления, чтобы возвращать 0 при делении на ноль ошибок вместо того, чтобы игнорировать ошибку.

Если я что-то не упустил, кажется, что numpy.seterr () не может возвращать значения при ошибках. У кого-нибудь есть какие-либо другие предложения о том, как я мог бы извлечь максимальную выгоду из NumPy при настройке собственного деления на ноль обработки ошибок?

59
hlin117

В numpy v1.7 + вы можете воспользоваться опцией "где" для ufuncs . Вы можете делать вещи в одну строку, и вам не нужно иметь дело с менеджером контекста errstate.

>>> a = np.array([-1, 0, 1, 2, 3], dtype=float)
>>> b = np.array([ 0, 0, 0, 2, 2], dtype=float)

# If you don't pass `out` the indices where (b == 0) will be uninitialized!
>>> c = np.divide(a, b, out=np.zeros_like(a), where=b!=0)
>>> print(c)
[ 0.   0.   0.   1.   1.5]

В этом случае вычисление деления выполняется в любом месте, где «b» не равно нулю. Если b равно нулю, то оно остается неизменным по сравнению с тем значением, которое вы изначально указали в аргументе out.

98
DStauffman

Опираясь на ответ @Franck Dernoncourt, исправляя -1/0:

def div0( a, b ):
    """ ignore / 0, div0( [-1, 0, 1], 0 ) -> [0, 0, 0] """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
        c[ ~ np.isfinite( c )] = 0  # -inf inf NaN
    return c

div0( [-1, 0, 1], 0 )
array([0, 0, 0])
36
denis

Опираясь на другие ответы и улучшая:

  • обработка 0/0 путем добавления invalid='ignore' к numpy.errstate()
  • представляя numpy.nan_to_num() для преобразования np.nan в 0.

Код:

import numpy as np

a = np.array([0,0,1,1,2], dtype='float')
b = np.array([0,1,0,1,3], dtype='float')

with np.errstate(divide='ignore', invalid='ignore'):
    c = np.true_divide(a,b)
    c[c == np.inf] = 0
    c = np.nan_to_num(c)

print('c: {0}'.format(c))

Результат:

c: [ 0.          0.          0.          1.          0.66666667]
35
Franck Dernoncourt

Однострочник (выдает предупреждение)

np.nan_to_num(array1 / array2)
13
Ulf Aslak

Попробуйте сделать это в два этапа. Сначала деление, потом замена.

with numpy.errstate(divide='ignore'):
    result = numerator / denominator
    result[denominator == 0] = 0

Строка numpy.errstate является необязательной и не позволяет numpy сообщать вам об «ошибке» деления на ноль, поскольку вы уже собираетесь это сделать и обрабатывать этот случай.

11
Pi Marillion

Вы также можете заменить на основе inf, только если dtypes массива являются числами с плавающей запятой, согласно этому ответу :

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> c = a / b
>>> c
array([ inf,   2.,   1.])
>>> c[c == np.inf] = 0
>>> c
array([ 0.,  2.,  1.])
2
atomh33ls

Другое решение, заслуживающее упоминания:

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> b_inv = np.array([1/i if i!=0 else 0 for i in b])
>>> a*b_inv
array([0., 2., 1.])
0
T. Gwen

Один из ответов, который я нашел при поиске связанного вопроса, заключался в манипулировании выходными данными в зависимости от того, был ли знаменатель нулевым или нет.

Предположим, что arrayA и arrayB были инициализированы, но arrayB имеет несколько нулей. Мы могли бы сделать следующее, если мы хотим безопасно вычислить arrayC = arrayA / arrayB.

В этом случае, когда у меня есть деление на ноль в одной из ячеек, я устанавливаю ячейку равной myOwnValue, которая в этом случае будет равна нулю

myOwnValue = 0
arrayC = np.zeros(arrayA.shape())
indNonZeros = np.where(arrayB != 0)
indZeros = np.where(arrayB = 0)

# division in two steps: first with nonzero cells, and then zero cells
arrayC[indNonZeros] = arrayA[indNonZeros] / arrayB[indNonZeros]
arrayC[indZeros] = myOwnValue # Look at footnote

Сноска. В ретроспективе эта строка в любом случае не нужна, поскольку arrayC[i] устанавливается в ноль. Но если бы это был случай, когда myOwnValue != 0, эта операция что-то сделает.

0
hlin117