Как вернуть 0 с делением на ноль


102

Я пытаюсь выполнить поэлементное деление в 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, устанавливая собственный разделитель на нулевую обработку ошибок?


В моей версии Python (Python 2.7.11 | Continuum Analytics, Inc.) это именно тот результат, который вы получите. С предупреждением.
Рамон Мартинес,

Самый емкий правильный ответ - stackoverflow.com/a/37977222/2116338
mrplants

Ответы:


189

В 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.


4
Если aи / или bмогут быть целочисленными массивами, то это та же концепция, вам просто нужно явно указать правильный тип вывода:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)критично, как указано в прокомментированной строке.
Джонатан Остром

1
Если использую np.divide(a, b, out=np.zeros_like(a), where=b!=0), я получаю сообщение об ошибке Assigning to function call which doesn't return. Странно то, что я использую его дважды, а ошибка появляется только один раз.
Джелмер Малдер

46

Основываясь на ответе @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])

Спасибо, я даже не заметил ту ошибку с кодом @Frank Dernoncourt.
hlin117

Привет, я пытаюсь выполнить математику массива, и я хочу, чтобы 0/0 приводило к 0, но я также хочу игнорировать np.NaN в своих расчетах. Подойдет ли это для этого? Кроме того, я пытаюсь понять. Что делает c [~ np.isfinite (c)] = 0? Я никогда не использовал ~ в Python. Для чего это? Спасибо
user20408

@ user20408, ~переворачивает Trueи Falseв Numpy массивов: print ~ np.array([ True, False, False ]). c[ ~ np.isfinite( c )] = 0означает: найти позиции, где cявляется конечным, преобразовать их в НЕ конечные с помощью ~и установить не-конечные значения на 0. См. также stackoverflow.com/search?q=[numpy ]+ "
boolean+

43

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

  • 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]

2
Хорошая работа для проверки, 0/0а также 1/0ошибок.
hlin117

Я попробовал ваш метод с примерами массивов, приведенных в ответе Д. Штауффмана, и, похоже, он дает очень большие числа вместо np.inf, который остается в конечном результате
Гал Авинери

Я бы не одобрил такой подход. Если какой- либо aили bсодержит NaN, ваше решение внезапно дает 0результат. Это может легко скрыть ошибки в вашем коде и является совершенно неожиданным.
DerWeh

Согласно недавнему руководству numpy, nan_to_num () принимает значения для замены положительного inf и отрицательного inf. numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)это подпись.
Крейг Хикс,


13

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

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

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


5
Вероятно, вам следует выполнить разделение в контекстеnp.errstate(divide='ignore'):
Уоррен Векессер

@WarrenWeckesser Справочная точка. Я отредактировал ответ, чтобы включить контекст. divide='warn'также может быть полезно, если он / она хочет получать уведомления.
Пи Мариллион

2

Вы также можете заменить на основе 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.])

0

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

Предположим 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

Еще одно решение, о котором стоит упомянуть:

>>> 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.])
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.